# 四. 走向世界之巅——快速排序

• 蒙特卡洛方法
• 单纯形法
• Krylov子空间迭代法
• 矩阵计算的分解方法
• 优化的Fortran编译器
• 计算矩阵特征值的QR算法
• 快速排序算法
• 快速傅立叶变换
• 整数关系探测算法
• 快速多极算法

## 4.2 算法和性能分析

``````private static int partition(Comparable[] a, int lo, int hi) {
int i = lo;
int j = hi + 1;
Comparable v = a[lo];
while (true) {
// find item on lo to swap
while (less(a[++i], v))
if (i == hi) break;

// find item on hi to swap
while (less(v, a[--j]))
if (j == lo) break;      // redundant since a[lo] acts as sentinel

// check if pointers cross
if (i >= j) break;

exch(a, i, j);
}

// put partitioning item v at a[j]
exch(a, lo, j);

// now, a[lo .. j-1] <= a[j] <= a[j+1 .. hi]
return j;
}

public static void sort(Comparable[] a) {
StdRandom.shuffle(a);
sort(a, 0, a.length - 1);
}

// quicksort the subarray from a[lo] to a[hi]
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);
sort(a, j+1, hi);
assert isSorted(a, lo, hi);
}
``````

## 4.4 对快速排序的研究和改进

``````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++;
}

// a[lo..lt-1] < v = a[lt..gt] < a[gt+1..hi].
sort(a, lo, lt-1);
sort(a, gt+1, hi);
assert isSorted(a, lo, hi);
}
``````

``````// multiKeySorter is a kind of Sortable used for sorting according to different keys
// One can write different lesser functions for a user-defined type and call
// By(*lesser*).Sort(*coll*) to sort the collection
type multiKeySorter struct {
coll   interface{}
lesser func(o1, o2 interface{}) bool
}
func (mks *multiKeySorter) Len() int {
if reflect.TypeOf(mks.coll).Kind() == reflect.Slice {
slice := reflect.ValueOf(mks.coll)
return slice.Len()
}
panic("passing a non-slice type")
}

func (mks *multiKeySorter) Swap(i, j int) {
if reflect.TypeOf(mks.coll).Kind() == reflect.Slice {
slice := reflect.ValueOf(mks.coll)
temp := reflect.ValueOf(slice.Index(i).Interface())
slice.Index(i).Set(reflect.ValueOf(slice.Index(j).Interface()))
slice.Index(j).Set(temp)
return
}
panic("passing a non-slice type")
}

func (mks *multiKeySorter) Less(i, j int) bool {
if reflect.TypeOf(mks.coll).Kind() == reflect.Slice {
slice := reflect.ValueOf(mks.coll)
return mks.lesser(slice.Index(i).Interface(), slice.Index(j).Interface())
}
panic("passing a non-slice type")
}

// By is a function type for multiple-key sorting
type By func(o1, o2 interface{}) bool

// Sort sorts the slice by lesser func passing in
func (by By) Sort(coll interface{}) {
mks := &multiKeySorter{
coll:   coll,
lesser: by,
}
sort.Sort(mks)
}

func TestMultiKeySorter(t *testing.T) {
fmt.Println("====== Multi Key Sorter ======")
planets := []Planet{
{"Mercury", 0.055, 0.4},
{"Venus", 0.815, 0.7},
{"Earth", 1.0, 1.0},
{"Mars", 0.107, 1.5},
}
name := func(o1, o2 interface{}) bool {
p1 := o1.(Planet)
p2 := o2.(Planet)
return strings.ToLower(p1.name) < strings.ToLower(p2.name)
}
distance := func(o1, o2 interface{}) bool {
p1 := o1.(Planet)
p2 := o2.(Planet)
return p1.dist < p2.dist
}
mass := func(o1, o2 interface{}) bool {
p1 := o1.(Planet)
p2 := o2.(Planet)
return p1.mass < p2.mass
}
sorter.By(name).Sort(planets)
fmt.Println("By name: ", planets)
sorter.By(distance).Sort(planets)
fmt.Println("By distance: ", planets)
sorter.By(mass).Sort(planets)
fmt.Println("By mass: ", planets)
}
``````

# 五. 为“排序”而生——优先级队列

## 5.3 叫我“二叉堆”！

### 5.3.1 “上浮”和“下沉”算法

``````private void swim(int k) {
while (k > 1 && less(k/2, k)) {
exch(k, k/2);
k = k/2;
}
}

private void sink(int k) {
while (2*k <= N) {
int j = 2*k;
if (j < N && less(j, j+1)) j++;
if (!less(k, j)) break;
exch(k, j);
k = j;
}
}
``````

``````public void insert(Key x) {
// double size of array if necessary
if (N >= pq.length - 1) resize(2 * pq.length);
// add x, and percolate it up to maintain heap invariant
pq[++N] = x;
swim(N);
assert isMaxHeap();
}

public Key delMax() {
if (isEmpty()) throw new NoSuchElementException("Priority queue underflow");
Key max = pq[1];
exch(1, N--);
sink(1);
pq[N+1] = null;     // to avoid loiterig and help with garbage collection
if ((N > 0) && (N == (pq.length - 1) / 4)) resize(pq.length / 2);
assert isMaxHeap();
return max;
}
``````

``````package cntr
import (
"fmt"
)

type PQueue struct {
keys    []interface{}
length  int
compare func(interface{}, interface{}) bool
}

func NewPQ(cmp func(interface{}, interface{}) bool) *PQueue {
// arr[0] not use
arr := make([]interface{}, 1)
arr[0] = 0
return &PQueue{
keys:    arr,
compare: cmp,
}
}

