Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package com.thealgorithms.searches;

import com.thealgorithms.devutils.searches.SearchAlgorithm;

/**
* Searches for a key in a sorted array that has been rotated at an unknown pivot.
*
* <p>
* Example:
* {@code [8, 9, 10, 1, 2, 3, 4, 5, 6, 7]}
*
* <p>
* This is a modified binary search. When the array contains no duplicates, the
* time complexity is {@code O(log n)}. With duplicates, the algorithm still
* works but may degrade to {@code O(n)} in the worst case.
*
* @see <a href="https://en.wikipedia.org/wiki/Search_in_rotated_sorted_array">Search in rotated sorted array</a>
* @see SearchAlgorithm
*/
public final class RotatedBinarySearch implements SearchAlgorithm {

@Override
public <T extends Comparable<T>> int find(T[] array, T key) {
int left = 0;
int right = array.length - 1;

while (left <= right) {
int middle = (left + right) >>> 1;
int cmp = key.compareTo(array[middle]);
if (cmp == 0) {
return middle;
}

// Handle duplicates: if we cannot determine which side is sorted.
if (array[left].compareTo(array[middle]) == 0 && array[middle].compareTo(array[right]) == 0) {
left++;
right--;
continue;
}

// Left half is sorted.
if (array[left].compareTo(array[middle]) <= 0) {
if (array[left].compareTo(key) <= 0 && key.compareTo(array[middle]) < 0) {
right = middle - 1;
} else {
left = middle + 1;
}
} else {
// Right half is sorted.
if (array[middle].compareTo(key) < 0 && key.compareTo(array[right]) <= 0) {
left = middle + 1;
} else {
right = middle - 1;
}
}
}

return -1;
}
}
84 changes: 84 additions & 0 deletions src/main/java/com/thealgorithms/sorts/TournamentSort.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
package com.thealgorithms.sorts;

import java.util.Arrays;

/**
* Tournament Sort algorithm implementation.
*
* Tournament sort builds a winner tree (a complete binary tree storing the index
* of the smallest element in each subtree). It then repeatedly extracts the
* winner (minimum) and updates the path from the removed leaf to the root.
*
* Time Complexity:
* - Best case: O(n log n)
* - Average case: O(n log n)
* - Worst case: O(n log n)
*
* Space Complexity: O(n) – additional winner-tree storage
*
* @see <a href="https://en.wikipedia.org/wiki/Tournament_sort">Tournament Sort Algorithm</a>
* @see SortAlgorithm
*/
public class TournamentSort implements SortAlgorithm {

@Override
public <T extends Comparable<T>> T[] sort(T[] array) {
if (array == null || array.length < 2) {
return array;
}

final int n = array.length;
final int leafCount = nextPowerOfTwo(n);

// Winner tree represented as an array:
// - Leaves live at [leafCount .. 2*leafCount)
// - Internal nodes live at [1 .. leafCount)
// Each node stores an index into the original array or -1 for "empty".
final int[] tree = new int[2 * leafCount];
Arrays.fill(tree, -1);

for (int i = 0; i < n; i++) {
tree[leafCount + i] = i;
}

for (int node = leafCount - 1; node >= 1; node--) {
tree[node] = winnerIndex(array, tree[node * 2], tree[node * 2 + 1]);
}

final T[] result = array.clone();
for (int out = 0; out < n; out++) {
final int winner = tree[1];
result[out] = array[winner];

int node = leafCount + winner;
tree[node] = -1;

for (node /= 2; node >= 1; node /= 2) {
tree[node] = winnerIndex(array, tree[node * 2], tree[node * 2 + 1]);
}
}

System.arraycopy(result, 0, array, 0, n);
return array;
}

private static int nextPowerOfTwo(int n) {
int power = 1;
while (power < n) {
power <<= 1;
}
return power;
}

private static <T extends Comparable<T>> int winnerIndex(T[] array, int leftIndex, int rightIndex) {
if (leftIndex == -1) {
return rightIndex;
}
if (rightIndex == -1) {
return leftIndex;
}

// If equal, prefer the left element to keep ordering deterministic.
return SortUtils.less(array[rightIndex], array[leftIndex]) ? rightIndex : leftIndex;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package com.thealgorithms.searches;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;

import org.junit.jupiter.api.Test;

class RotatedBinarySearchTest {

@Test
void shouldFindElementInRotatedArrayLeftSide() {
RotatedBinarySearch search = new RotatedBinarySearch();
Integer[] array = {8, 9, 10, 11, 12, 1, 2, 3, 4, 5, 6, 7};
assertEquals(2, search.find(array, 10));
}

@Test
void shouldFindElementInRotatedArrayRightSide() {
RotatedBinarySearch search = new RotatedBinarySearch();
Integer[] array = {8, 9, 10, 11, 12, 1, 2, 3, 4, 5, 6, 7};
assertEquals(6, search.find(array, 2));
}

@Test
void shouldFindElementInNotRotatedArray() {
RotatedBinarySearch search = new RotatedBinarySearch();
Integer[] array = {1, 2, 3, 4, 5, 6, 7};
assertEquals(4, search.find(array, 5));
}

@Test
void shouldReturnMinusOneWhenNotFound() {
RotatedBinarySearch search = new RotatedBinarySearch();
Integer[] array = {4, 5, 6, 7, 0, 1, 2};
assertEquals(-1, search.find(array, 3));
}

@Test
void shouldHandleWhenMiddleIsGreaterThanKeyInRightSortedHalf() {
RotatedBinarySearch search = new RotatedBinarySearch();
Integer[] array = {6, 7, 0, 1, 2, 3, 4, 5};
assertEquals(2, search.find(array, 0));
}

@Test
void shouldHandleDuplicates() {
RotatedBinarySearch search = new RotatedBinarySearch();
Integer[] array = {2, 2, 2, 3, 4, 2};
int index = search.find(array, 3);
assertTrue(index >= 0 && index < array.length);
assertEquals(3, array[index]);
}
}
19 changes: 19 additions & 0 deletions src/test/java/com/thealgorithms/sorts/TournamentSortTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package com.thealgorithms.sorts;

import static org.junit.jupiter.api.Assertions.assertNull;

import org.junit.jupiter.api.Test;

public class TournamentSortTest extends SortingAlgorithmTest {

@Test
void shouldAcceptWhenNullArrayIsPassed() {
Integer[] array = null;
assertNull(getSortAlgorithm().sort(array));
}

@Override
SortAlgorithm getSortAlgorithm() {
return new TournamentSort();
}
}