直接插入排序
算法原理
- 从A[2]A[2]A[2]开始,到A[n]A[n]A[n],查找出A[i]A[i]A[i]在A[1…i−1]A[1…i-1]A[1…i−1]中的插入位置kkk
- 将A[k…i−1]A[k…i-1]A[k…i−1]中所有元素位置依次后移一个位置
- 将A[i]A[i]A[i]复制到A[k]A[k]A[k]
代码实现
void InsertSort(int 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)O(n)O(n)
- 最坏情况:逆序,比较次数达到最大,为∑i=2ni\sum^n_{i=2}i∑i=2ni,移动次数也达到最大,为∑i=2n(i+1)\sum^n_{i=2}(i+1)∑i=2n(i+1)
- 平均情况:时间复杂度为O(n2)O(n^2)O(n2)
- 稳定性:稳定
折半插入排序
算法原理
- 直接插入排序中,总是边比较边移动元素
- 折半插入排序在直接插入排序的基础上,确定待插入位置后,统一移动元素
代码实现
void InsertSort1(int A[], int n){
int i, j, high, low, mid;
for(i=2; i<=n; i++){
A[0] = A[i];
low = 1;
high = i-1;
while(low <= high){
mid = (high+low)/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];
}
}
举例

性能分析
- 时间复杂度:减少了比较元素的次数,约为O(nlog2n)O(n\log_2n)O(nlog2n),且次数与待排序表的初始状态无关。元素的移动次数并未改变,任然依赖于排序表的初始状态。时间复杂度为O(n2)O(n^2)O(n2)
- 稳定性:稳定
希尔排序
算法原理
- 取一个小于nnn的步长d1d_1d1,把表中全部记录分成d1d_1d1组,所有距离为d1d_1d1的倍数的记录放在同一组,各组内进行直接插入排序
- 取第二个步长d2<d1d_2<d_1d2<d1,重复上述步骤,直至所取到的dt=1d_t=1dt=1,即所有记录都在同一组中,再进行直接插入排序(已有较好的局部有序性)
代码实现
void ShellSort(int A[], int n){
int d, i, j;
for(d=n/2; d>=1; d=d/2)
for(i=d+1; i<=n; ++i)
if(A[i] < A[i-d]){
A[0] = A[i];
for(j=i-d; j>0&&A[0]<A[j]; j-=d)
A[j+d] = A[j];
A[j+d] = A[0];
}
}
举例

性能分析
- 空间复杂度:只使用了常数个辅助单元,空间复杂度为O(1)O(1)O(1)
- 时间复杂度:最坏情况下为O(n2)O(n^2)O(n2)
- 稳定性:不稳定