func (pq *PQueue) Insert(v interface{}) {
pq.keys = append(pq.keys, v)
pq.length++
pq.swim(pq.length)
}

func (pq *PQueue) swim(k int) {
for k > 1 && pq.compare(pq.keys[k/2], pq.keys[k]) {
pq.keys[k/2], pq.keys[k] = pq.keys[k], pq.keys[k/2]
k = k / 2
}
}

func (pq *PQueue) pq() interface{} {
if pq.Empty() {
panic(fmt.Sprintf("queue is empty"))
}
return pq.keys[1]
}

func (pq *PQueue) PrintOut() {
fmt.Println(pq.keys[1:])
}

func (pq *PQueue) Del() interface{} {
if pq.Empty() {
panic(fmt.Sprintf("Trying to delete an empty queue"))
}
ret := pq.keys[1]
pq.keys[1] = pq.keys[pq.length]
pq.keys = pq.keys[:pq.length]
pq.length--
pq.sink(1)
return ret
}

func (pq *PQueue) sink(k int) {
for 2*k <= pq.length {
j := 2 * k
if j < pq.length && pq.compare(pq.keys[j], pq.keys[j+1]) {
j++
}
if !pq.compare(pq.keys[k], pq.keys[j]) {
break
}
pq.keys[k], pq.keys[j] = pq.keys[j], pq.keys[k]
k = j
}
}

func (pq *PQueue) IsHeapified() bool {
k := 1
for 2*k <= pq.length {
j := 2 * k
if pq.compare(pq.keys[k], pq.keys[j]) || (j < pq.length && pq.compare(pq.keys[k], pq.keys[j+1])) {
return false
}
k++
}
return true
}

func (pq *PQueue) Empty() bool {
return pq.length == 0
}

func (pq *PQueue) Size() int {
return pq.length
}
``````

## 5.4 又一个神一样的存在——堆排序

``````func HeapSort(arr []int) {
N := len(arr)
for k := N / 2; k >= 1; k-- {
sink(arr, k, N)
}
for N > 1 {
excher(arr, 1, N)
N--
sink(arr, 1, N)
}
}

func sink(arr []int, k, N int) {
for 2*k <= N {
j := 2 * k
if j < N && lesser(arr, j, j+1) {
j++
}
if !lesser(arr, k, j) {
break
}
excher(arr, k, j)
k = j
}
}

func lesser(arr []int, i, j int) bool {
return arr[i-1] < arr[j-1]
}

func excher(arr []int, i, j int) {
arr[i-1], arr[j-1] = arr[j-1], arr[i-1]
}
``````

# 六. 排序算法的学以致用

## 6.2 学以致用之二：人工智能问题中的优先级队列

Search算法进行求解，首先我们定义一个三元组，它由棋盘当前状态board，走到此位置要用的移动数moves，以及之前的状态prev组成。起始状态为(board, 0, NULL)，其中board是人为输入的初始状态。我们将起始状态塞入最小优先级队列，每次都取出优先级最小的三元组，然后将它的“邻居们”（所有只移动一步就能达到的棋盘）插入优先级队列（要注意将与之前状态prev相同的情况排除掉），此过程一直持续到弹出的三元组为最终状态，此时我们将根据它以及它的prev指针重建整个步骤序列作为算法的解。有三个关键的问题要解决：1.优先级怎么定义；2.如何判别棋盘走到了最终态；3.如何判别初始状态是可解的；

``````public Solver(Board initial) {
solvable = false;
solutions = null;
M = -1;
MinPQ<SNode> nq = new MinPQ<SNode>();
MinPQ<SNode> tq = new MinPQ<SNode>();

nq.insert(new SNode(initial));
tq.insert(new SNode(initial.twin()));

while (!nq.isEmpty() && !tq.isEmpty()) {
SNode n = nq.delMin();
SNode t = tq.delMin();

// test if we have reached the goal
if (t.board.manhattan() == 0) break;

if (n.board.manhattan() == 0) {
// rebuild the solutions
solutions = new Stack<Board>();
solutions.push(n.board);
solvable = true;
M = n.moves;
SNode prev = n.previous;
while (prev != null) {
solutions.push(prev.board);
M += prev.moves;
prev = prev.previous;
}
break;
}
// putting neighbors into queues
for (Board nbr : n.board.neighbors())
if (n.previous == null || !n.previous.board.equals(nbr))
nq.insert(new SNode(nbr, n.moves + 1, n));

for (Board tbr : t.board.neighbors())
if (t.previous == null || !t.previous.board.equals(tbr))
tq.insert(new SNode(tbr, t.moves + 1, t));

}
}
``````

### 推荐阅读更多精彩内容

• 1 序 2016年6月25日夜，帝都，天下着大雨，拖着行李箱和同学在校门口照了最后一张合照，搬离寝室打车去了提前租...
StarryThrone阅读 3,936评论 0 12
• 概述 排序有内部排序和外部排序，内部排序是数据记录在内存中进行排序，而外部排序是因排序的数据很大，一次不能容纳全部...
蚁前阅读 4,339评论 0 52
• 概述：排序有内部排序和外部排序，内部排序是数据记录在内存中进行排序，而外部排序是因排序的数据很大，一次不能容纳全部...
每天刷两次牙阅读 3,020评论 0 16
• Ba la la la ~ 读者朋友们，你们好啊，又到了冷锋时间，话不多说，发车！ 1.冒泡排序（Bub...
冷锋_007阅读 1,309评论 0 6
• 1.插入排序—直接插入排序(Straight Insertion Sort) 基本思想: 将一个记录插入到已排序好...
依依玖玥阅读 520评论 0 2