2020-05-29 09:46:18 +08:00
|
|
|
/**
|
|
|
|
* \file
|
|
|
|
* \brief [Ternary search](https://en.wikipedia.org/wiki/Ternary_search)
|
|
|
|
* algorithm
|
|
|
|
*
|
2017-12-24 01:30:49 +08:00
|
|
|
* This is a divide and conquer algorithm.
|
|
|
|
* It does this by dividing the search space by 3 parts and
|
|
|
|
* using its property (usually monotonic property) to find
|
|
|
|
* the desired index.
|
2020-05-27 04:40:09 +08:00
|
|
|
*
|
2020-05-29 09:46:18 +08:00
|
|
|
* * Time Complexity : O(log3 n)
|
|
|
|
* * Space Complexity : O(1) (without the array)
|
2017-12-24 01:30:49 +08:00
|
|
|
*/
|
|
|
|
|
|
|
|
#include <iostream>
|
|
|
|
|
2020-05-29 09:46:18 +08:00
|
|
|
/**
|
2020-05-27 04:40:09 +08:00
|
|
|
* The absolutePrecision can be modified to fit preference but
|
2017-12-24 01:30:49 +08:00
|
|
|
* it is recommended to not go lower than 10 due to errors that
|
|
|
|
* may occur.
|
2020-05-29 09:46:18 +08:00
|
|
|
*/
|
|
|
|
#define absolutePrecision 10
|
|
|
|
/**
|
2017-12-24 01:30:49 +08:00
|
|
|
* The value of _target should be decided or can be decided later
|
|
|
|
* by using the variable of the function.
|
|
|
|
*/
|
|
|
|
#define _target 10
|
|
|
|
|
2020-05-29 09:46:18 +08:00
|
|
|
#define MAX 10000000 ///< Maximum length of array
|
2017-12-24 01:30:49 +08:00
|
|
|
|
2020-05-29 09:46:18 +08:00
|
|
|
/**
|
2017-12-24 01:30:49 +08:00
|
|
|
* get_input function is to receive input from standard IO
|
2020-05-29 09:46:18 +08:00
|
|
|
* @todo @christianbender Get input from STDIO or write input to memory as done
|
|
|
|
* above.
|
2017-12-24 01:30:49 +08:00
|
|
|
*/
|
2020-05-29 09:46:18 +08:00
|
|
|
void get_input() {}
|
2017-12-24 01:30:49 +08:00
|
|
|
|
2020-05-29 09:46:18 +08:00
|
|
|
/**
|
2020-05-27 04:40:09 +08:00
|
|
|
* This is the iterative method of the ternary search which returns the index of
|
|
|
|
* the element.
|
2020-05-29 09:46:18 +08:00
|
|
|
* \param[in] left lower interval limit
|
|
|
|
* \param[in] right upper interval limit
|
|
|
|
* \param[in] A array to search in
|
|
|
|
* \param[in] target value to search for
|
|
|
|
* \returns index where the target value was found
|
|
|
|
* \returns -1 if target value not found
|
2017-12-24 01:30:49 +08:00
|
|
|
*/
|
2020-05-27 04:40:09 +08:00
|
|
|
int it_ternary_search(int left, int right, int A[], int target) {
|
|
|
|
while (1) {
|
|
|
|
if (left < right) {
|
|
|
|
if (right - left < absolutePrecision) {
|
|
|
|
for (int i = left; i <= right; i++)
|
2020-05-29 09:46:18 +08:00
|
|
|
if (A[i] == target)
|
|
|
|
return i;
|
2020-05-27 04:40:09 +08:00
|
|
|
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
int oneThird = (left + right) / 3 + 1;
|
|
|
|
int twoThird = (left + right) * 2 / 3 + 1;
|
|
|
|
|
|
|
|
if (A[oneThird] == target)
|
|
|
|
return oneThird;
|
|
|
|
else if (A[twoThird] == target)
|
|
|
|
return twoThird;
|
|
|
|
|
|
|
|
else if (target > A[twoThird])
|
|
|
|
left = twoThird + 1;
|
|
|
|
else if (target < A[oneThird])
|
|
|
|
right = oneThird - 1;
|
|
|
|
|
|
|
|
else
|
|
|
|
left = oneThird + 1, right = twoThird - 1;
|
|
|
|
} else {
|
|
|
|
return -1;
|
|
|
|
}
|
2017-12-24 01:30:49 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-05-29 09:46:18 +08:00
|
|
|
/**
|
2020-05-27 04:40:09 +08:00
|
|
|
* This is the recursive method of the ternary search which returns the index of
|
|
|
|
* the element.
|
2020-05-29 09:46:18 +08:00
|
|
|
* \param[in] left lower interval limit
|
|
|
|
* \param[in] right upper interval limit
|
|
|
|
* \param[in] A array to search in
|
|
|
|
* \param[in] target value to search for
|
|
|
|
* \returns index where the target value was found
|
|
|
|
* \returns -1 if target value not found
|
2017-12-24 01:30:49 +08:00
|
|
|
*/
|
2020-05-27 04:40:09 +08:00
|
|
|
int rec_ternary_search(int left, int right, int A[], int target) {
|
|
|
|
if (left < right) {
|
|
|
|
if (right - left < absolutePrecision) {
|
|
|
|
for (int i = left; i <= right; i++)
|
2020-05-29 09:46:18 +08:00
|
|
|
if (A[i] == target)
|
|
|
|
return i;
|
2019-08-21 10:10:08 +08:00
|
|
|
|
2020-05-27 04:40:09 +08:00
|
|
|
return -1;
|
|
|
|
}
|
2019-08-21 10:10:08 +08:00
|
|
|
|
2020-05-27 04:40:09 +08:00
|
|
|
int oneThird = (left + right) / 3 + 1;
|
|
|
|
int twoThird = (left + right) * 2 / 3 + 1;
|
2019-08-21 10:10:08 +08:00
|
|
|
|
2020-05-29 09:46:18 +08:00
|
|
|
if (A[oneThird] == target)
|
|
|
|
return oneThird;
|
|
|
|
if (A[twoThird] == target)
|
|
|
|
return twoThird;
|
2019-08-21 10:10:08 +08:00
|
|
|
|
2020-05-27 04:40:09 +08:00
|
|
|
if (target < A[oneThird])
|
|
|
|
return rec_ternary_search(left, oneThird - 1, A, target);
|
|
|
|
if (target > A[twoThird])
|
|
|
|
return rec_ternary_search(twoThird + 1, right, A, target);
|
|
|
|
|
|
|
|
return rec_ternary_search(oneThird + 1, twoThird - 1, A, target);
|
|
|
|
} else {
|
|
|
|
return -1;
|
|
|
|
}
|
2017-12-24 01:30:49 +08:00
|
|
|
}
|
|
|
|
|
2020-05-29 09:46:18 +08:00
|
|
|
/**
|
2017-12-24 01:30:49 +08:00
|
|
|
* ternary_search is a template function
|
2020-05-27 04:40:09 +08:00
|
|
|
* You could either use it_ternary_search or rec_ternary_search according to
|
|
|
|
* preference.
|
2020-05-29 09:46:18 +08:00
|
|
|
* \param [in] N length of array
|
|
|
|
* \param[in] A array to search in
|
|
|
|
* \param[in] target value to search for
|
2017-12-24 01:30:49 +08:00
|
|
|
*/
|
2020-05-27 04:40:09 +08:00
|
|
|
void ternary_search(int N, int A[], int target) {
|
|
|
|
std::cout << it_ternary_search(0, N - 1, A, target) << '\t';
|
|
|
|
std::cout << rec_ternary_search(0, N - 1, A, target) << '\t';
|
|
|
|
std::cout << std::endl;
|
2017-12-24 01:30:49 +08:00
|
|
|
}
|
|
|
|
|
2020-05-29 09:46:18 +08:00
|
|
|
/** Main function */
|
2020-05-27 04:40:09 +08:00
|
|
|
int main() {
|
2020-05-29 09:46:18 +08:00
|
|
|
int N = 21;
|
|
|
|
int A[] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, 4, 10};
|
2020-05-27 04:40:09 +08:00
|
|
|
get_input();
|
|
|
|
ternary_search(N, A, _target);
|
|
|
|
return 0;
|
2017-12-24 01:30:49 +08:00
|
|
|
}
|