5. Mergesort Flashcards

1
Q

merging:

A

combining two ordered arrays to make one larger ordered array.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
2
Q

mergesort

A

to sort an array, divide it into two halves, sort the two halves (recursively), and then merge the results.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
3
Q

Mergesort guarantees to

A

sort an array of N items in time proportional to N log N, no matter what the input. Its prime disadvantage is that it uses extra space proportional to N.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
4
Q

Abstract in-place merge.

A

The method merge(a, lo, mid, hi) in Merge.java puts the results of merging the subarrays a[lo..mid] with a[mid+1..hi] into a single ordered array, leaving the result in a[lo..hi]. While it would be desirable to implement this method without using a significant amount of extra space, such solutions are remarkably complicated. Instead, merge() copies everything to an auxiliary array and then merges back to the original.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
5
Q

Top-down mergesort

A

Merge.java is a recursive mergesort implementation based on this abstract in-place merge. It is one of the best-known examples of the utility of the divide-and-conquer paradigm for efficient algorithm design.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
6
Q

//Merge.java
/**
* The {@code Merge} class provides static methods for sorting an
* array using a top-down, recursive version of <em>mergesort</em>.
* <p>
* This implementation takes Θ(<em>n</em> log <em>n</em>) time
* to sort any array of length <em>n</em> (assuming comparisons
* take constant time). It makes between
* ~ ½ <em>n</em> log2 <em>n</em> and
* ~ 1 <em>n</em> log2 <em>n</em> compares.
* <p>
* This sorting algorithm is stable.
* It uses Θ(<em>n</em>) extra memory (not including the input array).
* <p>
*/
public class Merge {

A

// This class should not be instantiated.
private Merge() { }

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
7
Q

//Merge.java
// stably merge a[lo .. mid] with a[mid+1 ..hi] using aux[lo .. hi]
private static void merge(Comparable[] a, Comparable[] aux, int lo, int mid, int hi) {
// precondition: a[lo .. mid] and a[mid+1 .. hi] are sorted subarrays
assert isSorted(a, lo, mid);
assert isSorted(a, mid+1, hi);

    // copy to aux[]
    for (int k = lo; k <= hi; k++) {
        aux[k] = a[k];
    }

    // merge back to a[]
    int i = lo, j = mid+1;
    for (int k = lo; k <= hi; k++) {
        if      (i > mid)              a[k] = aux[j++];
        else if (j > hi)               a[k] = aux[i++];
        else if (less(aux[j], aux[i])) a[k] = aux[j++];
        else                           a[k] = aux[i++];
A

// precondition: a[lo .. mid] and a[mid+1 .. hi] are sorted subarrays
assert isSorted(a, lo, mid);
assert isSorted(a, mid+1, hi);

    // copy to aux[]
    for (int k = lo; k <= hi; k++) {
        aux[k] = a[k];
    }

    // merge back to a[]
    int i = lo, j = mid+1;
    for (int k = lo; k <= hi; k++) {
        if      (i > mid)              a[k] = aux[j++];
        else if (j > hi)               a[k] = aux[i++];
        else if (less(aux[j], aux[i])) a[k] = aux[j++];
        else                           a[k] = aux[i++];
    }
    // postcondition: a[lo .. hi] is sorted
    assert isSorted(a, lo, hi);
}
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
8
Q

//Merge.java
// mergesort a[lo..hi] using auxiliary array aux[lo..hi]
private static void sort(Comparable[] a, Comparable[] aux, int lo, int hi) {

A

if (hi <= lo) return;
int mid = lo + (hi - lo) / 2;
sort(a, aux, lo, mid);
sort(a, aux, mid + 1, hi);
merge(a, aux, lo, mid, hi);
}

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
9
Q

//Merge.java
/**
* Rearranges the array in ascending order, using the natural order.
* @param a the array to be sorted
*/
public static void sort(Comparable[] a) {

A

Comparable[] aux = new Comparable[a.length];
sort(a, aux, 0, a.length-1);
assert isSorted(a);
}

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
10
Q

//Merge.java
// is v < w ?
private static boolean less(Comparable v, Comparable w) {

A

return v.compareTo(w) < 0;
}

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
11
Q

//Merge.java
private static boolean isSorted(Comparable[] a) {

A

return isSorted(a, 0, a.length - 1);
}

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
12
Q

//Merge.java
private static boolean isSorted(Comparable[] a, int lo, int hi) {

A

for (int i = lo + 1; i <= hi; i++)
if (less(a[i], a[i-1])) return false;
return true;
}

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
13
Q

///Merge.java
*
* Index mergesort.
*/
// stably merge a[lo .. mid] with a[mid+1 .. hi] using aux[lo .. hi]
private static void merge(Comparable[] a, int[] index, int[] aux, int lo, int mid, int hi) {

A

// copy to aux[]
for (int k = lo; k <= hi; k++) {
aux[k] = index[k];
}

    // merge back to a[]
    int i = lo, j = mid+1;
    for (int k = lo; k <= hi; k++) {
        if      (i > mid)                    index[k] = aux[j++];
        else if (j > hi)                     index[k] = aux[i++];
        else if (less(a[aux[j]], a[aux[i]])) index[k] = aux[j++];
        else                                 index[k] = aux[i++];
    }
}
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
14
Q

//Merge.java
/**
* Returns a permutation that gives the elements in the array in ascending order.
* @param a the array
* @return a permutation {@code p[]} such that {@code a[p[0]]}, {@code a[p[1]]},
* …, {@code a[p[n-1]]} are in ascending order
*/
public static int[] indexSort(Comparable[] a) {

A

int n = a.length;
int[] index = new int[n];
for (int i = 0; i < n; i++)
index[i] = i;

    int[] aux = new int[n];
    sort(a, index, aux, 0, n-1);
    return index;
}
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
15
Q

//Merge.java
// mergesort a[lo..hi] using auxiliary array aux[lo..hi]
private static void sort(Comparable[] a, int[] index, int[] aux, int lo, int hi) {

A

if (hi <= lo) return;
int mid = lo + (hi - lo) / 2;
sort(a, index, aux, lo, mid);
sort(a, index, aux, mid + 1, hi);
merge(a, index, aux, lo, mid, hi);
}

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
16
Q

//Merge.java
// print array to standard output
private static void show(Comparable[] a) {

A

for (int i = 0; i < a.length; i++) {
StdOut.println(a[i]);
}
}

17
Q

//Merge.java
/**
* Reads in a sequence of strings from standard input; mergesorts them;
* and prints them to standard output in ascending order.
*
* @param args the command-line arguments
*/
public static void main(String[] args) {

A

String[] a = StdIn.readAllStrings();
Merge.sort(a);
show(a);
}
}

18
Q

Top-down mergesort uses between ______ and ___ compares and at most ___ array accesses to sort any array of length N.

A

Top-down mergesort uses between (1/2)Nlg N and NlgN compares and at most 6 N lg N array accesses to sort any array of length N.

19
Q

Improvements: Use insertion sort for small subarrays

A

We can improve most recursive algorithms by handling small cases differently. Switching to insertion sort for small subarrays will improve the running time of a typical mergesort implementation by 10 to 15 percent.

20
Q

Improvements: Test whether array is already in order.

A

We can reduce the running time to be linear for arrays that are already in order by adding a test to skip call to merge() if a[mid] is less than or equal to a[mid+1]. With this change, we still do all the recursive calls, but the running time for any sorted subarray is linear.

21
Q

Improvements: Eliminate the copy to the auxiliary array.

A

It is possible to eliminate the time (but not the space) taken to copy to the auxiliary array used for merging. To do so, we use two invocations of the sort method, one that takes its input from the given array and puts the sorted output in the auxiliary array; the other takes its input from the auxiliary array and puts the sorted output in the given array. With this approach, in a bit of mindbending recursive trickery, we can arrange the recursive calls such that the computation switches the roles of the input array and the auxiliary array at each level.

22
Q

Bottom-up mergesort.

A

Even though we are thinking in terms of merging together two large subarrays, the fact is that most merges are merging together tiny subarrays. Another way to implement mergesort is to organize the merges so that we do all the merges of tiny arrays on one pass, then do a second pass to merge those arrays in pairs, and so forth, continuing until we do a merge that encompasses the whole array. This method requires even less code than the standard recursive implementation. We start by doing a pass of 1-by-1 merges (considering individual items as subarrays of size 1), then a pass of 2-by-2 merges (merge subarrays of size 2 to make subarrays of size 4), then 4-by-4 merges, and so forth. MergeBU.java is an implementation of bottom-up mergesort.

23
Q

//MergeBU.java
/**
* The {@code MergeBU} class provides static methods for sorting an
* array using <em>bottom-up mergesort</em>. It is non-recursive.
* <p>
* This implementation takes Θ(<em>n</em> log <em>n</em>) time
* to sort any array of length <em>n</em> (assuming comparisons
* take constant time). It makes between
* ~ ½ <em>n</em> log2 <em>n</em> and
* ~ 1 <em>n</em> log2 <em>n</em> compares.
* <p>
* This sorting algorithm is stable.
* It uses Θ(<em>n</em>) extra memory (not including the input array).
*/
public class MergeBU {

A

// This class should not be instantiated.
private MergeBU() { }

24
Q

//MergeBU.java
// stably merge a[lo..mid] with a[mid+1..hi] using aux[lo..hi]
private static void merge(Comparable[] a, Comparable[] aux, int lo, int mid, int hi) {

A

// copy to aux[]
for (int k = lo; k <= hi; k++) {
aux[k] = a[k];
}

    // merge back to a[]
    int i = lo, j = mid+1;
    for (int k = lo; k <= hi; k++) {
        if      (i > mid)              a[k] = aux[j++];  // this copying is unnecessary
        else if (j > hi)               a[k] = aux[i++];
        else if (less(aux[j], aux[i])) a[k] = aux[j++];
        else                           a[k] = aux[i++];
    }

}
25
Q

//MergeBU.java
/**
* Rearranges the array in ascending order, using the natural order.
* @param a the array to be sorted
*/
public static void sort(Comparable[] a) {

A

int n = a.length;
Comparable[] aux = new Comparable[n];
for (int len = 1; len < n; len *= 2) {
for (int lo = 0; lo < n-len; lo += len+len) {
int mid = lo+len-1;
int hi = Math.min(lo+len+len-1, n-1);
merge(a, aux, lo, mid, hi);
}
}
assert isSorted(a);
}

26
Q

//MergeBU.java
// is v < w ?
private static boolean less(Comparable v, Comparable w) {

A

return v.compareTo(w) < 0;
}

27
Q

//MergeBU.java
private static boolean isSorted(Comparable[] a) {

A

for (int i = 1; i < a.length; i++)
if (less(a[i], a[i-1])) return false;
return true;
}

28
Q

//MergeBU.java
// print array to standard output
private static void show(Comparable[] a) {

A

for (int i = 0; i < a.length; i++) {
StdOut.println(a[i]);
}
}

29
Q

//MergeBU.java
/**
* Reads in a sequence of strings from standard input; bottom-up
* mergesorts them; and prints them to standard output in ascending order.
*
* @param args the command-line arguments
*/
public static void main(String[] args) {

A

String[] a = StdIn.readAllStrings();
MergeBU.sort(a);
show(a);
}
}

30
Q

Bottom-up mergesort uses between ___ and ___ compares and at most ___ array accesses to sort any array of length N.

A

Bottom-up mergesort uses between 1/2 N lg N and N lg N compares and at most 6 N lg N array accesses to sort any array of length N.

31
Q

No compare-based sorting algorithm can guarantee to sort N items with fewer than ___ ~ ___ compares.

A

No compare-based sorting algorithm can guarantee to sort N items with fewer than lg(N!) ~ N lg N compares.

32
Q

Mergesort is an asymptotically optimal compare-based sorting algorithm.

A

That is, both the number of compares used by mergesort in the worst case and the minimum number of compares that any compare-based sorting algorithm can guarantee are ~N lg N.