直接插入排序
基本思想:将序列分为有序区和无序区,再经过比较和后移操作将无序区元素插入到有序区中。
//C语言直接插入排序
#include <stdio.h>
//升序排列
void insertionSort(int *A,int n) {
for (int i = 1; i < n; i++) {
int key = A[i];
int j = i - 1;
//线性查找A[i]应插入的正确位置
while (j >= 0 && A[j] > key) {
//比key大的都后移一位,给key腾空
A[j + 1] = A[j];
j--;
}
A[j + 1] = key;
}
}
main(){
//测试
int A[6] = { 4,1,3,2,6,5 };
insertionSort(A, 6);
for(int i = 0; i < 6; i++)
printf("%d ",A[i]);
}
此时考虑对直接插入排序进行优化,原本在有序区查找元素的插入位置时使用的是线性查找法,可以采用二分查找法减少元素比较的次数。
优化:二分查找插入排序
伪代码:
//二分查找,返回A[i]需要插入的位置
BINARY-SEARCH(A,key,low,high)
while low<=high
mid=(low+high)/2
if key<A[mid]
high=mid-1
else
low=mid+1
return low
//插入排序
BINARY-INSERTION-SORT(A)
for i=2 to A.length
key=A[i]
loc=BINARY-SEARCH(A,key,1,i)
for j=i-1 to loc
A[j+1]=A[j]
A[loc]=key
C语言实现:
#include <stdio.h>
//二分查找过程,查找key应插入的位置
int binarySearch(int* A, int key, int low, int high) {
int mid = -1;
//循环直到low>high,此时low即为要插入的位置
while (low <= high) {
mid = (low + high) / 2;
if (key <= A[mid])
high = mid - 1;
else
low = mid + 1;
}
return low;
}
//使用二分查找改进插入排序,使之最坏情况下时间复杂度为Θ(nlgn)
void binInsertionSort(int* A, int n) {
//在子序列A[0..i]中查找A[i]应插入的位置
for (int i = 1; i < n; i++) {
int key = A[i];
//loc为二分查找获取的A[i]应插入的正确位置
int loc = binarySearch(A, key, 0, i);
//如果A[i]的位置需要改变
if (loc != i) {
//loc到i-1位置的元素都往后移动一个位置,把loc位置腾出来
for (int j = i - 1; j >= loc; j--) {
A[j + 1] = A[j];
}
//把A[i]放到正确的位置
A[loc] = key;
}
}
}
main(){
//测试
int A[9] = { 3, 5, 1, 2, 7, 12, 4, 17, 9 };
binInsertionSort(A, 9);
for(int i = 0; i < 9; i++)
printf("%d ",A[i]);
//输出:1 2 3 4 5 7 9 12 17
}
- 最好情况(序列为有序)下,无需进行后移操作,排序的时间复杂度为O(lgn)
- 最坏情况(序列为逆序)下,需要对1 + 2 + 3 + … + (n - 1) = n(n - 1)/2个元素后移,需要的赋值操作次数为n(n - 1)/2 + (n - 1),排序的时间复杂度为O(n2)
- 平均时间复杂度为O(n2)