几种排序算法的讲解(二)
来源:互联网 发布:壮语翻译软件 编辑:程序博客网 时间:2024/06/11 06:53
四、希尔排序
希尔排序其实是直接插入排序算法的一种变形,实质是分组插入排序。又称缩小增量排序。
该方法首先要理解分组操作,其实是以间隔分组,即每间隔几个数后就分做一组,然后进行插入排序。接着把间隔缩短一半,以此下去,直到间隔没有,才停下操作。
如:有10个数据,开始的时候每间隔10/2 = 5 划为一组,即第1个数与第6个数为一组,第2个数与第7个数为一组。。。。。。以此类推,然后对每一组的数进行插入排序。排序好后缩短间隔,5/2 = 2,即每间隔2个数就划为一组,以此操作直到间隔为0,无法缩小间隔为止。
如,对10、49、23、1、5、50、44、8、23、2、6这10个数据进行希尔排序。
第一次分组的时候: inter = 10/2 = 5
第一次分组如图,分成了5组,{A1,B1},{A2,B2},{A3,B3},{A4,B4},{A5,B5}这五个组,接着对每一组进行直接插入排序。(没间隔几个数,就分成几组)
第二次分组的时候: inter = 5/2 = 2
现在分成了2组,同上,对每组进行直接插入排序
第三次分组的时候: inter = 2/2 = 1
现在只有一组了,仍然进行插入排序
第四次无法分组了: inter = 1/2 = 0
希尔排序实现的代码如下:
#include <bits/stdc++.h>using namespace std;const int maxn = 10000;int a[maxn];int main(){ int n; while(cin>>n) { for(int i=1; i<=n; i++) cin>>a[i]; //开始不断地缩短间隔,直到间隔为0。第一次间隔为n/2 for(int inter = n/2; inter>0; inter/=2) { //每一次缩短间隔,其间隔数等于所分的组数,排序的时候从第1组到第inter组进行插入排序。 for(int gap=1; gap<=inter; gap++) { //下面是插入排序的代码,稍微改变了一下递增递减量,因为是每次间隔inter进行排序。 //大致的插入排序代码并没有改变 for(int i=gap+inter; i<=n; i+=inter) { int cur; for(cur=i-inter; cur>=1; cur-=inter) { if(a[cur]<a[i])break; } if(cur!=i-inter) { for(int k=i-inter; k>cur; k-=inter) swap(a[k+inter], a[k]); } } } } for(int i=1; i<=n; i++) cout<<a[i]<<" "; cout<<endl; } return 0;}
为了让代码尽可能地贴近所描述的语言,上面的代码写得过于复杂,看得有些头疼,我们可以把该代码缩减为以下代码:
#include <bits/stdc++.h>using namespace std;const int maxn = 10000;int a[maxn];int main(){ int n; while(cin>>n) { for(int i=1; i<=n; i++) cin>>a[i]; //缩短间隔,分组。 for(int inter=n/2; inter>0; inter/=2) { //从第inter个数开始,这个与普通的直接插入排序从第二个数开始的意味相同 for(int i=inter; i<=n; i++) { //每个数与自己组里的数进行直接插入排序 for(int cur=i-inter; cur>=1 && a[cur]>a[cur+inter]; cur-=inter) swap(a[cur], a[cur+inter]); } } for(int i=1; i<=n; i++) cout<<a[i]<<" "; cout<<endl; } return 0;}
代码精简,不过不易懂,再次也不多讲解这一个代码,读者自己思考一番吧。
五、堆排序
堆排序算法在处理大数据的效率是前面四种算法不可比的。
那么要学堆排序,首先要对树有个了解,准确地说是对二叉树要又了解。堆排序就是一个特殊的完全二叉树。
我们用数组存储一堆数据,然后要把数组当做一个二叉树来看。二叉树特点是,一个父节点连接两个儿子节点。开始的时候把一堆数存入数组里,然后把数组看成二叉树,即存数到数组里后就建立好了一个二叉树,此时的树里面的值都是混乱的。
如何去排序一棵二叉树?以排序一个最小堆为例。
一棵树的“某一个节点”父子间的值所在的位置不对的时候,即两个儿子中有值小于父亲的值时,要排序父子关系的话,也会影响后面子孙的位置。
我们首先要对这种牵连一人而祸害一窝的行为用一种方式进行处理(即用一个函数),然后遍历每一个节点,用这种行为处理方式处理每一个节点。
下面说说怎么建立这种处理方式函数。
要找一种规律,就像数学思维一样,任意取一个值设为变量x,绕着x这个值进行某些变化直到某条件成立为止。
这里就任意取一个树的节点作为“变量节点 ”,从这个节点开始进行排序,首先找出该节点和该节点的两个儿子之间的最小的,让最小的与节点的值换一换。
如果没有换值,那么停止,证明了该节点与他的儿子顺序是正确的;如果换值了,那么接下来取与节点交换的儿子作为“变量节点”,继续以上操作,直到要么是到了最后的叶处即到底了,要么是儿子与父亲的值没有交换为止。可见这里是一个递归操作。
好的,找到了处理一个节点关系的方式(函数),那么我们现在要遍历每个节点,用这个方式处理每一个节点,以达到排序一个数组的目的。
那么,如何遍历才是好呢?我们找到的处理方式是用来处理有儿子的节点,是吧。那么从只有儿子没有孙子的节点开始处理。
这样从底部打好基础,节省了很多的麻烦。
根据树的定义,有N个节点,那么儿子是叶的节点是从第n/2个节点开始的,前面的节点都有子孙了。那就是从第n/2个节点开始遍历到根节点。
说来说去,有点绕,结合下面的代码有助于消化堆排序。
#include <bits/stdc++.h>using namespace std;const int maxn = 100000;int a[maxn];//这个就是一个牵一发而动全身的处理方式,一个递归函数//参数即当前的节点的位置,还有树的节点数void softdown(int cur, int n){ //flag是为了判断该节点的关系是否正常,如果儿子的值与父亲的值没有交换过,则flag = 1; //temp 为了记录最小值的位置 int flag = 0, temp; while(cur*2<=n && flag==0) { //首先判断左儿子与父亲的值 if(a[cur]>a[cur*2]) temp = cur*2; else temp = cur; //判断是否有右儿子存在 if(cur*2+1 <= n) { if(a[temp]>a[cur*2+1]) temp = cur*2+1; } //如果发现最小值的位置不在父节点处,那么交换节点值,继续下一个节点进行处理 //否则递归停止 if(cur != temp) swap(a[cur], a[temp]); else flag = 1; cur = temp; }}void create(int n) //排序二叉树{ for(int i=n/2; i>=1; i--) softdown(i, n);}//因为根节点的值是最小的,所以每次输出根节点的值//然后把最后一位与根节点值交换,顺便让长度-1.再排序一次树。//这样就成了数组里存的值是从大到小排序,但输出的时候是从小到大。void Cout(int n) //输出函数{ while(n) { cout<<a[1]<<" "; swap(a[1], a[n]); n--; softdown(1, n); }}int main(){ int n; while(cin>>n) { for(int i=1; i<=n; i++) cin>>a[i]; create(n); Cout(n); cout<<endl; //直接输出数组里的数进行比较一番 for(int i=1; i<=n; i++) cout<<a[i]<<" "; cout<<endl; } return 0;}
- 几种排序算法的讲解(二)
- 几种排序算法的讲解(一)
- 排序算法讲解(二)
- 几种常见的排序算法及实现(二)
- 几种常用的排序算法(二)--python实现
- C++ 几种常用排序算法讲解
- 常见的几种排序算法二-希尔排序
- 总结几种排序算法(二)---选择排序
- (二)几种排序算法的学习总结(归并排序)
- 几种常见的排序算法及其复杂度——快速排序(二)
- 几种常见的排序(二)
- 几种排序算法及其代码实现(二)
- 几大内部排序算法(二)
- 几种磁盘调度算法的讲解
- 排序的几种算法
- 几种排序的算法
- 交换排序的几种排序算法
- 几种排序算法(冒泡排序算法,选择排序算法,快速排序算法,插入排序)
- Android 剪切板
- ionic配置页面间跳转的URL
- hdu3709 Balanced Number
- 使用Nexus搭建Maven本地仓库
- idea 2017注册码
- 几种排序算法的讲解(二)
- day23(File递归练习)
- 关于typedef的用法总结
- Oracle PL/SQL开发基础(第三十一弹:自定义异常)
- [DP动态规划]导弹拦截
- 日志管理
- Hdu6085 Rikka with Candies(2017多校第5场)
- 列出与'SCOTT'从事相同工作的所有员工及部门名称、部门人数、平均工资
- this之后的call,apply,bind。