参考“浙江大学 数据结构 陈越等”MOOC课程,《数据结构与算法分析——C语言描述》
前提 void X_sort(ElementType A[],int N)
为了简单,只讨论:
从小到大的整数排序;
N是正整数;
基于比较的排序(>=<有定义);
内部排序(所有数据可一次性导入内存空间,所有排序在内存空间一次性完成);
稳定性(任意两个相等的数据,排序前后的相对位置不变)。
没有一种排序在任何情况下都表现最好。
1、冒泡排序
最好情况:顺序T=O(N),最坏情况:逆序T=O(N2)。
简单,用于数组和单向链表,稳定。
void Bubble_Sort(ElementType A[],int N){
for(P=N-1;P>=0;P--){
flag=0;
for(i=0;i<P;i++){ // 一趟冒泡
if(A[i]>A[i+1]){
Swap(A[i],A[i+1]);
flag=1; // 标识发生了交换
}
}
if(flag==0) break; // 全程无交换
}
}
2、插入排序
最好情况:顺序T=O(N),最坏情况:逆序T=O(N2)。T(N,I)=O(N+I),如果序列基本有序,则插入排序简单且高效。
简单,不用交换,用于数组和单向链表,稳定。
void Insertion_Sort(ElementType A[],int N){
for(P=1;P<N;P++){
Tmp=A[P]; // 摸下一张牌
for(i=P;i>0&&A[i-1]>Tmp;i--){
A[i]=A[i-1]; // 移出空位
}
A[i]=Tmp; // 新牌落位
}
}
对于下标i<j,如果A[i]>A[j],则称(i,j)是一对逆序对。交换2个相邻元素正好消去1个逆序对。任意N个不同元素组成的序列平均具有N(N-1)/4个逆序对。任何仅以交换相邻元素来排序的算法,其平均时间复杂度为Ω(N2)。
要提高算法效率,必须每次消去不止1个逆序对,通过交换相隔较远的2个元素。
3、希尔排序
定义增量序列DM>DM-1>...>D1>1,对每个Dk进行“Dk-间隔”排序。注意“Dk-间隔”有序的序列在执行“Dk-1-间隔”排序后,仍然是“Dk-间隔”有序的。
原始希尔排序DM=[N/2],Dk=[Dk+1/2],即每次Dk减半。最坏情况:T=Θ(N2),增量元素不互质,小增量可能根本不起作用。如8,4,2,每一趟均没有元素变动,最后做1间隔插入排序。
void Shell_Sort(ElementType A[],int N){
for(D=N/2;D>0;D/=2){ // 希尔增量序列
for(P=D;P<N;P++){ // 插入排序
Tmp=A[P];
for(i=P;i>=D&&A[i-D]>Tmp;i-=D){
A[i]=A[i-D];
}
A[i]=Tmp;
}
}
}
Hibbard增量序列,Dk=2k-1,相邻元素互质。最坏情况:T=Θ(N3/2)。猜想:Tavg=O(N5/4)。
Sedgewick增量序列{1,5,19,41,109,...}9*4i-9*2i+1或4i-3*2i+1。猜想:Tworst=O(N4/3),Tavg=O(N7/6)。元素数量是万数量级以上,效果较好。不稳定。
void Shell_Sort(ElementType A[],int N){
int Sedgewick[]={929,505,209,109,41,19,5,1,0}; // 只列出少部分增量
for(Si=0;Sedgewick[Si]>=N;Si++); // 初始的增量Sedgewick[Si]不能超过待排序列长度
for(D=Sedgewick[Si];D>0;D=Sedgewick[++Si]){
for(P=D;P<N;P++){ // 插入排序
Tmp=A[P];
for(i=P;i>=D&&A[i-D]>Tmp;i-=D){
A[i]=A[i-D];
}
A[i]=Tmp;
}
}
}
4、堆排序
选择排序。每次交换可能消掉很多逆序对,最多交换N-1次。
无论如何T=Θ(N2)。如何快速找到最小元?
void Selection_Sort(ElementType A[],int N){
for(i=0;i<N;i++){
// 从A[i]到A[N-1]中找到最小元,将最小元的位置赋给MinPosition
MinPosition=ScanForMin(A,i,N-1); // 包含for循环
// 将未排序部分的最小元换到有序部分的最后位置
Swap(A[i],A[MinPosition]);
}
}
算法1,T(N)=O(NlogN),需要额外O(N)空间,复制元素需要时间。
void Heap_Sort(ElementType A[],int N){
BuildHeap(A); // O(N),建立堆
for(i=0;i<N;i++) // O(NlogN),取出最小值存放至新数组
TmpA[i]=DeleteMin(A);
for(i=0;i<N;i++) // O(N),将新数组的数据保存至原数组
A[i]=TmpA[i];
}
5、归并排序