**先贴上经典总结图
**
一、插入排序(直接法+折半优化)
原理:类比扑克牌理牌原理,将未排序序列中的元素一个个插入到已排序序列的正确位置上。
直接法:在有序序列中一个个比较,寻找正确位置
折半优化就是:运用二分法找到正确的插入位置
注意:插入排序一般会设置0号位置为哨兵位,不但可以临时保存元素,越界时还可以直接返回。所以数组是从1开始
void InsertSort(vector<int>& a,int n) {//直接插入排序
int i, j;
for (i = 2;i <= n;i++) {//0是哨兵项,从第二个元素起开始遍历插入
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];//插入到正确的位置,上一个移走后,j--了,所以这里是j+1
}
}
}
void BlnsertSort(vector<int>& a,int n) {//折半插入排序
int i, j;
for (i = 2;i <= n;i++) {
a[0] = a[i];//将当前元素存储到哨兵位置
int low = 1, high = i - 1;
while (low <= high) {//二分法查找插入位置
int mid = (low + high) / 2;
if (a[0] > a[mid]) low = mid + 1;
else high = mid - 1;
}//循环结束,high+1为插入位置
for (j = i - 1;j >= high+1;j--) {//移动元素,挪出位置
a[j+1] = a[j];
}
a[high+1] = a[0];
}
}
二、希尔排序
原理:易知插入排序在数列有序度较高的情况下时间复杂度较低(可降至O(n)),基于此,希尔排序的思想是:先将待排序序列分割为若干个子序列,分别进行直接插入排序,待整个数列基本有序,再对全体序列进行一次直接插入排序。
子序列的分割用到了增量序列,增量序列是一组递减并且互质的数,并且最后一个数一定是1,对于t趟的希尔排序,增量序列可以是dlta[k]=2^(t-k+1)-1。值得一提的是,目前希尔排序的最优增量序列仍是数学界尚未解决的难题。
按照dlta[k]进行t趟排序,每一趟对于数列中所有相隔距离为dlta[k]的元素进行排序
void ShellInsert(vector<int>& a, int dk,int n) {
//间隔dk,作一趟插入排序,相较于直接插入排序做了以下修改:
//1.前后记录位置的增量是dk,而不是1
//2.r[0]只是暂存单元,不是哨兵,当j<=0时,插入位置已找到
int i, j;
for (i = dk + 1;i <= n;i++) {//相距dk,所以从dk+1开始,
//寻找元素插入到前面的一个元素中
if (a[i] < a[i-dk]) {
a[0] = a[i];
for (j = i - dk;j > 0 && (a[j] > a[0]);j -= dk) {
a[j+dk] = a[j];
}
a[j+dk] = a[0];
}
}
}
void ShellSort(vector<int>& a, int dlta[], int t,int n) {//n为数组元素个数,0号作为哨兵,数组空间为n+1
//按增量序列dlta[0…t-1]对顺序表L作希尔排序
for (int k = 0;k < t;k++) {
ShellInsert(a, dlta[k], n);
}
}