目录
一、常见的排序算法分类
二、常见排序算法的实现
2.1插入排序
2.1.1基本思想
2.1.2直接插入排序
思路
step1.单趟控制
step2.总体控制
代码实现
测试
特性总结
2.1.3 希尔排序( 缩小增量排序 )
基本思想
思路演进
🌈1.代码实现单组排序(以红色组为例)
🌈2.加入控制多组排序的代码
🌈3.对上面代码修改 ,一组一组排 改为 多组并排!!!
🌈4.最后考虑,如何控制gap?
最终代码实现
测试
特性总结
三、结语
一、常见的排序算法分类
二、常见排序算法的实现
2.1插入排序
2.1.1基本思想
直接插入排序是一种简单的插入排序法,其基本思想是:
把待排序的记录按其关键码值的大小逐个插入到一个已经排好序的有序序列中,直到所有的记录插入完为 止,得到一个新的有序序列 。
2.1.2直接插入排序
思路
step1.单趟控制
先考虑单趟排序,暂时不考虑区间到底是从哪到哪 ,先抽象为[0,end]
假设[0,end]是有序的区间 a[end+1] 插入到 [0,end]中
❓具体如何插入:
下标是end+1的元素依次跟[0,end]区间中的元素作比较:
end+1先跟end比 再跟 end-1比较......依次往下
①如果a[end+1]<a[end] 以排升序为例子 ,那么a[end]就往后挪动 也就是往后覆盖
②如果a[end+1]>a[end] ,那么就停止比较 ,a[end+1] 插入到 [0,end]中
❓思路落实到代码:
用临时变量tmp 先保存a[end+1],最终插入的位置也是a[end+1]
step2.总体控制
接下来考虑如何控制[0,end]区间大小的变化:
❓执行过程描述:
初始时 区间元素个数肯定只有一个,
也就是end = 0 ,区间[0,0]有序,只有一个元素a[0],然后a[1]往里插入,
完成后,end = 1,区间[0,1]有序,有两个元素,a[2]往里插入...
直到整个数组元素都有序,排序完成。
❓思路落实到代码:
执行过程中,我们发现,end的值是不断变化的,所以加入外层循环变量i控制即可!
代码实现
void InsertSort(int* a, int n)
{
//外层循环 控制 多趟[0,end]
for (int i = 0; i < n-1; i++)
{
//单趟
//[0,end] end+1 插入 [0,end]
int end = i;
int tmp = a[end + 1];
while (end >= 0)
{
//升序
if (tmp < a[end])
{
//end 往后覆盖 end+1
a[end + 1] = a[end];
end--;
}
else
{
break;
}
}
a[end + 1] = tmp;
}
}
测试
特性总结
1. 元素集合越接近有序,直接插入排序算法的时间效率越高
2. 时间复杂度:O(N^2)
3. 空间复杂度:O(1),它是一种稳定的排序算法
4. 稳定性:稳定
2.1.3 希尔排序( 缩小增量排序 )
基本思想
希尔排序法又称缩小增量法。希尔排序法的基本思想是:
先选定一个整数gap,把待排序文件中所有记录分成多个组,所有距离为gap的记录分在同一组内,并对每一组内的记录进行排序。然后,再往后依次取 间隔为gap的记录,重复上述分组和排序的工作。当gap==1时,所有记录在统一组内排好序。
思路演进
总体思路:
1、预排序:分别对每个分组进行插入排序
2、直接插入排序 :保证最终结果是有序的
先选定一个整数 ,先假设 gap = 3. 图解
🌈1.代码实现单组排序(以红色组为例)
🌈2.加入控制多组排序的代码
总体有gap组 排完红色组 接着排 蓝色组、绿色组 则需要再加入一层循环控制
j==0 红色组 插入排序
j==1 蓝色组 插入排序
j==2 绿色组 插入排序
🌈3.对上面代码修改 ,一组一组排 改为 多组并排!!!
上面代码是 : 红色组排完 排绿色组 绿色排完 排蓝色组
下面代码是 : 红色组第一个位置排好,
i++ 排蓝色组第一个位置 ,
再 i++ 排绿色组第一个位置,
以此类推......
实现多组并排:
🌈4.最后考虑,如何控制gap?
gap越大:小的值更快调到前面,大的值更快调到后面
gap越小:调得越慢 但 越接近有序
gap==1 :就是直接插入排序
所以我们再加入一层循环 控制gap
最终代码实现
void ShellSort(int* a, int n)
{
int gap = n;
while (gap > 1)
{
gap = gap / 2 ;
for (int i = 0; i < n - gap; i ++)
{
//单趟
//[0,end] end+gap 插入 [0,end]
int end = i;
int tmp = a[end + gap];
while (end >= 0)
{
//升序
if (tmp < a[end])
{
//end 往后覆盖
a[end + gap] = a[end];
end -= gap;
}
else
{
break;
}
}
a[end + gap] = tmp;
}
}
}
测试
特性总结
1. 希尔排序是对直接插入排序的优化。
2. 当gap > 1时都是预排序,目的是让数组接近于有序。
当gap == 1时,数组已经是接近有序,再进行直接插入排序,目的是让数组有序。
这样整体而言,可以达到优化的效果。我们实现后可以进行性能测试的对比。
3. 希尔排序的时间复杂度不好计算,因为gap的取值方法很多,导致很难去计算,因此在好些树中给出的希尔排序的时间复杂度都不固定。平均时间复杂度O(N^1.3)
三、结语
插入排序就先讲到这里,后面滴选择、交换、归并排序,都会快快更新滴~