Merge Sort
Stable vs. Non-Stable Sorts We frequently use sorting methods for items with multiple keys Sometimes we need to apply the sorting with different keys For instance we want to sort a list of people based on first name and than on age So Black age 30 should appear before Jones age 30 If we sort a list based on the first key (name) and then apply a sort based on the second key (age) how can we guarantee that the list is still ordered based on the first key? Definition: A sorting method is said the be stable if it preserves the relative order of the items with duplicated keys on the list
An Example of a Stable Sort Adams (30) Washington (23) Wilson (50) Black (23) Brown (40) Smith (30) Thompson (40) Jackson (23) White (50) Jones (50) Adams (30) Washington (23) Wilson (50) Black (23) Brown (40) Smith (30) Thompson (40) Jackson (23) White (50) Jones (50) Adams (30) Black (23) Brown (40) Jackson (23) Jones (50) Smith (30) Thompson (40) Washington (23) White (50) Wilson (50) Adams (30) Black (23) Brown (40) Jackson (23) Jones (50) Smith (30) Thompson (40) Washington (23) White (50) Wilson (50) Black (23) Jackson (23) Washington (23) Adams (30) Smith (30) Brown (40) Thompson (40) Jones (50) White (50) Wilson (50) Black (23) Jackson (23) Washington (23) Adams (30) Smith (30) Brown (40) Thompson (40) Jones (50) White (50) Wilson (50)
Stable vs. Non-Stable Sorts Mergesort is relatively easy to be made stable Just make sure the merge function is stable Another algorithms that sort in O(n log n) is heapsort but it is not stable Quicksort is also not stable You need to understand which of the main sorting algorithms are stable and which ones are not.
Mergesort Quicksort is based on the idea of selecting an element and dividing the list in two halves and then sorting the halves separately We examine the complementary process which is called merging. Given two lists which are ordered combine them into a larger ordered list Selection and merging are complementary because Selection divides a list into two independent lists Merging joins two independent lists into one larger list This should give a hint that Mergesort should consist of two recursive calls and one merging procedure
Mergesort The desirable features of Mergesort It performs in O (n log n) in the worst case It is stable It is quite independent of the way the initial list is organized Good for linked lists. Can me implemented in such a way that data is accessed sequentially Drawbacks It may require an array of up to the size of the original list This can be avoided but the algorithms becomes significantly more complicated making it not worth while Instead of making it complicated we can use heapsort which is also O(n log n)
Understanding the Algorithm 1. Calculate the index of the middle of the list, called it m 2. Use recursion to sort the two partitions [first,m] and [m+1,last] 3. Merge the two ordered lists into one large list 1. Calculate the index of the middle of the list, called it m 2. Use recursion to sort the two partitions [first,m] and [m+1,last] 3. Merge the two ordered lists into one large list
Mergesort in C++ void mergesort(int theArray[], int first, int last) { // PRE: list is an array && // the portion to be sorted runs from first to last inclusive if (first >= last) // Nothing to sort return; int mid = (first+last)/2; // calculate the middle of the list // Recursively call the two partitions mergesort(theArray,first,mid); mergesort(theArray,mid+1,last); merge(theArrayt,first,mid,last); // POST: list is sorted in ascending order between the first // and the last } void mergesort(int theArray[], int first, int last) { // PRE: list is an array && // the portion to be sorted runs from first to last inclusive if (first >= last) // Nothing to sort return; int mid = (first+last)/2; // calculate the middle of the list // Recursively call the two partitions mergesort(theArray,first,mid); mergesort(theArray,mid+1,last); merge(theArrayt,first,mid,last); // POST: list is sorted in ascending order between the first // and the last }
MergeSort Process The list is divided into two equal ( as equal as possible) part. There are different ways to divide the list into two equal part. The following algorithm divides the list until the list has just one item which are sorted Then with recursive merge function calls these smaller pieces merge. Let’s see the algorithm in action.
Merge Sort in Action
On the performance of Mergesort Unlike quicksort, mergesort guarantees O(n log n) in the worst case The reason for this is that quicksort depends on the value of the pivot whereas mergesort divides the list based on the index Why is it O (n log n)? Each merge will require N comparisons Each time the list is halved So the standard divide-and-conquer recurrence applies to mergesort T(n) = 2T * n/2 + (n)
Merge Sort Workhorse…Merge Function void merge(int theArray[], int first, int last) { { tempArray[MAX_SIZE]; int first1 = first; int last1 = mid; int first2 = mid+1; int last2 = last; //while both arrays are not empty, copy the smaller item into the temp array int index = first1; //next available location in tempArray for (; (first1 <= last1 && (first2 <= last2); ++index){ if (theArray[first1],theArray[first2]){ tempArray[index] = theArray[first1]; ++first1; } else{ tempArray[index] = the Array[first2]; ++first2; } //finish off the first sub array, if necessary for (; first1 <= last1; ++first1; ++index) tempArray[index] = theArray[first1]; //finish off the first sub array, if necessary for (; first2 <= last2; ++first2; ++index) tempArray[index] = theArray[first2]; //copy result back into the original array for (index = first; index<= last; ++index) theArray[index] = tempArray[index]; } //end merge void merge(int theArray[], int first, int last) { { tempArray[MAX_SIZE]; int first1 = first; int last1 = mid; int first2 = mid+1; int last2 = last; //while both arrays are not empty, copy the smaller item into the temp array int index = first1; //next available location in tempArray for (; (first1 <= last1 && (first2 <= last2); ++index){ if (theArray[first1],theArray[first2]){ tempArray[index] = theArray[first1]; ++first1; } else{ tempArray[index] = the Array[first2]; ++first2; } //finish off the first sub array, if necessary for (; first1 <= last1; ++first1; ++index) tempArray[index] = theArray[first1]; //finish off the first sub array, if necessary for (; first2 <= last2; ++first2; ++index) tempArray[index] = theArray[first2]; //copy result back into the original array for (index = first; index<= last; ++index) theArray[index] = tempArray[index]; } //end merge