算法结构2.希尔排序
希尔是一个人的名字,因为他在论文中首次提到了这样的排序方式,这是希尔排序的来源
希尔排序,比插入排序有更加的优化,
有很多的文章中说希尔排序中也用到了插入排序,这样的说法只是为了方便理解,其实是不正确的
希尔排序中并没有用到插入排序
对吧,那么我们希尔排序:
希尔排序的思想:对于一个数组,如何来提高排序的效率,排序过程过程有两个步骤:1,比较大小 2.交换位置
只要减少比较的次数和数组之间交换的次数,那么就可以实现效率的提高
比较次数最多的 是任意的两个数字之间都进行比较,比如 a,b,c 这三个数据进行排序,最多的次数比较如下:[a,b],[b,c],[a,c] 那么次数为 排列组合 3!/2!=3次 按照这样的比较方法:
数组中包含4个元素 4!/2!=12
数组中包含5个元素5!/2!=60
随着元素的增加,那么比较的次数是非常的大的
上节说的是插入排序 O(n^2) (算法结构1.插入排序_datouniao1的博客-CSDN博客) 相对于上面的任意元素比较 减少了不少比较次数
那么希尔排序,如何在减少比较的次数,希尔排序中引入了步长的概念 ,比如:
[a,b,c,d,e,f,g,h,i,j,k.....]
在一开始的时候a 不和b 比较了,a 直接和g 比较,比如说a 是一个很大的数字和b 比较了大于b那么我和b进行交换位置,发现还大于c 那么又要和c交换位置,发现还大于d......一点点的往后挪动,这个过程自然增加了比较的次数和交换 次数
那么a和g比较,b 就和 h比较,.....从a 到g 这个中间的长度,称为步长,步长选择多少比较合适
合适的步长能够减少交换和比较的次数,
首位利用程序写出希尔排序算法的人,她采用的步长是 gap=length/2,后来很多人就感觉这个比较合适
那么我在此处也用c语言采用 gap=length/2作为步长,在之后每次步长 变化gap=gap/2
我们来看:
int xepx2(int arrs [],int size){int gap=size/2;int count=0;int compare=0;do { for(int k=0;k<=size;k++){ for (int j = k + gap; j <size; j += gap) {compare++;if(arrs[k] > arrs[j]){count++;int temp = arrs[k];arrs[k] = arrs[j];arrs[j] = temp; }} } gap=gap/2;}while(gap>0);printf("一共转移了多少次元素%d,比较了%d \n",count,compare);}int xepx3(int arrs [],int size){int gap=size/2;int count=0;int compare=0;do { for(int k=0;k<size/2;k++){ for (int j = k; j+gap<size; j += gap) {compare++;if(arrs[j] > arrs[j+gap]){count++;int temp = arrs[j];arrs[j] = arrs[j+gap];arrs[j+gap] = temp; }} } gap=gap/2;}while(gap>0);printf("一共转移了多少次元素%d,比较了%d \n",count,compare);}int main(){int arrs [] ={13,19,20,2,1,6,5,9,12,7,8,3,10,11,11};printf("原始数据:");for(int i=0;i<sizeof(arrs)/4;i++){printf("%d,",arrs[i]);}printf("\n");xepx2(arrs,sizeof(arrs)/4);printf("希尔之后:");for(int i=0;i<sizeof(arrs)/4;i++){printf("%d,",arrs[i]);}
}
希尔排序的结果如下:
原始数据:13,19,20,2,1,6,5,9,12,7,8,3,10,11,11,
一共转移了多少次元素26次,比较了144次
希尔之后:1,2,3,5,6,7,8,9,10,11,11,12,13,19,20,
在这个地方我看看希尔排序和插入排序都是的区别在于希尔排序在第二个for循环里 j 每次变化的是gap步长的长度,并且在最外层增加了一个步长的循环
为了展示出希尔排序比插入排序更加的优越,我们来看一下插入排序的数据,相同数组:
int shellsort(int arrs [],int size){int compare=0;int count=0;for(int i=0;i<size;i++){for(int j=0;j<size;j++){compare++;if(arrs[i] < arrs[j]){count++;int temp = arrs[i];arrs[i] = arrs[j];arrs[j] = temp; }}}printf("一共转移了多少次元素%d,比较了%d \n",count,compare);
}int main(){int arrs [] ={13,19,20,2,1,6,5,9,12,7,8,3,10,11,11};int length=sizeof(arrs)/sizeof(int); printf("排序之前:");for(int i=0;i<length;i++){printf("%d,",arrs[i]); }printf("\n");shellsort(arrs,length); printf("排序之后:");for(int i=0;i<length;i++){ printf("%d,",arrs[i]); }printf("\n"); return 0;
}
插入排序结果:
排序之前:13,19,20,2,1,6,5,9,12,7,8,3,10,11,11,
一共转移了多少次元素55,比较了225
排序之后:1,2,3,5,6,7,8,9,10,11,11,12,13,19,20,
从比较的次数和交换的次数来说,希尔排序整整比插入排序少了一半
上面我们对数组进行排序,步长采用的是length/2 并且依次的减半
其实我们还可以不采用这样的步长,对希尔排序进行优化,如何优化,通过采用合适的步长来进行优化,我们可以采用步长依次为{5,3,2,1}
为什么用{5,3,2,1},通过这样的步长设置,可以挪动最小的,比较最少
优化之后的希尔排序:
int xepx(int arrs [],int size){int gaps[]={5,3,2,1};int count=0;int compare=0;for(int j=0;j<4;j++){int gap=gaps[j];for(int i=0;i<gap;i++){ int l=i;do{compare++;if(arrs[l]>arrs[l+gap]){count++;int temp=arrs[l];arrs[l]=arrs[l+gap];arrs[l+gap]=temp;}l=l+gap;}while(l+gap<size); } }printf("一共转移了多少次元素%d,比较了%d \n",count,compare);
}int main(){int arrs [] ={13,19,20,2,1,6,5,9,12,7,8,3,10,11,11};printf("原始数据:");for(int i=0;i<sizeof(arrs)/4;i++){printf("%d,",arrs[i]);}printf("\n");xepx(arrs,sizeof(arrs)/4);printf("希尔之后:");for(int i=0;i<sizeof(arrs)/4;i++){printf("%d,",arrs[i]);}
}
原始数据:13,19,20,2,1,6,5,9,12,7,8,3,10,11,11,
一共转移了多少次元素24,比较了49
希尔之后:1,2,3,5,6,8,7,9,10,11,11,12,13,19,20,
我们可以看到的是优化之后的希尔排序仅仅交换了24次,比较了49 次,完成了整个排序,这个比gap=length/2 转移26 次比较144次可以说优化了很多
我们来看一下这个排序的古城:
1.对步长进行遍历
2.根据步长找到找到一组数,对这一组数进行冒泡排序(下一节内容)
冒泡排序:它重复地走访过要排序的元素列,依次比较两个相邻的元素,如果顺序(如从大到小、首字母从Z到A)错误就把他们交换过来。走访元素的工作是重复地进行直到没有相邻元素需要交换,也就是说该元素列已经排序完成。
这里的冒泡排序中相邻的元素 每次是增加1 ,在这个优化的算法中相邻的元素看作是 每次增加步长的元素
优化之后的算法可以看作是希尔算法和冒泡排序的优化,所以在有的文章中认为希尔排序是按照步长分割之后的数组,然后运用插入排序进行排序是没有真正的理解希尔排序,希尔并没有说获取到的新数组里面插入排序,也可以利用冒泡排序对新的数组进行排序
上面是对希尔排序方法的介绍,我们也可以将希尔排序算法看作是步长排序算法
希望对你有所帮助
算法结构2.希尔排序相关推荐
- js排序算法详解-希尔排序
全栈工程师开发手册 (作者:栾鹏) js系列教程5-数据结构和算法全解 js排序算法详解-希尔排序 希尔排序,直接上图: 像这个算法看图理解起来并不是很难,就像比赛一样,1-6一组,2-7一组,每差5 ...
- python算法与数据结构-希尔排序算法(35)
阅读目录 一.希尔排序的介绍 二.希尔排序的原理 三.希尔排序的图解 四.希尔排序的python代码实现 五.希尔排序的C语言实现 六.希尔排序的时间复杂度 七.希尔排序的稳定性 一.希尔排序的介绍 ...
- 算法系列【希尔排序】篇
常见的内部排序算法有:插入排序.希尔排序.选择排序.冒泡排序.归并排序.快速排序.堆排序.基数排序等.用一张图概括: 关于时间复杂度: 1. 平方阶 (O(n2)) 排序各类简单排序:直接插入 ...
- 希尔排序是一种稳定的排序算法_全面解析十大排序算法之四:希尔排序
点击上方蓝字关注我们吧 1. 十种排序算法的复杂度和稳定性 时间复杂度:一个算法消耗所需要的时间 空间复杂度:运行一个算法所需要的内存时间 稳定性:如一个排列数组:1.4.5.6.4.7. 此时有一对 ...
- 算法系列之五 希尔排序
对于前面讲过的基础排序来说,他们在实际使用的时候,价值并不是太大.它的价值在于,体现了一种很好的思想.通过一些改进和变化,可以达到一个不错的性能.希尔排序就是典型的一个例子,它改进了插入排序,使得算法 ...
- python算法与数据结构-希尔排序算法
希尔排序(shell sort)是插入排序的一种,也称缩小增量排序,与普通的插入算法的区别就是gap步长. 希尔排序内层循环逻辑如下所示: 上面的可以分为4组,一个一个的按照插入算法来做,第一组有54 ...
- Hark的数据结构与算法练习之希尔排序
算法说明 希尔排序是插入排序的优化版. 插入排序的最坏时间复杂度是O(n2),但如果要排序的数组是一个几乎有序的数列,那么会降低有效的减低时间复杂度. 希尔排序的目的就是通过一个increment(增 ...
- 白话经典算法系列之——希尔排序的实现
希尔排序的实质就是分组插入排序,该方法又称缩小增量排序,因DL.Shell于1959年提出而得名. 该方法的基本思想是:先将整个待排元素序列分割成若干个子序列(由相隔某个"增量"的 ...
- 【数据结构----笔记5】插入排序算法之【希尔排序算法】
/*__________________________________________________________________________________________________ ...
最新文章
- LINQ 学习路程 -- 查询操作 GroupBy ToLookUp
- x9此计算机上没有hasp_mastercam x9安装步骤
- C# 调用 taskkill命令结束服务进程
- python栈是什么意思_Python数据结构——栈
- linux 7 没有权限访问,技术|RHCSA 系列(十三): 在 RHEL 7 中使用 SELinux 进行强制访问控制...
- C++成员函数中的const修饰符
- xfce4设置屏保/锁屏时间
- mac 无法启动linux系统安装,苹果官方技术文档显示新款Mac Mini不能安装Linux系统...
- html引vue怎么实现国际化,Vue项目中Vue-i18n和element-ui国际化开发实现过程_唇印_前端开发者...
- 配合Opencv2.4.9,CMake3.12.1和VS2010在win10下构建项目踩坑记录
- Moses Staff攻陷以色列网络并加密数据,拒绝谈判
- Django笔记 —— 模型高级进阶
- 报错:Avoid adding reactive properties to a Vue instance or its root $data at runtime - declare it upfr
- 基于Matlab的语音识别
- oracle字段类型number默认值,Oracle 字段类型 | 学步园
- 关于阿里云短信验证服务完整的教程
- QtDesigner配置
- 北京周边骑行路线总结
- java碰撞检测代码_java 实现精确碰撞检测。
- Cocoa-专业术语