760 likes | 915 Views
Object Oriented Data Structures. Sorting Insertion Sort Selection Sort Shell Sort Divide and Conquer Sort Merge Sort Quick Sort Heaps and Heap Sort. Sorting.
E N D
Object Oriented Data Structures Sorting Insertion SortSelection SortShell SortDivide and Conquer SortMerge SortQuick SortHeaps and Heap Sort Kruse/Ryba ch08
Sorting There is part of me that wants to write, part that wants to theorize, a part that wants to sculpt, a part that wants to teach....To force myself into a single role, to decide to be just one thing in life, would kill off large parts of me. My career will form behind me. All I can do is let this day come to me in peace. All I can do is take the step before me now, and not fear repeating an effort or making a new one. Hugh PratherNotes to Myself Kruse/Ryba ch08
Sortable Lists • template <class Record> • class Sortable_list:public List<Record> { • public: // Add prototypes for sorting methods here. • private: // Add prototypes for auxiliary functions here. • }; Kruse/Ryba ch08
Insertion Sort - contiguous "Cow" "Dog" "Ilama" "Horse" "Jackass" "Yak" Kruse/Ryba ch08
"Iquana" "Iquana" Insertion Sort - contiguous "Cow" "Dog" "Horse" "Jackass" "Yak" Kruse/Ryba ch08
template <class Record>void Sortable_list<Record>::insertion_sort(){int i; // first unsorted entryint j; // searches sorted part Record current; //entry temporarily removedfor (i = 1; i < count; i++) {if (entry[i] < entry[i - 1]) { j = i; current = entry[i]; // Pull unsorted entry outdo { // Shift entries entry[j] = entry[j - 1]; j--; // j is empty. } while (j > 0 && entry[j - 1] > current); • entry[j] = current; } { // for loop} Kruse/Ryba ch08
Insertion Sort - linked "Cow" "Dog" "Horse" "Jackass" "Yak" "Llama" Kruse/Ryba ch08
Insertion Sort - linked "Cow" "Dog" "Horse" "Jackass" "Yak" "Llama" It goes here!!!! Kruse/Ryba ch08
Insertion Sort - linked "Cow" "Dog" "Horse" "Jackass" "Yak" "Llama" Kruse/Ryba ch08
{ • Node <Record> *first_unsorted, // the first unsorted *last_sorted, // tail of the sorted sublist *current, // used to traverse the sorted sublist *trailing; // one position behind current Kruse/Ryba ch08
if (head != NULL) { last_sorted = head; while (last_sorted->next != NULL) { first_unsorted = last_sorted->next;if (first_unsorted->entry < head->entry) { last_sorted->next = first_unsorted->next; first_unsorted->next = head; head = first_unsorted; }else { trailing = head; current = trailing->next;while (first_unsorted->entry > current->entry) { trailing = current; current = trailing->next; }if (first_unsorted == current) last_sorted = first_unsorted; else { last_sorted->next = first_unsorted->next; first_unsorted->next = current; trailing->next = first_unsorted; • } Kruse/Ryba ch08
Analysis • Verifies that a list is correctly sorted as quickly as can be done. • Good whenever a list is nearly in the correct order and a few entries are many position away from correct locations. Kruse/Ryba ch08
Selection Sort • Still relatively easy to prove correct. • Performs only O(n) swaps. • Still performs O(n2) comparisons. Kruse/Ryba ch08
Create a variable largest Selection Sort 0 initialize to zero table[0] table[1] table[2] table[3] table[4] 45 31 23 76 20 Kruse/Ryba ch08
j Create a variable largest Selection Sort 0 table[0] table[1] table[2] table[3] table[4] 45 31 23 76 20 create a variable j and initialize it to 1 Kruse/Ryba ch08
j Create a variable largest Selection Sort 0 table[0] table[1] table[2] table[3] table[4] 45 31 23 76 20 create a variable j and initialize it to 1 Kruse/Ryba ch08
j Create a variable largest Selection Sort 0 compare the contents of the cells specified by largest and j. If the data in largest is less than the data in position j, copy j to largest table[0] table[1] table[2] table[3] table[4] 45 31 23 76 20 Kruse/Ryba ch08
j Create a variable largest Selection Sort 0 table[0] table[1] table[2] table[3] table[4] 45 31 23 76 20 advance j by 1 and compare again. Kruse/Ryba ch08
j Create a variable largest Selection Sort 3 table[0] table[1] table[2] table[3] table[4] 45 31 23 76 20 advance j and compare again. This time there is a change in largest Kruse/Ryba ch08
j Create a variable largest Selection Sort 3 table[0] table[1] table[2] table[3] table[4] 45 31 23 76 20 the last comparison takes place when j reaches top. There is no change and largest contains the location of the largest element. Kruse/Ryba ch08
j Create a variable largest Selection Sort 3 table[0] table[1] table[2] table[3] table[4] 45 31 23 76 20 If the element found at largestis greater than the element found at top, swap them Kruse/Ryba ch08
top Create a variable largest Selection Sort 0 table[0] table[1] table[2] table[3] table[4] 45 31 23 20 76 decrement top by one and start over Kruse/Ryba ch08
template <class Record>void Sortable_list<Record>::selection_sort()/*Post: The entries of the Sortable_list have been rearranged so that the keys in all the entries are sorted into nondecreasing order.Uses: max_key, swap.*/ • {for (int position = count - 1; position > 0; position--) {int max = max_key(0, position); swap(max, position); }} Kruse/Ryba ch08
template <class Record>int Sortable_list<Record>::max_key(int low, int high) • /*Pre: low and high are valid positions in the Sortable_list and low <= high.Post: The position of the entry between low and high with the largest key is returned.*/{int largest, current; largest = low;for (current = low + 1; current <= high; current++)if (entry[largest] < entry[current]) largest = current;return largest;} Kruse/Ryba ch08
Shell Sort Tim Dot Eva Roy Tom Kim Guy Amy Jon Ann Jim Kay Ron Jan Kruse/Ryba ch08
Tim Tim Tim Tim Tim Dot Dot Dot Dot Dot Eva Eva Eva Eva Eva Roy Roy Roy Roy Roy Tom Tom Tom Tom Tom Kim Kim Kim Kim Kim Guy Guy Guy Guy Guy Amy Amy Amy Amy Amy Jon Jon Jon Jon Jon Ann Ann Ann Ann Ann Jim Jim Jim Jim Jim Kay Kay Kay Kay Kay Ron Ron Ron Ron Ron Jan Jan Jan Jan Jan Shell Sort Kruse/Ryba ch08
Jim Tim Tim Tim Dot Dot Dot Dot Eva Eva Amy Eva Roy Roy Roy Roy Tom Tom Tom Tom Kim Kim Kim Kim Guy Guy Guy Guy Amy Amy Eva Amy Jon Jon Jon Jon Ann Ann Ann Ann Tim Jim Jim Jim Kay Kay Kay Kay Ron Ron Ron Ron Jan Jan Jan Jan Shell Sort Tim Dot Eva Roy Ann Kim Guy Amy Jon Tom Jim Kay Ron Jan Kruse/Ryba ch08
Shell Sort Jim Dot Amy Jan Ann Kim Guy Eva Jon Tom Tim Kay Ron Roy Kruse/Ryba ch08
Jim Jim Jim Dot Dot Dot Amy Amy Amy Jan Jan Jan Ann Ann Ann Kim Kim Kim Guy Guy Guy Eva Eva Eva Jon Jon Jon Tom Tom Tom Tim Tim Tim Kay Kay Kay Ron Ron Ron Roy Roy Roy Shell Sort Kruse/Ryba ch08
Guy Guy Guy Dot Ann Ann Amy Amy Amy Jan Jan Jan Ann Dot Dot Kim Kim Jon Jim Jim Jim Eva Eva Eva Jon Jon Kay Ron Ron Ron Tim Roy Roy Kay Kay Kim Tom Tom Tom Roy Tim Roy Shell Sort Kruse/Ryba ch08
Guy Amy Ann Ann Amy Dot Jan Eva Dot Guy Jon Jan Jim Jim Eva Jon Kay Kay Ron Kim Roy Ron Kim Roy Tom Tim Tim Tom Shell Sort Kruse/Ryba ch08
template <class Record>void Sortable_list<Record>::shell_sort() {int increment, // spacing of entries start; // starting point increment = count;do { increment = increment / 3 + 1;for (start = 0; start < increment; start++) sort_interval(start, increment);// modified insertion sort • } while (increment > 1); • } Kruse/Ryba ch08
How Fast? Any algorithm that sorts a list of n entries by use of key comparisons must, in its worst case, perform at least comparisons of keys, and in the average case, it must perform at least comparison of keys. Kruse/Ryba ch08
void Sortable_list::sort(){ if the list has length greater than 1 { partition the list into lowlist, highlist; lowlist.sort(); highlist.sort(); combine(lowlist, highlist); }} Divide and Conquer Kruse/Ryba ch08
Mergesort • Chop into two sublists of near equal size • Sort each sublist separately • Merge two lists into one sorted list Kruse/Ryba ch08
template <class Record>void sortable_list<Record>::recursive_merge_sort(Node<Record> *&sub_list) • {if (sub_list != NULL && sub_list->next != NULL) { Node<Record> *second_half = divide_from(sub_list); recursive_merge_sort(sub_list); recursive_merge_sort(second_half); sub_list = merge(sub_list, second_half); • } Kruse/Ryba ch08
divide_from(Node<Record> *sub_list){ Node<Record> *position,*midpoint,*second_half;if ((midpoint = sub_list) == NULL) return NULL; // List is empty. position = midpoint->next;while (position != NULL) { position = position->next;if (position != NULL) { midpoint = midpoint->next; position = position->next; } } second_half = midpoint->next; midpoint->next = NULL;return second_half;} Kruse/Ryba ch08
Quicksort • Choose one key from the list that will (hopefully) partition the list into two approximately equal sublists. • Repeat for each of the sublists until the sublists are very small • Sort the reduced sublists • Put the sublists together Kruse/Ryba ch08
Partitioning A key insight is that one can very quickly partition a vector into those elements that are larger than some value and those elements that are smaller. 2 97 17 37 12 46 10 55 80 42 39 Kruse/Ryba ch08
2 97 17 37 12 46 10 55 80 42 39 Partitioning Choose an element, say element 37. Call this the pivot element. Divide the vector into those portions smaller than 37 and those larger than 37. Kruse/Ryba ch08
2 97 17 37 12 46 10 55 80 42 39 Partitioning Divide the vector into those portions smaller than 37 and those larger than 37. 12 10 17 37 2 97 46 55 80 42 39 > pivot <= pivot pivot Kruse/Ryba ch08
97 17 12 46 10 55 80 42 39 37 2 97 17 12 46 10 55 80 42 39 37 2 97 17 12 46 10 55 80 42 39 37 2 Vizualization of Partitioning Algorithm The algorithm proceeds by first moving the pivot to the bottom of the vector, then movinglowandhigh index counters towards each other. The area between the two index values is unknown. 2 97 17 37 12 46 10 55 80 42 39 Kruse/Ryba ch08
97 17 12 46 10 55 80 42 39 37 2 97 17 12 46 10 55 80 42 39 37 2 97 17 12 46 10 55 80 42 39 37 2 10 17 12 46 97 55 80 42 39 37 2 10 17 12 46 97 55 80 42 39 37 2 97 17 12 46 10 55 80 42 39 37 2 Kruse/Ryba ch08
10 17 12 46 97 55 80 42 39 37 2 check 17 check 2 10 17 12 46 97 55 80 42 39 37 2 check 12 10 17 12 46 97 55 80 42 39 37 2 10 10 10 check 46 17 17 17 12 12 12 97 97 46 97 46 46 55 55 55 80 80 80 42 42 42 39 39 39 37 37 37 2 2 2 SWAP check 46 Kruse/Ryba ch08
check 46 When the two indexes cross, the vector is divided into two parts, but the pivot is out of place. 10 17 12 46 97 55 80 42 39 37 2 A final swap is then used to put the pivot between the two sections. 10 17 12 46 97 55 80 42 39 37 2 10 37 17 46 97 55 80 42 39 12 2 10 17 12 46 97 55 80 42 39 37 2 Kruse/Ryba ch08
Quicksort, the Algorithm • template <class Record>void Sortable_list<Record>::quick_sort()/*Post: The entries of the Sortable_list have been rearranged so that their keys are sorted into nondecreasing order. • Uses: The contiguous List implementation of Chapter 6, recursive_quick_sort.*/{ recursive_quick_sort(0, count - 1);} Kruse/Ryba ch08
template <class Record>void sortable_list<Record>::recursive_quick_sort(int low, int high){int pivot;if (low < high) { // Otherwise, no sorting needed. pivot = partition(low, high); recursive_quick_sort(low, pivot - 1); recursive_quick_sort(pivot + 1, high); }} Kruse/Ryba ch08
Selecting Good Pivots Execution can be improved if we try to select pivot elements in an intelligent fashion. Algorithms that have been proposed: Kruse/Ryba ch08
Selecting Good Pivots • Simply use the first element as the pivot value. This avoids the need for the initial swap, but is a relatively poor choice if the vector is somewhat, but not completely, ordered. • Select the pivot at random from the range of values. • Select the pivot as the value in the midpoint range of elements (this is the option used in our version of the algorithm) • Select three values from the range, and compute the mean (middle) value from these three. Kruse/Ryba ch08
Asymptotic Execution of Quicksort Best case occurs if we always select a pivot that divides vector in half. n n/2 n/4 n/8 Kruse/Ryba ch08