简单排序的定义(浙大mooc学习笔记)
文章目录
常用命名格式:
void X_sort(ELementType A[],int N)
大多数情况下,为简单起见,讨论 从小到大排序
默认条件:
1.N是正整数
2.只讨论基于比较的排序(> = < 有定义)
3.只讨论内部排序
4.稳定性:任意两个相等的数据,排序前后的相对位置不发生改变
重要的一点:没有任何一种排序是任何情况下都表现最好的
冒泡排序
图例:

原始的冒泡排序:
void Bublle_Sort(ElemenType 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]);
}
}
}
}
存在的问题:如果在排序途中,序列已经是有序的了,此时排序还是会运行进行比较
冒泡排序的改进:
void Bublle_Sort(ElemenType 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)
T=O(N)
最坏情况: 逆序(全部逆序)
T
=
(
(
n
)
+
(
n
−
1
)
+
⋯
+
(
2
)
+
(
1
)
)
=
n
∗
(
n
−
1
)
2
=
O
(
N
2
)
T = \left((n)+(n-1)+\cdots+(2)+(1)\right) = \frac{n*(n-1)}{2} =O(N^2)
T=((n)+(n−1)+⋯+(2)+(1))=2n∗(n−1)=O(N2)
思考
如果元素使用链表存储,该怎么写冒泡排序?
冒泡排序是否稳定?
稳定
插入排序
插入排序可以理解为打扑克牌时的理牌方法。
代码描述
伪码描述如下:
void Insertion_Sort(ElementType A[],int N)
{
for(p = 1; p < N; p++){/*从1开始而不是从0开始,因为手牌只有一张的时不需要排序*/
Tmp = A[p];/*摸下一张牌*/
for(i = p; i > 0 && A[i-1] > Tmp; i--)/*与手里的牌一一对比*/
A[i] = A[i-1];/*移出空位,把原来的牌往后移*/
A[i] = Tmp;/*新牌落位*/
}
}
复杂度
最好情况:顺序(不需要错位,例如:3、4、5、6、7)
T
=
O
(
N
)
T=O(N)
T=O(N)
最坏情况:逆序(每摸一张牌,把原来的牌往后错一位)
T
=
1
+
2
+
⋯
+
n
=
O
(
n
2
)
T=1+2+\cdots+n=O(n^2)
T=1+2+⋯+n=O(n2)
与冒泡排序的比较
冒泡排序是两两元素互换,交换过程有3步。
插入排序是每个元素向后移位,最后一次性将元素插入。
插入排序是否稳定?
稳定
例题
1.给定初始序列
{
34
,
8
,
64
,
51
,
32
,
21
}
\{34,8,64,51,32,21\}
{34,8,64,51,32,21},冒泡排序和插入排序分别需要多少次元素交换才能完成?
解:冒泡排序9次,插入排序9次
2.对一组包含10个元素的非递减有序序列,采用插入排序排成非递增序列,其可能的比较次数和移动次数分别是
A. 45, 44
B. 54, 63
C. 100, 54
D. 100, 100
答案:A
解析:他问的是可能的比较次数和移动次数分别是多少,那我们就假设原理就是全部递增的,插入排序后要求全部递减,这样的比较次数应该是最多的。
时间复杂度下限
逆序对
对于下标i<j,如果a[i]>a[j],则称**(i,j)**是一对 逆序对。(也就是不符合递增的数对)
例题: { 34 , 8 , 64 , 51 , 32 , 21 } \{34,8,64,51,32,21\} {34,8,64,51,32,21}中有多少逆序对?
解答:(34,8),(34,32),(34,21),(64,51),(64,32),(64,21),(51,32),(51,21),(32,21)
可以看到,有9个逆序对。在前面我们知道,对于这个序列,冒泡排序和插入排序都需要交换9次元素。
可以得出:
插入排序:
T
(
N
,
I
)
=
O
(
N
+
I
)
,
其
中
N
为
序
列
中
元
素
个
数
,
I
为
序
列
中
逆
序
对
个
数
T(N,I)=O(N+I),其中N为序列中元素个数,I为序列中逆序对个数
T(N,I)=O(N+I),其中N为序列中元素个数,I为序列中逆序对个数
可以知道,如果一个序列基本有序,那么插入排序运行起来会很快。
两个定理
-
任意 N N N个不同元素组成的序列平均具有 N ( N − 1 ) 4 N(N-1)\over4 4N(N−1) 个逆序对
-
任意仅以交换相邻两元素来排序的算法,其平均时间复杂度为 Ω ( N 2 ) \Omega(N^2) Ω(N2)
这意味着,如果要提高算法效率我们必须:
- 每次消去不止一个逆序对
- 每次交换相隔较远的两个元素。