排序
排序算法的稳定性:经过排序后,能使关键字相同的元素保持原顺序中的相对位置不变
基于比较的排序次数至少为
⌈
l
o
g
2
(
n
!
)
⌉
\lceil log_2(n!)\rceil
⌈log2(n!)⌉
插入排序
void InsertSort(ElemType A[],int n){
int i,j;
for(i=2;i<=n;i++){
if(A[i]<A[i-1]){
A[0]=A[i];
for(j=i-1;A[0]<A[j];j--){
A[j+1]=A[j];
}
A[j+1]=A[0];
}
}
}
空间复杂度
O
(
1
)
O(1)
O(1),时间复杂度
O
(
n
2
)
O(n^2)
O(n2)
是一个稳定的排序方法
折半插入排序(二分法)
void InsertSort(ElemType A[],int n){
int i,j,low,high,mid;
for(i=2;i<=n;i++){
A[0]=A[i];
low=1;
high=i-1;
while(low<=high){
mid=(low+high)/2;
if(A[mid]>A[0]) high=mid-1;
else low=mid+1;
}
for(j=i-1;j>=high+1;j--)
A[j+1]=A[j];
A[high+1]=A[0];
}
}
减少了比较次数,但是对实际的整体复杂度无影响
希尔排序
将待排序表分割成若干形如 L [ i , i + d , i + 2 d , . . . , i + k d ] L[i,i+d,i+2d,...,i+kd] L[i,i+d,i+2d,...,i+kd]的“特殊”子表,对每个子表分别进行直接插入排序。
void ShellSort(ElemType A[],int n){
int dk,i,j;
for(dk=n/2;dk>=1;dk=dk/2){
for(i=dk+1;i<=n;i++){
if(A[i]<A[i-dk]){
A[0]=A[i];
for(j=i-dk;j>0&&A[0]<A[j];j-=dk)
A[j+dk]=A[j];
A[j+dk]=A[0];
}
}
}
}
当n在某个特定范围时,希尔排序时间复杂度为
O
(
n
1.3
)
O(n^{1.3})
O(n1.3),在最坏情况下希尔排序的时间复杂度为
O
(
n
2
)
O(n^2)
O(n2)
希尔排序是一种不稳定的排序方法,适用于线性表为顺序存储的情况。
冒泡排序
void BubbleSort(ElemType A[],int n){
for(int i=0;i<n-1;i++){
bool flag=false;
for(int j=n-1;j>i;j--){
if(A[j-1]>A[j]){
swap(A[j-1],A[j]);
flag=true;
}
}
if(!flag) return;
}
}
仅用了常数个辅助单元,因此空间复杂度为
O
(
1
)
O(1)
O(1)
比较次数:
Σ
i
=
1
n
−
1
(
n
−
i
)
=
n
(
n
−
1
)
2
\Sigma_{i=1}^{n-1}(n-i)=\frac{n(n-1)}{2}
Σi=1n−1(n−i)=2n(n−1),移动次数
Σ
i
=
1
n
−
1
3
(
n
−
i
)
=
3
n
(
n
−
1
)
2
\Sigma_{i=1}^{n-1}3(n-i)=\frac{3n(n-1)}{2}
Σi=1n−13(n−i)=23n(n−1)
最坏情况时间复杂度
O
(
n
2
)
O(n^2)
O(n2),平均时间复杂度
O
(
n
2
)
O(n^2)
O(n2)
是一种稳定的排序方法。
简单选择排序
void SelectSort(ElemType A[],int n){
for(int i=0;i<n-1;i++){
int min=1;
for(int j=i+1;j<n;j++)
if(A[j]<A[min]) min=j;
if(min!=i) swap(A[i],A[min]);
}
}
时间复杂度 O ( n 2 ) O(n^2) O(n2)