/* ****************************************************************************** * file name : search_sort.cpp * author : Hung Q. Ngo * description: implementations of various search & sorting algorithms on * integers, including * - linear search * - binary search * - insertion sort * - selection sort * - merge sort * - quick sort * - randomized quick sort * - heap sort ****************************************************************************** */ #include #include "search_sort.h" using namespace std; /** * ----------------------------------------------------------------------------- * The Seclection Sort algorithm * for each i from 0 to n-2, move the i'th smallest element to its position * ----------------------------------------------------------------------------- */ void selection_sort(vector &vec) { int i, j, k; for (i=0; i &vec) { int temp, j; for (int i=1; i= 0 && vec[j] > temp) { vec[j+1] = vec[j]; j--; } vec[j+1] = temp; } } /** * ----------------------------------------------------------------------------- * merges two halves, this function does not need to be in the header file * because the users don't use it directly. Without a prototype, its definition * has to come before merge_sort() itself * ----------------------------------------------------------------------------- */ void merge(vector &target, const vector &left, const vector &right) { if (target.size() != left.size() + right.size()) return; // sanity check size_t i=0, j=0, k=0; while (i < left.size() && j < right.size()) { if (left[i] <= right[j]) target[k++] = left[i++]; else target[k++] = right[j++]; } while (i < left.size()) target[k++] = left[i++]; while (j < right.size()) target[k++] = right[j++]; } /** * ----------------------------------------------------------------------------- * The Merge Sort algorithm * - create a copy of the left half, and a copy of the right half * - recursively sort the left half and the right half * - then merge the two halves * ----------------------------------------------------------------------------- */ void merge_sort(vector &vec) { size_t n = vec.size(); if (n <= 1) return; vector left(vec.begin(), vec.begin()+n/2); vector right(vec.begin()+n/2, vec.end()); merge_sort(left); merge_sort(right); merge(vec, left, right); } /** * ----------------------------------------------------------------------------- * The Quick Sort algorithm * - we rearrange the members vec[p...q] so that there will be some r between * p and q such that all vec[i] < vec[r] for p <= i < r and * vec[r] <= vec[j] for r < j <= q * - then sort vec[p..r-1] and vec[r+1..q] * ----------------------------------------------------------------------------- */ void qs_with_range(vector &vec, int p, int q) { if (p >= q) return; // partition, int r=p-1; for (int j=p; j &vec) { qs_with_range(vec, 0, vec.size()-1); } /** * ----------------------------------------------------------------------------- * The Randomized Quick Sort algorithm * - pick a random pivot, that's all * ----------------------------------------------------------------------------- */ void rqs_with_range(vector &vec, int p, int q) { if (p >= q) return; // pick a random pivot int m = rand() % (q-p+1); swap(vec[q], vec[p+m]); // partition int r=p-1; for (int j=p; j &vec) { srand(static_cast(time(0))); rqs_with_range(vec, 0, vec.size()-1); } /** * ----------------------------------------------------------------------------- * sink node i of the heap vec[0..n-1] * - uses a recursive strategy for easy explanation * - if the greater of the left or the right child is greater than the node * then swap and sink that subtree * ----------------------------------------------------------------------------- */ void recursive_sink(vector &vec, size_t i, size_t n) { size_t left = 2*i + 1; if (n > vec.size() || left >= n) return; size_t right = left + 1; // possibly >= n size_t my_pick = (right >= n) ? left : (vec[right] > vec[left]) ? right : left; if (vec[i] < vec[my_pick]) { swap(vec[i], vec[my_pick]); recursive_sink(vec, my_pick, n); } } /** * ----------------------------------------------------------------------------- * "un-spinning" the previous recursive sinking procedure * ----------------------------------------------------------------------------- */ void sink(vector &vec, size_t i, size_t n) { if (n > vec.size()) return; size_t left, right, my_pick; while ((left = 2*i+1) < n) { // left = 2*i+1; // if (left >= n) break; right = left + 1; // possibly >= n my_pick = right >= n ? left : vec[right] > vec[left] ? right : left; if (vec[i] >= vec[my_pick]) break; swap(vec[i], vec[my_pick]); i = my_pick; } } /** * ----------------------------------------------------------------------------- * turn the input vector into a heap * ----------------------------------------------------------------------------- */ void heapify(vector &vec) { for (int i=vec.size()/2; i>=0; i--) // recursive_sink(vec, i, vec.size()); sink(vec, i, vec.size()); } /** * ----------------------------------------------------------------------------- * The Heap Sort algorithm * - heapify the array of size n * - swap the first and the last * - sink the first and recurse * ----------------------------------------------------------------------------- */ void heap_sort(vector &vec) { heapify(vec); for (int j=vec.size()-1; j>=1; j--) { swap(vec[0], vec[j]); // could also do recursive_sink(vec, 0, j); sink(vec, 0, j); } } /** * ----------------------------------------------------------------------------- * scan a vector, search for the key * ----------------------------------------------------------------------------- */ bool linear_search(vector& vec, int key) { for (size_t i=0; i& sorted_vec, int key, size_t left, size_t right) { while (left <= right) { // the following will cause problems if you do // mid = (left+right)/2, due to potential integer overflow size_t mid = left + (right - left)/2; if (key > sorted_vec[mid]) left = mid+1; else if (key < sorted_vec[mid]) right = mid-1; else return true; } return false; }