插入排序
基本思想:每次将一个待排序的值插入到前面已经排好序适当位置上,直到所有值全部插完为止。即边插边排序,保证子序列中随时都是排好序的。
1. 直接插入排序
-
基本思想
整个排序过程为n-1趟插入,即先将序列中第1个记录看成是一个有序子序列,然后从第2个记录开始,逐个进行插入,直至整个序列有序。 -
例子
(13,6,3,31,9,27,5,11)【13】, 6, 3, 31, 9, 27, 5, 11
【6, 13】, 3, 31, 9, 27, 5, 11
【3, 6, 13】, 31, 9, 27, 5, 11
【3, 6, 13,31】, 9, 27, 5, 11
【3, 6, 9, 13,31】, 27, 5, 11
【3, 6, 9, 13,27, 31】, 5, 11
【3, 5, 6, 9, 13,27, 31】, 11
【3, 5, 6, 9, 11,13,27, 31】 -
代码实现
void direInsert(vector<int> &list) { int n=list.size(); int j; for (int i = 1; i < n; i++) { int temp = list[i]; for (j=i;j>0&&temp<list[j-1];j--) { list[j] = list[j-1];//后移 } list[j] = temp; } }
-
算法分析
时间复杂度为 o(n^2)
空间复杂度为 o(1)
2. 折半插入排序
-
基本思想
在插入排序的基础上,用折半查找的方式进行比较插入。 -
例子
写代码时根据下面的图去理解比较好,因为在脑子构造图像很容易混乱。
-
代码实现
void halfInsert(vector<int> &list) { int n=list.size(); int j; for (int i = 1; i < n; i++) { int low = 0, high = i - 1; int temp = list[i]; while (low <= high) { int m = (low + high) / 2; if (list[m]>temp ) high = m - 1; else low = m + 1; } for (j = i-1; j >high; j--) { list[j] = list[j-1]; } list[high+1] = temp; } }
-
算法分析
折半查找比顺序查找快,所以折半插入排序就平均性能来说比直接插入排序要快
时间复杂度为 o(n^2)
空间复杂度为 o(1)
3. 希尔排序 -
基本思想
先将整个待排记录序列分割成若干子序列,分别进行直接插入排序,待整个序列中的记录“基本有序”时,再对全体记录进行一次直接插入排序。 -
例子
将相隔某个增量dk的值组成一个子序列进行排序,让增量dk逐趟缩短直到dk=1为止。增量由自己设置,本题设置依次为5,3,1,最后一个值必须为1。
-
代码实现
void shell(vector<int> &list,vector<int> &d)
{//向量d用于存放增量,如5,3,1
int i, j, k;
for (k = 0; k < d.size();k++)//增量
{
int dk = d[k];
for (i = dk; i < lsit.size(); i++)
{
if (list[i] < list[i - dk])
{
int temp = list[i];
for (j = i - dk; j >= 0 && temp < list[j]; j =j- dk)
{
list[j + dk] = list[j];
}
list[j+dk] = temp;
}
}
}
}
- 算法分析
时间复杂度为o(n^1.25)
~o(1.6n^1.25)
空间复杂度为 o(1)