1. 冒泡排序 Bubble_Sort
假定有一组序列:12 32 9 89 12 21
需要将其排成非递减的序列, 执行一趟排序的操作是:
从头到尾扫描一遍, 发现第i个元素比第i-1个元素大, 则交换两个元素。执行一趟之后,最大的元素必将排到最后。
剩下的N-1个元素,重复执行排序。
算法1.1 原始冒泡排序
void Bubble_Sort( ElementType A[], int N )
{
for ( p=N-1; P>=0; P-- )
{
for ( i=0; i<P; i++ ) /* 一趟排序 */
{
if ( A[i] > A[i+1] )
{
Swap(A[i], A[i+1]);
}
}
}
}
算法1.2 改良的冒泡排序
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; /*全程无交换, 不需要继续排序*/
}
}
最好情况:T = O(N)
最坏情况:T = O(N^2)
优势:(1)简单 (2)对数组和链表都容易操作
2. 插入排序 Insertion_Sort
假设要将一个序列排序成非递减的顺序
算法2.1 直接插入排序
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; /*元素落位*/
}
}
最好情况: T = O(N) 即上届是N级别, O表示上届, Ω表示下届, Θ表示即是上届又是下届
最坏情况: T = O(N^2)
定理2.1:任意N个不同元素组成的序列平均具有N(N-1)/4个逆序对
冒泡排序与插入排序的相同点:
(1) 只对相邻的两个元素交换操作
(2) 一趟排序只能消除一个逆序对
(3) 平均时间复杂度与逆序对的个数有关, 平均时间复杂度Ω(N^2),即下届就是N平方级别的
定理2.2:任何以交换相邻两个元素来排序的算法,其平均时间复杂度为Ω(N^2)
这就意味着,要提高算法效率,必须做到:
(1) 每次消去不止1个逆序对
(2) 每次交换像个较远的2个元素
3. 希尔排序 Shell_Sort
基本思路:利用插入排序的简单,克服插入排序每次只交换相邻元素的缺点.
步骤:
(1) 定义增量序列 Dm > Dm-1 > ... > D1=1
(2) 对每个Dk进行 Dk-间隔 排序(k = m, m-1, ..., 1)
规律: Dk-间隔 有序的序列, 在执行 Dk-间隔 排序后, 任然是 Dk-间隔 有序的
算法3.1 原始希尔排序
增量 Dm = ∟N/2」, Dk = ∟Dk-1/2」,即每次取N/2作为增量
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;
}
}
}
最坏情况: T = Θ(N^2)
问题在于: 增量序列不互质, 所以要提高效率就在于增量的取值
更多的增量序列
(1) Hibbard增量序列
-> Dk = 2^k - 1 保证相邻元素互质
-> 最坏情况: T = Θ(N^3/2)
-> 猜想的平均复杂度: T = O(N^5/4)
(2) Sedgewick增量序列
-> {1, 5, 19, 41, 109, ...}
计算公式 9X4^i - 9X2^i + 1 或者 4^i - 3X2^i + 1
-> 猜想: 平均 T = O(N^7/6), 最坏 T = O(N^4/3)
4. 选择排序
基本思路:从i到N-1的序列中找到最小的元素,然后与第i个元素交换
算法4.1 简单选择排序
void Selection_Sort( ElementType A[], int N )
{
/*从A[i]到A[N-1]中找到最小元素的下标并返回*/
MinPosition = ScanForMin( A, i, N-1 );
/*将未排序部分的最小元素换到有序部分的最后位置*/
Swap( A[i], A[MinPosition] );
}
简单选择排序的时间复杂度 T = Θ(N^2), 关键在于 ScanForMin 函数实现.
如何找到最小元素: 最小堆! --> 堆排序