Skip to content
Merged
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
56 changes: 34 additions & 22 deletions src/main/java/com/thealgorithms/searches/TernarySearch.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,38 +3,44 @@
import com.thealgorithms.devutils.searches.SearchAlgorithm;

/**
* A ternary search algorithm is a technique in computer science for finding the
* minimum or maximum of a unimodal function The algorithm determines either
* that the minimum or maximum cannot be in the first third of the domain or
* that it cannot be in the last third of the domain, then repeats on the
* remaining third.
* A ternary search algorithm is a divide-and-conquer algorithm that searches for
* a key in a sorted array by dividing the search domain into three parts.
*
* <p>
* Worst-case performance Θ(log3(N)) Best-case performance O(1) Average
* performance Θ(log3(N)) Worst-case space complexity O(1)
* Worst-case performance: Θ(log3(N))<br>
* Best-case performance: O(1)<br>
* Average performance: Θ(log3(N))<br>
* Worst-case space complexity: O(log3(N))
*
* @author Podshivalov Nikita (https://github.com/nikitap492)
* @see SearchAlgorithm
* @see IterativeBinarySearch
*/
public class TernarySearch implements SearchAlgorithm {
public final class TernarySearch implements SearchAlgorithm {

/**
* @param arr The **Sorted** array in which we will search the element.
* Searches for a value in a sorted array using ternary search.
*
* @param arr The sorted array in which we will search for the element.
* @param value The value that we want to search for.
* @return The index of the element if found. Else returns -1.
* @return The index of the element if found. Returns -1 if the array is null or empty, if value is null, or if not found.
*/
@Override
public <T extends Comparable<T>> int find(T[] arr, T value) {
if (arr == null || arr.length == 0 || value == null) {
return -1;
}
return ternarySearch(arr, value, 0, arr.length - 1);
}

/**
* @param arr The **Sorted** array in which we will search the element.
* Recursively searches for the specified key within the range [start, end].
*
* @param arr The sorted array in which we will search the element.
* @param key The value that we want to search for.
* @param start The starting index from which we will start Searching.
* @param end The ending index till which we will Search.
* @return Returns the index of the Element if found. Else returns -1.
* @param start The starting index from which we will start searching.
* @param end The ending index till which we will search.
* @return Returns the index of the element if found. Else returns -1.
*/
private <T extends Comparable<T>> int ternarySearch(T[] arr, T key, int start, int end) {
if (start > end) {
Expand All @@ -45,16 +51,22 @@ private <T extends Comparable<T>> int ternarySearch(T[] arr, T key, int start, i
/* Second boundary: add 2/3 of length to start */
int mid2 = start + 2 * (end - start) / 3;

if (key.compareTo(arr[mid1]) == 0) {
int cmp1 = key.compareTo(arr[mid1]);
if (cmp1 == 0) {
return mid1;
} else if (key.compareTo(arr[mid2]) == 0) {
}

int cmp2 = key.compareTo(arr[mid2]);
if (cmp2 == 0) {
return mid2;
} /* Search the first (1/3) rd part of the array.*/ else if (key.compareTo(arr[mid1]) < 0) {
return ternarySearch(arr, key, start, --mid1);
} /* Search 3rd (1/3)rd part of the array */ else if (key.compareTo(arr[mid2]) > 0) {
return ternarySearch(arr, key, ++mid2, end);
} /* Search middle (1/3)rd part of the array */ else {
return ternarySearch(arr, key, mid1, mid2);
}

if (cmp1 < 0) {
return ternarySearch(arr, key, start, mid1 - 1);
} else if (cmp2 > 0) {
return ternarySearch(arr, key, mid2 + 1, end);
} else {
return ternarySearch(arr, key, mid1 + 1, mid2 - 1);
}
}
}
62 changes: 62 additions & 0 deletions src/test/java/com/thealgorithms/searches/TernarySearchTest.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
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;

Expand Down Expand Up @@ -78,4 +79,65 @@ void testEdgeCaseEmptyArray() {

assertEquals(-1, index, "Should return -1 for an empty array");
}

@Test
void testNullArrayReturnsMinusOne() {
TernarySearch search = new TernarySearch();
assertEquals(-1, search.find(null, 5));
}

@Test
void testNullKeyReturnsMinusOne() {
Integer[] arr = {1, 2, 3, 4, 5};
TernarySearch search = new TernarySearch();
assertEquals(-1, search.find(arr, null));
}

@Test
void testSingleElementPresent() {
Integer[] arr = {42};
TernarySearch search = new TernarySearch();
assertEquals(0, search.find(arr, 42));
}

@Test
void testSingleElementAbsent() {
Integer[] arr = {42};
TernarySearch search = new TernarySearch();
assertEquals(-1, search.find(arr, 24));
}

@Test
void testTwoElements() {
Integer[] arr = {10, 20};
TernarySearch search = new TernarySearch();
assertEquals(0, search.find(arr, 10));
assertEquals(1, search.find(arr, 20));
assertEquals(-1, search.find(arr, 15));
}

@Test
void testMiddlePartitionSearch() {
Integer[] arr = {1, 3, 5, 7, 9, 11, 13, 15, 17, 19};
TernarySearch search = new TernarySearch();
assertEquals(3, search.find(arr, 7));
assertEquals(4, search.find(arr, 9));
assertEquals(5, search.find(arr, 11));
}

@Test
void testDuplicateElements() {
Integer[] arr = {1, 2, 2, 2, 3};
TernarySearch search = new TernarySearch();
int index = search.find(arr, 2);
assertTrue(index >= 1 && index <= 3, "Index should be one of the occurrences of 2");
}

@Test
void testGenericStrings() {
String[] words = {"apple", "banana", "cherry", "date", "elderberry"};
TernarySearch search = new TernarySearch();
assertEquals(2, search.find(words, "cherry"));
assertEquals(-1, search.find(words, "fig"));
}
}
Loading