目录
- 一、插入排序
- 二、希尔排序
一、插入排序
思路:
插入排序就像玩扑克牌,抽出一张牌作为比较的元素,与前面的牌依次进行比较,小于继续往前比较,大于等于停下插入到当前位置。
图示:
void InsertSort(int* a, int n)
{
//控制所有次排序
for (int i = 0; i < n - 1; i++)
{
int end = i;//记录临时下标
int tmp = a[end + 1];//比较的元素
//一趟排序
while (end >= 0)
{
if (a[end] > tmp)//非升序
{
a[end + 1] = a[end];//前面的覆盖后面的
}
else
{
break;//是升序跳出本次循环
}
--end;//下标往前移动
}
a[end + 1] = tmp;//指向元素的下一个元素覆盖为tmp
}
}
注意:总共的排序次数是n-1趟,即end最多只能到倒数第二个元素,因为如果end为最后一个元素,那么end+1的位置就是越界的。
特性总结:
- 数组的元素越接近有序,该排序的效率越高
- 时间复杂度:O(N^2)
- 空间复杂度:O(1)
- 稳定
二、希尔排序
希尔排序与插入排序很像,单趟排序的思路基本相似,不同的是,插入排序的每次对比一个指向的元素是向前移动一个距离,希尔排序是移动gap个距离,从大到小,最后为1
void ShellSort(int* a, int n)
{
int gap = n;//先定义好初始距离
while (gap > 1)//限定条件
{
gap = gap / 3 + 1;//距离缩小
//类似插入排序,只是把1改成gap
for (int i = 0; i < n - gap; i++)
{
int end = i;
int tmp = a[end + gap];
while (end >= 0)
{
if (a[end] > tmp)
{
a[end + gap] = a[end];
}
else
{
break;
}
end -= gap;
}
a[end + gap] = tmp;
}
}
}
注意:while循环的条件gap大于1并不是说gap不能为1,而是这里在前面的进入循环的时候就有可能为1了,记住gap是先缩小再使用的,进入循环时(还没有缩小)的gap是上次使用的gap
假如gap此时为2:,满足条件,进入while循环,2除3等于0,0加1等于1,下面使用的gap就是1
再进行循环的判断,如果条件不是大于1的话,而是大于等于1,那么gap为1可以进入循环,然后1除1等于1,1+1等于2,就死循环了。
特性总结:
- 希尔排序是对直接插入排序的优化
- 希尔排序的时间复杂度不好计算,因为gap的取值方式很多,时间复杂度暂时为:O(N ^1.3)——O(N ^2)
- 空间复杂度:O(1)
- 不稳定