一、直接插入排序
直接插入排序和希尔排序都为插入排序类,因此将其归类到一块。
插入排序是指:将数组当前元素插入到该元素之前的有序序列中,即
- 将数组从头到尾进行遍历,依次将元素插入到前面有序数组中相应的位置
- 而从头到尾开始遍历可以保证遍历到某个元素时前面的数组是有序的
具体步骤:
- 从头到尾遍历数组元素
- 然后从当前元素往前遍历有序数组,找到比该元素值还要小的元素数组索引
- 将该索引到当前元素索引之间的数组后移
- 最后将当前元素插入到有序数组中
具体的代码:
vector<int> InsertSort(vector<int>& arr) {
int tmp;
int i,j;
for(i = 1;i < arr.size();i++)
{
int k = i;
//找到前面有序数列的比arr[i]小的索引
for(j = i;j >= 0;j--)
{
if(arr[j] >= arr[i])
{
k = j;
}
else break;
}
if(i != k)
{
tmp = arr[i];
//将数组后移
for(j = i - 1;j >= k;j--)
arr[j+1] = arr[j];
arr[k] = tmp;
}
}
return arr;
}
复杂度分析:
- 当最好的情况,排序是有序的,不需要后移,时间复杂度为O(n)
- 最坏的情况,排序是逆序的,比较次数是(n+2)(n-1)/2,移动次数是(n+4)(n-1)/2
- 根据概率相同的原则,平均比较和移动次数约为n2/4,n2/2,即复杂度约为O(n2)
二、希尔排序
直接插入排序在基本有序的时候效率是很高的,只需要少量的插入操作就可以完成整个记录集的排序工作。而希尔排序就是利用了分治的思想,让整体元素更加有序,减少比较和后移的操作。可以说是直接插入排序的升级版本。
- 希尔排序的关键是利用分治的思想,通过增量将数组一部分组成一个子序列,实现跳跃式的移动,通过一步步将增量缩小,不断使得整体数组有序。
具体步骤:
- 选择增量increment = length/3 + 1
- 对间隔为increment的子数组进行直接插入排序
- increment = increment/3+1
- 重复循环,直至increment <= 1;
具体代码:
vector<int> MySort(vector<int>& arr) {
// write code here
int tmp;
int i,j;
int increment = arr.size();
do
{
increment = increment/3 + 1;
for(i = increment;i < arr.size();i = i + increment)
{
int k = i;
//找到前面有序数列的比arr[i]小的索引
for(j = i;j >= 0;j = j - increment)
{
if(arr[j] >= arr[i])
{
k = j;
}
else break;
}
if(i != k)
{
tmp = arr[i];
//将数组后移
for(j = i - increment;j >= k;j = j - increment)
arr[j + increment] = arr[j];
arr[k] = tmp;
}
}
}while(increment > 1);
return arr;
}
- 增量的取值可以任意,但最后一个增量必须等于1