From 1645cf281fbe5ae7e43900760a27c112f1730f25 Mon Sep 17 00:00:00 2001 From: weiss-ben <90002567+weiss-ben@users.noreply.github.com> Date: Mon, 26 Sep 2022 19:28:55 +0300 Subject: [PATCH] feat: add new Median Search implementation (#1992) * feat: add new median search algorithm with linked list * Removed filename Co-authored-by: David Leal * Update search/median_search2.cpp Co-authored-by: David Leal * Update search/median_search2.cpp Co-authored-by: David Leal * Update search/median_search2.cpp Co-authored-by: David Leal * Update search/median_search2.cpp Co-authored-by: David Leal * fix: Requested changes made * Update search/median_search2.cpp Co-authored-by: David Leal * Update search/median_search2.cpp Co-authored-by: David Leal * Update search/median_search2.cpp Co-authored-by: David Leal * Added algorithm and implementation explanations. Also added wikipedia link. * Update search/median_search2.cpp Co-authored-by: David Leal * Added @brief and wikipedia link to algo * Update search/median_search2.cpp Co-authored-by: David Leal * moved includes to top of file * fix: clang-tidy fixes applied * fix: clang-tidy fixes * updating DIRECTORY.md * clang-format and clang-tidy fixes for b24ca86e * Update search/median_search2.cpp Co-authored-by: David Leal * clang-format and clang-tidy fixes for 247e0616 * fix: fixed test case failing * clang-format and clang-tidy fixes for 4c1400db * fix: test cases now pass * clang-format and clang-tidy fixes for f3027971 * Update search/median_search2.cpp Co-authored-by: David Leal * Update search/median_search2.cpp Co-authored-by: David Leal * clang-format and clang-tidy fixes for b8b5f5fd * clang-format and clang-tidy fixes for d67d450c Co-authored-by: David Leal --- DIRECTORY.md | 1 + search/linear_search.cpp | 51 ++++++-------- search/median_search2.cpp | 139 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 159 insertions(+), 32 deletions(-) create mode 100644 search/median_search2.cpp diff --git a/DIRECTORY.md b/DIRECTORY.md index 19ceab1e4..fe099e891 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -318,6 +318,7 @@ * [Jump Search](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/search/jump_search.cpp) * [Linear Search](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/search/linear_search.cpp) * [Median Search](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/search/median_search.cpp) + * [Median Search2](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/search/median_search2.cpp) * [Saddleback Search](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/search/saddleback_search.cpp) * [Sublist Search](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/search/sublist_search.cpp) * [Ternary Search](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/search/ternary_search.cpp) diff --git a/search/linear_search.cpp b/search/linear_search.cpp index b69cd4243..82cd4b4ce 100644 --- a/search/linear_search.cpp +++ b/search/linear_search.cpp @@ -7,8 +7,8 @@ * @author [Ritika Mukherjee](https://github.com/ritikaa17) */ -#include /// for IO operations -#include /// for assert +#include /// for assert +#include /// for IO operations /** * \brief [Algorithm implementation for linear search] @@ -18,17 +18,15 @@ * \returns index where the key-value occurs in the array * \returns -1 if key-value not found */ -int LinearSearch(int *array, int size, int key) -{ - for (int i = 0; i < size; ++i) - { - if (array[i] == key) - { +int LinearSearch(int *array, int size, int key) { + for (int i = 0; i < size; ++i) { + if (array[i] == key) { return i; } } - /* We reach here only in case element is not present in array, return an invalid entry in that case*/ + /* We reach here only in case element is not present in array, return an + * invalid entry in that case*/ return -1; } @@ -36,12 +34,10 @@ int LinearSearch(int *array, int size, int key) * @brief Self-test implementations * @returns void */ -static void tests() -{ +static void tests() { int size = 4; int *array = new int[size]; - for (int i = 0; i < size; i++) - { + for (int i = 0; i < size; i++) { array[i] = i; } @@ -50,8 +46,7 @@ static void tests() assert(LinearSearch(array, size, 2) == 2); size = 6; - for (int i = 0; i < size; i++) - { + for (int i = 0; i < size; i++) { array[i] = i; } @@ -60,15 +55,14 @@ static void tests() assert(LinearSearch(array, size, 5) == 5); std::cout << "All tests have successfully passed!\n"; - delete[] array; // free memory up + delete[] array; // free memory up } /** * @brief Main function * @returns 0 on exit */ -int main() -{ +int main() { int mode = 0; std::cout << "Choose mode\n"; @@ -76,13 +70,12 @@ int main() std::cin >> mode; - if (mode == 2) - { + if (mode == 2) { int size = 0; std::cout << "\nEnter the size of the array [in range 1-30 ]: "; std::cin >> size; - while (size <= 0 || size > 30){ + while (size <= 0 || size > 30) { std::cout << "Size can only be 1-30. Please choose another value: "; std::cin >> size; } @@ -92,8 +85,7 @@ int main() // Input for the array elements std::cout << "Enter the array of " << size << " numbers: "; - for (int i = 0; i < size; i++) - { + for (int i = 0; i < size; i++) { std::cin >> array[i]; } @@ -101,19 +93,14 @@ int main() std::cin >> key; int index = LinearSearch(array, size, key); - if (index != -1) - { + if (index != -1) { std::cout << "Number found at index: " << index << "\n"; - } - else - { + } else { std::cout << "Array element not found"; } delete[] array; - } - else - { - tests(); // run self-test implementations + } else { + tests(); // run self-test implementations } return 0; } diff --git a/search/median_search2.cpp b/search/median_search2.cpp new file mode 100644 index 000000000..2e9b04f9f --- /dev/null +++ b/search/median_search2.cpp @@ -0,0 +1,139 @@ +/** + * @file + * @brief Given a linked list L[0,....,n] of n numbers, find the middle node. + * + * @details The technique utilized in this implementation is the ["Floyd's + * tortoise and + * hare"](https://en.wikipedia.org/wiki/Cycle_detection#Floyd's_tortoise_and_hare) + * approach. This technique uses two pointers that iterate through the list at + * different 'speeds' in order to solve problems. In this implementation, for + * every iteration the slow pointer advances one node while the fast pointer + * advances two nodes. The result of this is that since the fast pointer moves + * twice as fast as the slow pointer, when the fast pointer reaches the end of + * the list the slow pointer will be pointing to the middle node of the list. + * + * Here are some example lists you can use to see how the algorithm works + * A = [1,2,3,4,5] + * B = [1,2,3,4,5,6] + * print median(A) #should be 39 + * print median(B) #should be 4 + * + * @author [Benjamin Weiss](https://github.com/weiss-ben) + * @see median_search.cpp + */ + +#include /// for assert +#include /// for IO operations + +/** + * Definition for singly-linked list. + */ +struct ListNode { + int val{0}; ///< the value stored in the node + ListNode* next{nullptr}; ///< pointer to the next node + ListNode() = default; ///< default constructor + explicit ListNode(int x) + : val(x) {} ///< constructor with value for node->val provided + ListNode(int x, ListNode* next) + : val(x), + next(next) { + } ///< constructor with values provided for node->val and node->next +}; + +/** + * @namespace search + * @brief Search algorithms + */ +namespace search { +/** + * @namespace median_search + * @brief Functions for the Median Search algorithm implementation. Wkipedia + * link to algorithm: https://en.wikipedia.org/wiki/Median_search + */ +namespace median_search2 { +/** + * This function searches for the median of a linked list. + * @param head The head of the linked list. + * @returns Median node of the linked list. + */ +ListNode* middleNode(ListNode* head) { + if (!head) { + return nullptr; + } + + // Fast and slow pointers + ListNode* fastptr = nullptr; + ListNode* slowptr = fastptr = head; + + // fast jumps 2 while slow jumps 1 + while (fastptr->next && fastptr->next->next) { + slowptr = slowptr->next; + fastptr = fastptr->next->next; + } + + return (fastptr->next) ? slowptr->next : slowptr; +} +} // namespace median_search2 +} // namespace search + +/** + * @brief Self-test implementations + * @returns void + */ +static void test() { + auto* head1 = new ListNode; + head1->val = 1; + + ListNode* temp = head1; + for (int i = 2; i < 6; ++i) { + // Allocate next + auto* temp1 = new ListNode; + temp1->val = i; + + // Advance + temp->next = temp1; + temp = temp1; + } + temp->next = nullptr; + + ListNode* median = search::median_search2::middleNode(head1); + assert(3 == median->val); // 3 is the value of the median node. + std::cout << "test case:1 passed\n"; + + // Test case # 2 + auto* head2 = new ListNode; + head2->val = 1; + + ListNode* temp2 = head2; + for (int i = 2; i < 7; ++i) { + // Allocate next + auto* temp3 = new ListNode; + temp3->val = i; + + // Advance + temp2->next = temp3; + temp2 = temp3; + } + temp2->next = nullptr; + + ListNode* median1 = search::median_search2::middleNode(head2); + assert(4 == median1->val); // 4 is the value of the median node. + std::cout << "test case:2 passed\n"; + + delete head1; + delete temp; + + delete head2; + delete temp2; + + std::cout << "--All tests passed--\n"; +} + +/** + * @brief Main function + * @returns 0 on exit + */ +int main() { + test(); // run self-test implementations + return 0; +}