开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 29 天,点击查看活动详情
希尔排序 | shellSort
思想
希尔排序法,也称为缩小增量排序,是插入排序算法的改进版本。我们知道,插入排序法可以高速处理顺序较整齐的数据,而希尔排序法就是充分发挥这一特点
具体的,希尔排序算法记录如下:
- 把记录按下标的一定增量
g
进行分组,并对每组使用插入排序算法进行排序; - 随着增量
g
逐渐减少,每组包含的数值会越来越多 - 当增量
g
减到 1 时,全部数据将被分为一组。此时再进行一次插入排序即可。
理解
这里的增量以及分组该如何理解?往下看:
- 假设现在我们需要通过希尔排序法将数组
nums
中的元素按升序的形式排列。 nums = [2, 7, 9, 4, 5, 6, 3, 1]
- 通常的,我们会将增量
g
初始化为数组nums
长度的一半,即g = nums.size() / 2
- 因此,这里的
g
等于 4。 - 接着,我们根据增量 4 对数组进行分组(也就是将相隔距离为 4 的元素分为一组)。
- 因此在数组
[2, 7, 9, 4, 5, 6, 3, 1]
中,2 和 5分为一组,7 和 6 分为一组,9 和 3 分为一组,4 和 1 分为一组。 - 对每一组分别进行插入排序,那么数组更新为:
[2, 6, 3, 1, 5, 7, 9, 4]
(比如 9 和 3 是一组,所以交换二者的位置) - 当我们对每个组分别进行插入排序后,就可以来更新增量
g
了 - 一般更新增量
g
的方式为g /= 2;
,因此此时的g
为 2。 - 此时,我们根据增量 2 对数组进行分组。
- 因此在数组
[2, 6, 3, 1, 5, 7, 9, 4]
中,2, 3, 5, 9
分为一组,6, 1, 7, 4
分为一组 - 对每一组分别进行插入排序,那么数组更新为:
[2, 1, 3, 4, 5, 6, 9, 7]
- 现在的任务就是更新增量
g
,即g /= 2;
,所以g
更新为 1。 - 将相隔距离为 1 的元素组成一组(其实就只有一组了)
- 用插入排序对该组进行排序,此时,排序已经结束了。
代码
void shellSort(int A[], int size) {
int g, pos, j; // g 为希尔增量,pos为待插入记录位置
int tmp;
for (g = size/2; g > 0; g /= 2){
for (pos = g; pos < size; pos++) {
tmp = A[pos];
for (j = pos - g; j >= 0 && A[j] > tmp; j -= g)
A[j+g] = A[j]; // 记录后移
A[j+g] = tmp; // 将待插入记录放到合适位置
}
}
}
分析
要想完成数据排序就必须在最后指向 g = 1
,使用插入排序法。(此时对象数据的顺序应该已经很整齐了)
另外,增量 g
的选择方法数不胜数,迄今为止人们已经对其进行了许多研究。这里记录另一个增量取值方式:当 时,算法的复杂度基本维持在