diff --git a/search/median_search.cpp b/search/median_search.cpp index 7379cad26..479de8107 100644 --- a/search/median_search.cpp +++ b/search/median_search.cpp @@ -1,78 +1,156 @@ /** - * \file - * \brief [Median search](https://en.wikipedia.org/wiki/Median_search) algorithm - * \warning This core is erroneous and gives invorrect answers. Tested using - * cases from [here](https://brilliant.org/wiki/median-finding-algorithm/) - * \ingroup median search - * \{ + * @file median_search.cpp + * @brief Implementation of [Median search](https://en.wikipedia.org/wiki/Median_of_medians) algorithm. + * @cases from [here](https://brilliant.org/wiki/median-finding-algorithm/) + * + * @details + * Given an array A[1,...,n] of n numbers and an index i, where 1 ≤ i ≤ n, find the i-th smallest element of A. + * median_of_medians(A, i): + * #divide A into sublists of len 5 + * sublists = [A[j:j+5] for j in range(0, len(A), 5)] + * medians = [sorted(sublist)[len(sublist)/2] for sublist in sublists] + * if len(medians) <= 5: + * pivot = sorted(medians)[len(medians)/2] + * else: + * #the pivot is the median of the medians + * pivot = median_of_medians(medians, len(medians)/2) + * #partitioning step + * low = [j for j in A if j < pivot] + * high = [j for j in A if j > pivot] + * k = len(low) + * if i < k: + * return median_of_medians(low,i) + * elif i > k: + * return median_of_medians(high,i-k-1) + * else: #pivot = k + * return pivot + * + * \note this algorithm implements median search for only arrays which have distinct elements + * + * Here are some example lists you can use to see how the algorithm works + * A = [1,2,3,4,5,1000,8,9,99] (Contain Unique Elements) + * B = [1,2,3,4,5,6] (Contains Unique Elements) + * print median_of_medians(A, 0) #should be 1 + * print median_of_medians(A,7) #should be 99 + * print median_of_medians(B,4) #should be 5 + * + * @author Unknown author + * @author [Sushil Kumar](https://github.com/Rp-sushil) */ -#include + #include +#include #include +#include /** - * @todo add documentation + * @namespace search + * @brief Search algorithms */ -template -void comp(X x, std::vector *s1, std::vector *s2, - std::vector *s3) { - if (s1->size() >= x && s1->size() + s2->size() < x) { - std::cout << (*s2)[0] << " is the " << x + 1 << "th element from front"; - } else if (s1->size() > x) { - std::sort(s1->begin(), s1->end()); - std::cout << (*s1)[x] << " is the " << x + 1 << "th element from front"; - } else if (s1->size() + s2->size() <= x && s3->size() > x) { - std::sort(s3->begin(), s3->end()); - std::cout << (*s3)[x - s1->size() - s2->size()] << " is the " << x + 1 - << "th element from front"; - } else { - std::cout << x + 1 << " is invalid location"; - } +namespace search { +/** + * @namespace median_search + * @brief Functions for [Median search](https://en.wikipedia.org/wiki/Median_search) algorithm + */ +namespace median_search { +/** +* This function search the element in an array for the given index. +* @param A array where numbers are saved +* @param idx current index in array +* @returns corresponding element which we want to search. +*/ +int median_of_medians(const std::vector& A, const int& idx) { + int pivot = 0; // initialized with zero + std::vector a(A.begin(), A.end()); + std::vector m; + int r = a.size(); + for(int i = 0; i < r; i += 5){ + std::sort(a.begin() + i, a.begin() + std::min(r, i + 5)); + int mid = (i + std::min(r, i + 5)) / 2; + m.push_back(a[mid]); + } + int sz = int(m.size()); + if(sz <= 5){ + std::sort(m.begin(), m.end()); + pivot = m[(sz- 1) / 2]; + } + else{ + pivot = median_of_medians(m, idx); + } + std::vector low; + std::vector high; + for(int i = 0; i < r; i++){ + if(a[i] < pivot){ + low.push_back(a[i]); + } + else if(a[i] > pivot){ + high.push_back(a[i]); + } + } + int k = int(low.size()); + if(idx < k){ + return median_of_medians(low, idx); + } + else if(idx > k){ + return median_of_medians(high, idx-k-1); + } + else{ + return pivot; + } } +} // namespace median_search +} // namespace search -#define MAX_NUM 20 ///< maximum number of values to sort from +/** + * Function to test above algorithm + */ +void test(){ + std::vector A{25,21,98,100,76,22,43,60,89,87}; + int i = 3; + assert(A[6] == search::median_search::median_of_medians(A, i)); // A[6] = 43, is the fourth smallest element. + std::cout << "test case:1 passed\n"; + + std::vector B{1,2,3,4,5,6}; + int j = 4; + assert(B[4] == search::median_search::median_of_medians(B, j)); // B[4] = 5, is the fifth smallest element. + std::cout << "test case:2 passed\n"; + + std::vector C{1,2,3,4,5,1000,8,9,99}; + int k = 3; + assert(C[3] == search::median_search::median_of_medians(C, k)); // C[3] = 4, is the fourth smallest element. + std::cout << "test case:3 passed\n"; + std::cout << "--All tests passed--\n"; +} /** * Main function */ -int main() { - std::vector v{25, 21, 98, 100, 76, 22, 43, 60, 89, 87}; - std::vector s1; - std::vector s2; - std::vector s3; - - // creates an array of random numbers - // for (int i = 0; i < MAX_NUM; i++) { - // int r = std::rand() % 1000; - // v.push_back(r); - // std::cout << r << " "; - // } - for (int r : v) std::cout << r << " "; - - int median = std::rand() % 1000; // initialize to a random numnber - - std::cout << "\nmedian=" << median << std::endl; - int avg1, avg2, avg3, sum1 = 0, sum2 = 0, sum3 = 0; - - for (int i = 0; i < v.size(); i++) { // iterate through all numbers - if (v.back() == v[median]) { - avg1 = sum1 + v.back(); - s2.push_back(v.back()); - } else if (v.back() < v[median]) { - avg2 = sum2 + v.back(); - s1.push_back(v.back()); - } else { - avg3 = sum3 + v.back(); - s3.push_back(v.back()); - } - v.pop_back(); - } - - int x; - std::cout << "enter the no. to be searched form begining:- "; - std::cin >> x; - comp(x - 1, &s1, &s2, &s3); - - return 0; +int main() +{ + test(); + int n = 0; + std::cout << "Enter Size of Array: "; + std::cin >> n; + std::vector a(n); + std::cout << "Enter Array: "; + for(int i = 0; i < n; i++){ + std::cin >> a[i]; + } + std::cout << "Median: "; // Median defination: https://en.wikipedia.org/wiki/Median + int x = search::median_search::median_of_medians(a, (n - 1) / 2); + if(n % 2 == 0){ + int y = search::median_search::median_of_medians(a, n / 2); + std::cout << (float(x) + float(y))/2.0; + } + else{ + std::cout << x; + } + std::cout << "\nTo find i-th smallest element "; + std::cout << "\nEnter i: "; + int idx = 0; + std::cin >> idx; + idx--; + std::cout << idx + 1<< "-th smallest element: " << search::median_search::median_of_medians(a, idx) << '\n'; + return 0; } -/// } +