文章目录
Sorting
Merge Sort
Implementation
Also see source code in Merge.java
- Merger function, merge to sorted arrays.
private static void merge(Comparable[] a, Comparable[] aux, int lo, int mid, int hi) {
assert isSorted(a, lo, mid);
assert isSorted(a, mid+1, hi);
// copy to auxiliary array
for (int k = lo; k < hi; k++) {
aux[k] = a[k];
}
// merge
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++];
}
}
- Class Merge, perform sort and merge
private class Merge {
private static void merge(...) { /* as before */}
private static void sort(Comparable[] a, Comparable[] aux, int lo, int hi) {
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);
}
public static void sort(Comparable[] a) {
aux = new Comparable[a.length];
sort(a, aux, 0, a.length - 1);
}
}
- Bottom-up mergesort: Java implementation
public class MergeBU {
private static void merge(...) {...}
private static void sort(Comparable[] a) {
int N = a.length;
Comparable[] aux = new Comparable[N];
for (int sz = 1; sz < N; sz = sz+sz) {
// array size 从 1 开始, 每次 merge 完之后 size 翻倍
for (int lo = 0; lo < N-sz; lo += sz+sz)
// two array of size sz merge together, then go to the next two sub-array, until the end of array.
merge(a, aux, lo, lo+sz-1, Math.min(lo+sz+sz-1, N-1)));
}
}
}
- Practical improvements
- Use insertion sort for small subarrays
- Stop if already sorted
- Is biggest item in first half <= smallest item in second half?
- Helps for partially-ordered arrays.
- Eliminate the copy to the auxiliary array. Save time (but not space).
Comparators
-
Comparable interface: sort using a type’s natural order.
-
Comparator interface: sort using an alternate order (Must be a total order)
public interface Comparator<Key> int compare(Key v, Key w) // compare keys v and w
-
To implement a comparator:
- Define a (nested) class that implements the Comparator interface.
- Implement the
compare()
method.
Example: Point2D.java
Stability
A typical application: First, sort by name, then sort by section.
A stable sort preserves the relative order of items with equal keys.
Stable: Insertion, Merge Sort Unstable: Selection, Shell, Quick Sort
Quick Sort
Implementation
Choose a sentinel and partition the array, also see in Quick.java
private static int partition(Comparable[] a, int lo, int hi) {
int i = lo, j = hi+1;
while (true) {
while (less(a[++i], a[lo])) // 如果a[i]小于sentinel,++i
if (i == hi) break;
while (less(a[lo], a[--j])) // 如果a[j]小于sentinel,--j
if (j == lo) break;
if (i >= j) break; // i and j cross, exit loop
exch(a, i, j); // exchange a[i] and a[j]
}
exch(a, lo, j); // exchange a[lo](sentinel) and a[j]
return j;
}
Quick Sort class
public class Quick {
private static int partition(Comparable[] a, int lo, int hi) { ... }
public static void sort(Comparable[] a) {
StdRandom.shuffle(a);
sort(a, 0, a.length - 1);
}
private static void sort(Comparable[] a, int lo, int hi) {
if (hi <= lo) return;
int j = partition(a, lo, hi);
sort(a, lo, j-1); // a[j] is sentinel
sort(a, j+1, hi);
}
}
Selection: Find the kth smallest item in an array
public static Comparable select(Comparable[] a, int k) {
StdRandom.shuffle(a);
int lo = 0, hi = a.length - 1;
while (hi > lo) {
int j = partition(a, lo, hi);
if (j < k) lo = j + 1;
if (j > k) hi = j - 1;
else return a[k];
}
return a[k];
}
3-way Quicksort
The goal of 3-way partitioning is to speed up quicksort in the presence of duplicate keys.
- Quicksort with 3-way partitioning is entropy-optimal. (Proof: beyond scope)
- Bottom line: Randomized quicksort with 3-way partitioning reduces running time from linearithmic to linear in broad class of applications. Best case N, average NlgN, worst N^2/2
private static void sort(Comparable[] a, int lo, int hi) {
if (hi <= lo) return;
int lt = lo, gt = hi;
Comparable v = a[lo];
int i = lo;
while (i < gt) {
int cmp = a[i].compareTo(v);
if (cmp < 0) exch(a, lt++, i++);
else if (cmp > 0) exch(a, i, gt--);
else i++;
}
sort(a, lo, lt-1);
sort(a, gt+1, hi);
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HK697lrb-1585967019425)(…/…/.gitbook/assets/3-way.png)]
Also see source code in Quick3way.java
System Sorts
- Java
Arrays.sort()
uses tuned quicksort for primitive types; tuned mergesort for objects.
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pce0T5qx-1585967019427)(…/…/.gitbook/assets/sortsummary.png)]
Collinear Points (Exercise)
For each point, calculate the slop of this point and every other points, sort these points by slope order. The points with equal slopes are collinear points.
Heap Sort
Heap-ordered binary tree
- Keys in nodes
- Parent’s key no smaller than children’s key
Array representation
- Indices start at 1.
- Take nodes in level order
- No explicit links needed!
Use array indices to move through tree, parent node at k
is at k/2
, children of node at k
are at 2k
and 2k+1
.
Binary heap: Java implementation, also see in MaxPQ.java
public class MaxPQ<Key extends Comparable<Key>> {
private Key[] pq; // store items at indices 1 to n
private int N; // number of items on priority queue
public MaxPQ(int capacity) {
pq = (Key[]) new Comparable[capacity];
}
public boolean isEmpty() { return N == 0; }
public void insert(Key x) {
if (n == pq.length - 1) resize(2 * pq.length);
pq[++N] = x;
swim(N);
}
public Key delMax() {
Key max = pq[1];
exch(1, N--);
sink(1);
pq[N+1] = null; // prevent loitering
return max;
}
private void sink(int k) { // sink node k
while (2*k <= N) {
// left child of node k is 2*k, right child of node k is 2*k+1
int j = 2*k;
// if left child is less than right child, move to right child
if (j < n && less(j, j+1)) j++;
// if parent node is greater than the larger child, then break while
if (!less(k,j)) break;
// else, parent node is smaller than child j, exch them
exch(k, j);
// follow the node, go to the next level
k = j;
}
}
private void swim(int k) { // swim node k
// while parent node is smaller than node k, then swap these two items.
while (k > 1 && less(k/2, k)) {
exch(k, k/2);
k = k/2;
}
}
}
Heapsort: basic plan for in-place sort, see source code Heap.java
- Create max-heap with all N keys
- Repeatedly remove the maximum key
public class Heap {
public static void sort(Comparable[] a) {
int N = a.length;
// construct the heap order, from the last parent node to k = 1.
for (int k = N/2; k>=1; k--)
sink(a, k, N);
// exchange the max with the end of array, sink a[1], get rid of sorted part.
while (N > 1) {
exch(a, 1, N);
sink(a, 1, --N);
}
}
}
Significance. In-place sorting algorithm with NlogN
worst-case.
Bottom line: Heapsort is optimal for both time and space, but
- Inner loop longer than quick sort
- Makes poor use of cache memory, references to memory are all over the place when it is a huge array. So it is not a good alg for situation with caching. Does not have local memory address, but quick sort has.
- Not stable
Event-Driven Simulation (optional)
Predict the collision events, add these events to the priority queue (initialization), dequeue the event within minimum time, and then update the velocity of collision points, predict events correspond to the updated points, add the new predicted event to priority queue, repeat and simulate this process. see website Event-Driven Simulation
8-puzzle (Exercise)
Use A* search algorithm, the idea is: First, insert the initial search node (the initial board, 0 moves, and a null previous search node) into a priority queue. Then, delete from the priority queue the search node with the minimum priority, and insert onto the priority queue all neighboring search nodes (those that can be reached in one move from the dequeued search node). Repeat this procedure until the search node dequeued corresponds to the goal board.
Specification
Solution