前言
准备开始写一个算法系列,记录一下自己学习的过程,参考前人的总结的基础上分享一下自己的理解。欢迎大家私下交换意见。
插入排序的特点保持排序过的集合是有序的,下一个需要排序的元素作为一个节点插入已经有序的集合中。
直接插入排序
图解:
5 | 2 | 1 | 4 | 8 | 7 | 3 | 6 |
第一步:2 插入,认为左边的{5}是一个有序集合。
2 | 5 | 1 | 4 | 8 | 7 | 3 | 6 |
第二步:1 插入,认为左边的{2,5}是一个有序集合。
1 | 2 | 5 | 4 | 8 | 7 | 3 | 6 |
第三步:4 插入,认为左边的{1,2,5}是一个有序集合。
1 | 2 | 4 | 5 | 8 | 7 | 3 | 6 |
......
由此可见,每次新元素要插入到有序集合中,符合要求的只需要比较,不符合要求的需要移动(避免移动选用链表,但是需要考虑空间问题;如果不想用副本,原来的数据要选用离链表避免移动,需要记录下次插入节点地址)
最坏的情况,每排序一个新元素需要比较有序集合的所有元素,时间复杂度:1+2+3+...+(n-1) = n(n-1)/2 时间复杂度是按最高指数幂 O(n^2)。
随着算法的优化,在查找插入位置的时候可以采用“二分法”;分组排序,最后再全排序。
希尔排序
希尔排序又称“缩小增量排序”通过取模余数为零的分为一组,然后组内排序;通过增量不断缩小至1完成全排序。
由此可见“增量”的取值至关重要,倍数、公因子都是需要考虑的因素,当然最后增量一定是“1”,需要全排序。
图解:
一次增量排序:
一、确定增量:3
12 | 8 | 2 | 7 | 4 | 5 | 3 | 6 |
a | b | c | a | b | c | a | b |
二、A组直接排序:
3 | 8 | 2 | 7 | 4 | 5 | 12 | 6 |
a | b | c | a | b | c | a | b |
三、B组直接排序:
3 | 4 | 2 | 7 | 6 | 5 | 12 | 8 |
a | b | c | a | b | c | a | b |
四、C组直接排序:
3 | 4 | 2 | 7 | 6 | 5 | 12 | 8 |
a | b | c | a | b | c | a | b |
对应的字母的元素为一组,组内做直接排序;然后 增量2 做一次增量排序;最后 增量1 做一次全排序。
希尔排序相当于多次增量递减的直接插入排序,增量初始值、递减幅度由具体数据集的散列特点决定。