希尔排序原理和算法图解

news/2025/2/13 0:02:43/

原理:

这个是基于插入排序的改进。将待排序的记录数目减少,所以,我们需要采用跳跃分割策略:将相距某个分量的记录组成一个子序列分别进行插入排序得到的结果是基本有序。

算法讲解:

	void ShellSort(SqList *L) {int i,j;int increment = L->length;do {increment = increment / 3 + 1; // 增量序列for( i = increment + 1; i<=L->length;i++) {if (L->r[i]<L->r[i-increment]) {// 需要将L->r[i]插入有序增量子表L->r[0] = L->r[i];for(j = i - increment;j>0&&L->r[0]<L->r[j];j-=increment)L->r[j+increment] = L->r[j]; // 记录后移,查找插入位置L->r[j+increment] = L->r[0];}}} while (increment>1);}

1.程序开始,此时假设我们传入的SqList 参数值为 length = 9,r[10] = {0,9,1,5,8,3,7,4,6,2}.请看图

2.第四行,变量increment,初始值让它等于待排序的记录,9。

3.第5-19行是一个do循环,它终止条件是 increment 不大于 1 时。其实也是增量为1就停止循环。

4.第 7 行,这一句很关键,但也是难以理解的地方,我们后面还要谈到它1,先放一放。这里执行后,increment = 9 / 3 + 1 = 4。

5.第 8-17 行是一个 for 循环,i 从 4 + 1 = 5 开始到 9 结束。

6.第 10 行,判断 L.r[i]  与 L.[i-increment]大小,L.r[5] = 3小于L.r[i-increment] = r[1] = 9,第 12 行,将L.r[5] = 3 赞存入L.r[0]。第 13-14 行的循环只是为了将L.r[1] = 9的值赋值给L.r[5],由于循环的增量是 j -= increment,其实它就循环一次,此时 j = -3. 第 15 行,再将 L.r[0] = 3 赋值给 L.r[j+increment] = L.r[1] = 3.如图,事实上,这一段代码就干了一件事,就是将第 5 位的 3 和 第 1 位的 9 交换了位置。

 7.循环继续,i = 6,L.r[6] = 7 > L.r[i - increment] = L.r[2] = 1,因此不交换两组数据。如图

8.循环继续,i = 7,L.r[7] =  4 < L.r[i-increment] = L.r[3] = 5,交换两者数据。如图

 9.循环继续, i = 8,L.r[8] = 6 < L.r[i-increment] = L.r[4] = 8,交换两者数据。如图。

 

 10.循环继续,i = 9,L.r[9] = 2 < L.r[i-increment] = L.r[5] = 9,两者交换数据。注意,第 13 和 14 行是循环,此时还要继续比较 L.r[5] 与 L.r[1] 的大小,因为 2 < 3,交换位置。

 

 最终第一轮循环后,数组的结果如下图所示。我们的数字1,2等小数字基本已经在前两位,而8,9等大数字都基本在最后,也就是说,通过这样的排序,我们的整个序列基本有序。这就是希尔排序的精华所在,不是一步一步移动,而是跳跃式的前移,从而使没次完成一轮循环后,整个序列就朝着有序坚实地迈进一步。

 11.我们继续,在完成一轮do循环后,此时由于increment = 4 > 1因此我们需要继续 do 循环。第 7 行 increment = 4 / 3 + 1 = 2。第 8 - 17 行 for 循环,i 从 2 + 1= 3 开始到 9 结束。当i = 3,4时,不用交换,当 i = 5 时,需要交换。

12. 此后, i = 6,7,8,9均不用交换。

13.再完成一轮do循环,increment = 2,继续do循环,第七行得到 increment = 1,最后一次循环了。尽管 8-17 行 for 循环,i 从 2 到 9结束,但由于当前的序列更接近有序,可交换的数据更少了。最终完成排序。

 复杂度分析:

这里“增量”的选取就非常关键了。我们用 increment = increment  / 3 + 1;的方式选取增量,可究竟应该选取什么样的增量才是最好,目前还是一个数学难题,迄今还没有人找到一种最好的增量序列。不过大量研究表明,当增量序列为 \delta k = 2^{t-k+1} - 1 (0 \leq k \leq \left \lfloor log_{2}(n + 1) \right \rfloor  时,可以获得不错的效率,其时间复杂度为 O(n^{3/2}) 要好于直接排序 O(n^2).需要注意的是,增量序列最后一个增量值必须等于 1 才行。另外,由于记录是跳跃式的移动,希尔排序并不是一个稳定的排序算法。


http://www.ppmy.cn/news/824858.html

相关文章

希尔排序详解

一.思路 希尔排序是建立在插入排序的思想之上的&#xff0c;因为插入排序在应对数组接近有序的情况下&#xff0c;时间复杂度接近O(N)&#xff0c;故如果对数组先进行预排序&#xff0c;使数组接近有序&#xff0c;再进行直接插入排序&#xff0c;能大幅度降低时间复杂度 二.实…

排序算法——希尔排序

希尔排序 什么是希尔排序为什么不直接使用插入排序希尔排序代码实现 什么是希尔排序 希尔排序也叫做&#xff1a;缩小增量排序。 分组&#xff08;分组的组数需要循环递减&#xff0c;直到减为1&#xff09;排序。 先将待排序序列分成若干组&#xff0c;然后使用直接插入排序在…

入坑机器学习:四,单变量线性回归

开始我们机器学习的第一个算法。 还是借用吴老师的例子&#xff1a; 这个例子是预测住房价格的&#xff0c;我们要使用一个数据集&#xff0c;数据集包含俄勒冈州波特兰市的住房价格。在这里&#xff0c;我要根据不同房屋尺寸所售出的价格&#xff0c;画出我的数据集。比方说&…

C语言数据结构希尔排序(示例代码)

#include <stdio.h> #include <stdbool.h> #define MAX 7 int intArray[MAX] {4,6,3,2,1,9,7}; void printline(int count) { int i; for(i 0;i < count-1;i) { printf(“”); } printf(“\n”); } void display() { int i; printf(“[”); // navigat…

C#排序算法之希尔排序

前言 希尔排序是插入排序的优化&#xff0c;它利用了分治的思想&#xff0c;将需要排序的数组分为几段&#xff0c;在每一段中做插入排序。通过分治的思想&#xff0c;使得排序效率比起原来的插入排序要快了很多。对于插入排序&#xff0c;不了解的可以查看我之前的文章&#…

关于vue2项目搭建的步骤

vue2项目每次搭建项目总是需要注意各种插件的版本&#xff0c;在这里记录一下&#xff0c;免得总是需要看半天需要安装哪个版本。 1.创建项目 vue create 项目名称 2.安装路由插件及配置 npm i vue-router3 &#xff08;1&#xff09;router/index.jsimport VueRouter fro…

插入排序与希尔排序

插入排序 将一元素插入到已排序完毕的数组中 可以将无序数组的第一个元素看作 只有一个元素的有序数组 后将数组中的元素一一插入到有序数组中的合适位置 所有元素被插入到有序数组中时&#xff0c;便已将此数组置为有序 动图演示 代码逻辑如下&#xff1a; 以升序为例 …

希尔排序(升序)

希尔排序就是按照不同间隔&#xff0c;对序列进行排序&#xff0c;直到间隔步长为1时&#xff0c;排序后&#xff0c;该序列即为升序序列。 一般步长选取序列长度除以2的k次幂&#xff0c;在不同步长下&#xff0c;将序列各组进行插入排序。大大的减少了插入排序的时间复杂度。…