目录
插入排序
-
直接插入排序
-
折半插入排序
-
希尔排序
直接插入排序
-
算法理解
-
算法思想
-
每次将一个待排序的记录安其关键字大小插入到前面已排好序的子序列中,直到全部记录插入完成
-
算法图解
-
-
-
代码实现
void InsertSort (int A[], int n) { int temp=A[0]; for (int i=1; i<n; i++) { //将各元素插入已安排好的序列中 if (A[i]<A[i-1]) { //若A[i]关键字小于前驱 temp=A[i]; //用temp暂存A[i] for(int j=i-1; j>0 && A[j]>temp; j--) { //检查所有前面已排好序的元素 A[j+1]=A[j]; //所有大于temp的元素都向后挪位 } A[j+1]=temp; //复制到插入位置 } } }
-
性能分析
-
空间复杂度:O(1)
-
时间复杂度
-
最好情况:表中元素已经有序,此时每插入一个元素,都只序比较一次而不用移动元素。O(n)
-
最坏情况:表中元素顺序刚好与排序结果中的元素顺序相反(逆序),总的比较次数达到最大,总的移动次数也达到最大。O(n²)
-
平均时间复杂度:O(n²)
-
-
稳定性:由于每次插入元素时总是从后向前比较再移动,所以不会出现相同元素相对位置发生变化的情况。(稳定)
-
适用性:顺序存储和链式存储的线性表
-
折半插入排序
-
算法理解
-
算法思想:先用折半查找找到应该插入的位置,再统一移动带插入元素之后的所有元素,改进的是比较次数,移动次数并未改变。
-
算法图解
-
-
代码实现
void InsertSort (int A[], int n) { int low, high, mid; for (int i=2; i<=n; i++) { //依次将A[2]~A[n]插入前面的已排序序列 A[0]=A[i]; //将A[i]暂存到A[0](哨兵) 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 (int j=i-1; j>=high+1; j--) { //统一后移元素,空出插入位置 A[j+1]=A[j]; } A[high+1]=A[0]; //插入操作 } } } //当low>high时,折半查找停止,应将[low,i-1]内的元素全部右移,并将A[0]复制到low所指位置 //当A[mid]==A[0]时,为保证算法的“稳定性”,应继续在mid所指位置右边寻找插入位置
-
性能分析
-
比起“直接插入排序”,比较关键字的次数减少了,但是移动元素的次数没变,整体看来时间复杂度仍然是O(n²)
-
稳定性:稳定
-
适用性:只适用于顺序表
-