© 2004 Goodrich, Tamassia Merge Sort 1
© 2004 Goodrich, Tamassia Merge Sort 1
7 29 4 2 4 7 9
72 2 7
77 22
94 4 9
99 44
Merge Sort
Divide-and-Conquer ( 10.1.1)
Divide-and conquer is a general algorithm design paradigm:
Divide: divide the input data S in two disjoint subsets S1 and S2 Recur: solve the subproblems associated with S1 and S2 Conquer: combine the solutions for S1 and S2 into a solution for S
It uses a comparator It has O(n log n) running time It does not use an auxiliary priority queue It accesses data in a sequential manner (suitable to sort data on a disk)
2
Unlike heap-sort
Merge Sort
Merge-Sort
Merge-sort on an input sequence S with n elements consists of three steps:
Divide: partition S into two sequences S1 and S2 of about n/2 elements each Recur: recursively sort S1 and S2 Conquer: merge S1 and S2 into a unique sorted sequence
Algorithm mergeSort(S, C) Input sequence S with n elements, comparator C Output sequence S sorted according to C if S.size() > 1 (S1, S2) partition(S, n/2) mergeSort(S1, C) mergeSort(S2, C) S merge(S1, S2)
Merge Sort
Algorithm merge(A, B) Input sequences A and B with n/2 elements each Output sorted sequence of A B
S empty sequence while A.isEmpty() B.isEmpty() if A.first().element() < B.first().element() S.insertLast(A.remove(A.first())) else S.insertLast(B.remove(B.first())) while A.isEmpty() S.insertLast(A.remove(A.first())) while B.isEmpty() S.insertLast(B.remove(B.first())) return S
Merge Sort 4
Merge-Sort Tree
An execution of merge-sort is depicted by a binary tree
the root is the initial call the leaves are calls on subsequences of size 0 or 1
7 2
9 4 2 4 7 9
2 2 7
22
4 4 9
44
5
77
2004 Goodrich, Tamassia
99
Merge Sort
Execution Example
Partition
7 2 9 43 8 6 1 1 2 3 4 6 7 8 9
7 2 9 4 2 4 7 9
3 8 6 1 1 3 8 6
7 2 2 7
9 4 4 9
3 8 3 8
6 1 1 6
77
22
99
44
Merge Sort
33
88
66
11
6
7 29 4 2 4 7 9
3 8 6 1 1 3 8 6
7 2 2 7
9 4 4 9
3 8 3 8
6 1 1 6
77
22
99
44
Merge Sort
33
88
66
11
7
7 29 4 2 4 7 9
3 8 6 1 1 3 8 6
722 7
9 4 4 9
3 8 3 8
6 1 1 6
77
22
99
44
Merge Sort
33
88
66
11
8
7 29 4 2 4 7 9
3 8 6 1 1 3 8 6
722 7
9 4 4 9
3 8 3 8
6 1 1 6
77
22
99
44
Merge Sort
33
88
66
11
9
7 29 4 2 4 7 9
3 8 6 1 1 3 8 6
722 7
9 4 4 9
3 8 3 8
6 1 1 6
77
22
99
44
Merge Sort
33
88
66
11
10
7 29 4 2 4 7 9
3 8 6 1 1 3 8 6
722 7
9 4 4 9
3 8 3 8
6 1 1 6
77
22
99
44
Merge Sort
33
88
66
11
11
7 29 4 2 4 7 9
3 8 6 1 1 3 8 6
722 7
9 4 4 9
3 8 3 8
6 1 1 6
77
22
99
44
Merge Sort
33
88
66
11
12
7 29 4 2 4 7 9
3 8 6 1 1 3 8 6
722 7
9 4 4 9
3 8 3 8
6 1 1 6
77
22
99
44
Merge Sort
33
88
66
11
13
7 29 4 2 4 7 9
3 8 6 1 1 3 6 8
722 7
9 4 4 9
3 8 3 8
6 1 1 6
77
22
99
44
Merge Sort
33
88
66
11
14
7 29 4 2 4 7 9
3 8 6 1 1 3 6 8
722 7
9 4 4 9
3 8 3 8
6 1 1 6
77
22
99
44
Merge Sort
33
88
66
11
15
Analysis of Merge-Sort
The height h of the merge-sort tree is O(log n)
at each recursive call we divide in half the sequence, we partition and merge 2i sequences of size n/2i we make 2i+1 recursive calls
Time
O(n2) O(n2) O(n log n)
Notes
slow in-place for small data sets (< 1K) slow in-place for small data sets (< 1K)
merge-sort
2004 Goodrich, Tamassia
O(n log n)
Merge Sort
Nonrecursive Merge-Sort
merge runs of length 2, then 4, then 8, and so on
public static void mergeSort(Object[] orig, Comparator c) { // nonrecursive Object[] in = new Object[orig.length]; // make a new temporary array System.arraycopy(orig,0,in,0,in.length); // copy the input Object[] out = new Object[in.length]; // output array Object[] temp; // temp array reference used for swapping int n = in.length; for (int i=1; i < n; i*=2) { // each iteration sorts all length-2*i runs for (int j=0; j < n; j+=2*i) // each iteration merges two length-i pairs merge(in,out,c,j,i); // merge from in to out two length-i runs at j temp = in; in = out; out = temp; // swap arrays for next iteration } // the "in" array contains the sorted array, so re-copy it System.arraycopy(in,0,orig,0,in.length); } protected static void merge(Object[] in, Object[] out, Comparator c, int start, int inc) { // merge in[start..start+inc-1] and in[start+inc..start+2*inc-1] int x = start; // index into run #1 int end1 = Math.min(start+inc, in.length); // boundary for run #1 int end2 = Math.min(start+2*inc, in.length); // boundary for run #2 int y = start+inc; // index into run #2 (could be beyond array boundary) int z = start; // index into the out array while ((x < end1) && (y < end2)) if (c.compare(in[x],in[y]) <= 0) out[z++] = in[x++]; else out[z++] = in[y++]; if (x < end1) // first run didn't finish System.arraycopy(in, x, out, z, end1 - x); else if (y < end2) // second run didn't finish System.arraycopy(in, y, out, z, end2 - y); }
Merge Sort
18