|
| 1 | +/** |
| 2 | + * @file |
| 3 | + * @brief Given a linked list L[0,....,n] of n numbers, find the middle node. |
| 4 | + * |
| 5 | + * @details The technique utilized in this implementation is the ["Floyd's |
| 6 | + * tortoise and |
| 7 | + * hare"](https://en.wikipedia.org/wiki/Cycle_detection#Floyd's_tortoise_and_hare) |
| 8 | + * approach. This technique uses two pointers that iterate through the list at |
| 9 | + * different 'speeds' in order to solve problems. In this implementation, for |
| 10 | + * every iteration the slow pointer advances one node while the fast pointer |
| 11 | + * advances two nodes. The result of this is that since the fast pointer moves |
| 12 | + * twice as fast as the slow pointer, when the fast pointer reaches the end of |
| 13 | + * the list the slow pointer will be pointing to the middle node of the list. |
| 14 | + * |
| 15 | + * Here are some example lists you can use to see how the algorithm works |
| 16 | + * A = [1,2,3,4,5] |
| 17 | + * B = [1,2,3,4,5,6] |
| 18 | + * print median(A) #should be 39 |
| 19 | + * print median(B) #should be 4 |
| 20 | + * |
| 21 | + * @author [Benjamin Weiss](https://github.com/weiss-ben) |
| 22 | + * @see median_search.cpp |
| 23 | + */ |
| 24 | + |
| 25 | +#include <cassert> /// for assert |
| 26 | +#include <iostream> /// for IO operations |
| 27 | + |
| 28 | +/** |
| 29 | + * Definition for singly-linked list. |
| 30 | + */ |
| 31 | +struct ListNode { |
| 32 | + int val{0}; ///< the value stored in the node |
| 33 | + ListNode* next{nullptr}; ///< pointer to the next node |
| 34 | + ListNode() = default; ///< default constructor |
| 35 | + explicit ListNode(int x) |
| 36 | + : val(x) {} ///< constructor with value for node->val provided |
| 37 | + ListNode(int x, ListNode* next) |
| 38 | + : val(x), |
| 39 | + next(next) { |
| 40 | + } ///< constructor with values provided for node->val and node->next |
| 41 | +}; |
| 42 | + |
| 43 | +/** |
| 44 | + * @namespace search |
| 45 | + * @brief Search algorithms |
| 46 | + */ |
| 47 | +namespace search { |
| 48 | +/** |
| 49 | + * @namespace median_search |
| 50 | + * @brief Functions for the Median Search algorithm implementation. Wkipedia |
| 51 | + * link to algorithm: https://en.wikipedia.org/wiki/Median_search |
| 52 | + */ |
| 53 | +namespace median_search2 { |
| 54 | +/** |
| 55 | + * This function searches for the median of a linked list. |
| 56 | + * @param head The head of the linked list. |
| 57 | + * @returns Median node of the linked list. |
| 58 | + */ |
| 59 | +ListNode* middleNode(ListNode* head) { |
| 60 | + if (!head) { |
| 61 | + return nullptr; |
| 62 | + } |
| 63 | + |
| 64 | + // Fast and slow pointers |
| 65 | + ListNode* fastptr = nullptr; |
| 66 | + ListNode* slowptr = fastptr = head; |
| 67 | + |
| 68 | + // fast jumps 2 while slow jumps 1 |
| 69 | + while (fastptr->next && fastptr->next->next) { |
| 70 | + slowptr = slowptr->next; |
| 71 | + fastptr = fastptr->next->next; |
| 72 | + } |
| 73 | + |
| 74 | + return (fastptr->next) ? slowptr->next : slowptr; |
| 75 | +} |
| 76 | +} // namespace median_search2 |
| 77 | +} // namespace search |
| 78 | + |
| 79 | +/** |
| 80 | + * @brief Self-test implementations |
| 81 | + * @returns void |
| 82 | + */ |
| 83 | +static void test() { |
| 84 | + auto* head1 = new ListNode; |
| 85 | + head1->val = 1; |
| 86 | + |
| 87 | + ListNode* temp = head1; |
| 88 | + for (int i = 2; i < 6; ++i) { |
| 89 | + // Allocate next |
| 90 | + auto* temp1 = new ListNode; |
| 91 | + temp1->val = i; |
| 92 | + |
| 93 | + // Advance |
| 94 | + temp->next = temp1; |
| 95 | + temp = temp1; |
| 96 | + } |
| 97 | + temp->next = nullptr; |
| 98 | + |
| 99 | + ListNode* median = search::median_search2::middleNode(head1); |
| 100 | + assert(3 == median->val); // 3 is the value of the median node. |
| 101 | + std::cout << "test case:1 passed\n"; |
| 102 | + |
| 103 | + // Test case # 2 |
| 104 | + auto* head2 = new ListNode; |
| 105 | + head2->val = 1; |
| 106 | + |
| 107 | + ListNode* temp2 = head2; |
| 108 | + for (int i = 2; i < 7; ++i) { |
| 109 | + // Allocate next |
| 110 | + auto* temp3 = new ListNode; |
| 111 | + temp3->val = i; |
| 112 | + |
| 113 | + // Advance |
| 114 | + temp2->next = temp3; |
| 115 | + temp2 = temp3; |
| 116 | + } |
| 117 | + temp2->next = nullptr; |
| 118 | + |
| 119 | + ListNode* median1 = search::median_search2::middleNode(head2); |
| 120 | + assert(4 == median1->val); // 4 is the value of the median node. |
| 121 | + std::cout << "test case:2 passed\n"; |
| 122 | + |
| 123 | + delete head1; |
| 124 | + delete temp; |
| 125 | + |
| 126 | + delete head2; |
| 127 | + delete temp2; |
| 128 | + |
| 129 | + std::cout << "--All tests passed--\n"; |
| 130 | +} |
| 131 | + |
| 132 | +/** |
| 133 | + * @brief Main function |
| 134 | + * @returns 0 on exit |
| 135 | + */ |
| 136 | +int main() { |
| 137 | + test(); // run self-test implementations |
| 138 | + return 0; |
| 139 | +} |
0 commit comments