1.常用各种排序(限于比较排序)
(1) Insertion:平均时间 O(n^2);最坏时间 O(n^2);空间 O(1);稳定
每次将一个待排的记录插入到前面的已经排好的队列中的适当位置。
$ Insertion-Sort(A)
for j=2 to length[A] do
key <- A[j]
i <- j-1
while i>0 && A[i]>key do
A[i+1] <- A[i]
i--
A[i+1] <- key
(2) Merge:平均时间 O(nlgn);最坏时间 O(nlgn);空间 O(n);稳定
$ Merge(A,p,q,r)
for i=1 to q-p+1 do L[i] <- A[p+i-1]
for j=1 to r-q do R[j] <- A[q+j]
L[q-p+2] <- R[r-q+1] <- infty
i <- j <- 1
for k=p to r do
L[i]<=R[j]?A[k]<-L[i++]:A[k]<-R[j++]
$ Merge-Sort(A,p,r)
if p<r then
q <- (p+r)/2
Merge-Sort(A,p,q)
Merge-Sort(A,q+1,r)
Merge(A,p,q,r)
(3)Heap:平均时间 O(nlgn);最坏时间 O(nlgn);空间 O(1);不稳定
$ Max-Heapify(A,i)
if Left[i]<=heap-size[A] && A[Left[i]]>A[i]
then largest <- Left[i]
else largest <- i
if Right[i]<=heap-size[A] && A[Right[i]]>A[largest]
then largest <- Right[i]
if largest 不等于 i then
exchange A[i] <-> A[largest]
Max-Heapify(A,largest)
$ Build-Max-Heap(A)
heap-size[A] <- length[A]
for i=length[A]/2 to 1
Max-Heapify(A,i)
$ Heap-Sort(A)
Build-Max-Heap(A)
for i=length[A] to 2
exchange A[1] <-> A[i]
heap-size[A]--
Max-Heapify(A,1)
衍生的优先级队列算法,下面只介绍最大优先级队列
Insert(S,x):把元素x插入集合S.这一操作可写为S<—SU{x}
$ Heap-Max-Insert(A,key)
heap-size[A] <- heap-size[A]+1
A[heap-size[A]] <- -infinity
Heap-Increase-Key(A,heap-size[A],key)
Maximum(S):返回S中具有最大关键字的元素
$ Heap-Maximum(A)
return A[1]
Extract-Max(S):去掉并返回S中的具有最大关键字的元素
$ Heap-Extract-Max(A)
if heap-size[A]<1 then
error "heap underflow"
max <- A[1]
A[1] <- A[heap-size[A]]
heap-size[A] <- heap-size[A]-1
Max-Heapify(A,1)
return max
Increase-Key(S,x,k):将元素x的关键字的值增加到k,这里k值不能小于x的原关键字的值
$ Heap-Increase-Key(A,i,key)
if key<A[i] then error
A[i] <- key
while i>1 && A[Parent(i)]<A[i] do
exchange A[i] <-> A[Parent(i)]
i <- Parent(i)
(4)Quick:平均时间 O(nlgn);最坏时间 O(n^2);空间 O(lgn);不稳定
通过一趟排序将待排的记录分割成独立的两部分,其中一部分记录的关键字均比另一个部分的关键字小,然后再分别对这两个部分记录继续进行排序,以达到整个序列有效。
快排有随机版本,也就是说在partition的时候是随机选取分点值的,这样的话平均效果会好一点,但操作相对复杂而且没有质的飞跃。
clrs的Ex7.2-2表明它对排序对象有多个相同值时候的效果是比较差的,有一种快排的三路变体可以解决这中边界数据。
$ Partition(A,p,r)
x <- A[r]
i <- p-1
for j=p to r-1 do
if A[j]<=x then
i++
exchange A[i] <-> A[j]
exchange A[i+1] <-> A[r]
return i+1
$ Quick-Sort(A,p,r)
if p<r then
q <- Partition(A,p,r)
Quick-Sort(A,p,q-1)
Quick-Sort(A,q+1,r)
快排的三路变体
PARTITION(A,p,r,int& q1, int& q2) //用指针或者引用返回两个参数
1 x = A[r]
2 i = p-1
3 for j = p to r - 1
4 if A[j] <= x
5 i = i + 1
6 exchange A[i] with A[j]
7 exchange A[i + 1] with A[r]
8 k= i+1
9 for j = p to i
10 if A[j] = x
11 k = k - 1
12 exchange A[j] with A[k]
13 q1 = k,q2=i+1
2.总结
n比较小的时候,适合插入排序和选择排序
基本有序的时候,适合直接插入排序和冒泡排序
n很大但是关键字的位数较少时,适合 链式基数排序
n很大的时候,适合 快速排序堆排序归并排序
无序的时候,适合 快速排序