diff --git a/src/main/java/com/thealgorithms/searches/TernarySearch.java b/src/main/java/com/thealgorithms/searches/TernarySearch.java index 4d9f55ea9917..1071d172ef21 100644 --- a/src/main/java/com/thealgorithms/searches/TernarySearch.java +++ b/src/main/java/com/thealgorithms/searches/TernarySearch.java @@ -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. * *

- * 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))
+ * Best-case performance: O(1)
+ * Average performance: Θ(log3(N))
+ * 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 > 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 > int ternarySearch(T[] arr, T key, int start, int end) { if (start > end) { @@ -45,16 +51,22 @@ private > 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); } } } diff --git a/src/test/java/com/thealgorithms/searches/TernarySearchTest.java b/src/test/java/com/thealgorithms/searches/TernarySearchTest.java index 367b595e55d9..fa62b3f8f847 100644 --- a/src/test/java/com/thealgorithms/searches/TernarySearchTest.java +++ b/src/test/java/com/thealgorithms/searches/TernarySearchTest.java @@ -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; @@ -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")); + } }