排序算法之堆排序

一、什么是堆

  如果一个完全二叉树的每个节点,都不大于它的子节点,就可以称之为堆。所谓完全二叉树,就是除了叶子节点以外,所有的其他节点,都有完整的左字树和右子树,除了最后一层的非叶子节点以外。

                                                   

二、堆排序算法的大体脉络

        1、对无序的数据先建一个堆,

        2、输出堆顶元素,

        3、然后以最后一个元素代替堆顶元素,

        4、进行调整,使之仍然为一个堆。

        5、重复步骤2,3,4,直到堆中只剩下一个元素。

三、堆排序算法的详细过程

       1、填充

  首先,将这些无序的数字,填充成一个完全二叉树,但这时一般是不能够满足堆的要求的。没有关系,我们后面来进行调整。先来看看填充的过程。实际上,填充的顺序就是按照树的层次遍历的顺序,即从上到下,从左到右,一层一层往下放。就这样放完一层,放二层,放完二层,放三层,直到所有的数都放完为止。

                                                

  2、建堆

  填充完毕后,开始建堆的过程。显然,所有的叶子节点,都满足建堆的要求,因为它没有字节点。我们可以从最后一个非叶子节点开始。如图1所示,这里就是7,它满足堆的要求,再向前看5,这个节点不满足要求,右字树比它要小,需要把它和右子树互换一下,互换后如图2所示。再向前看2,它需要和做孩子互换,互换后,如图3所示。再向前看,现在到10,和之前的情况有些不同,10比之前的两个孩子都大,那到底该和哪一个孩子交换呢?稍微考虑一下,我们应该和最小的那个孩子交换,不然的话,我们交换完以后,仍然不能满足堆的要求。换过后,如图4所示。注意,10 换下来以后,破坏了原来满足要求的字树,所以还应该再调整,10和5应该互换,互换后,如图5所示。最后是6和1换,换后如图6所示。注意,6换下来以后,破坏了原来满足要求的字树,所以还应该再调整,6和2应该互换,互换后,如图7所示。至此,一个堆就建好了。这个堆满足的性质是,所以的父节点的值都不大于它的叶子节点的值。

             图1                                                                      图2                                                                                 图3

 

            图4                                                                         图5                                                                                   图6 

                 图7

   3、筛选并输出堆顶元素

  从初始的这个堆中,输出堆顶的这个元素。如图8所示,先输出1,然后根节点就空了。接着如图9,我们可以把最后一个元素9提拔上来,让9做根元素。显而易见,现在除了新提拔的这个根节点以外,其他的节点都满足堆的性质,那么就需要调整这个根节点。9要和左右孩子相比,与较小的孩子2互换。换后如图10所示。接着对局部的数,我们再调整,直到9落地为止,换后如图11。至此,这个完全二叉树就满足堆的要求了,我们输出2,如图12。然后,如图13,把最后一个元素10提拔上去,然后,还像之前一样,把10逐步向下调整,这个完全二叉树满足堆的要求后,输出堆顶的元素3,如图14。在堆排序的术语上,我们把较大的元素从顶层落到底层的过程称为“筛选”。然后再把最后一个元素提拔上去,在筛选,再提拔,再筛选,重复这个过程,堆变得越来越小,直至整个堆只剩下一个元素,把这个元素也输出,我们的堆排序过程也就结束了。

                        图8                                                                         图9                                                                 图10

 

                      图11                                                        图12                                                                                     图13

 

                  图14                                                                                      图15

四、代码实现

  堆排序可以用二叉树的结构来表示,但在 实际应用中,我们还可以更节省内存空间,用一位数组来表示这个二叉树,当数据量很大的时候,一维数组占用的内存比二叉树占用的内存小很多。当然,对于一般的二叉树,我们是不能这样表示的,现在的完全二叉树具有特殊性,我们可以用一维数组来表示它。

       从面向对象的角度出发,对二叉树,这要能给点一个节点,确定父节点和子节点在哪里就可以了,至于在内存中怎么存储的,并不重要。如下图所示,对于完全二叉树,给定当前节点,其父子点和子节点都是可以唯一确定的。把这些节点序号,对应到一维数组元素的下标,就可以用一维数组来表示完全二叉树了。

                                          

  因为我们用一维数组来代替完全二叉树,所以填充的过程就免去了,可以直接进行筛选,然后提拔最后一个元素,再筛选,直至堆中只剩下最后一个元素,输出,堆排序完成。代码如下:

public class HeapSort {public static void main(String[] args) {int[] a={7,2,3,6,8,5};heapSort(a);}public static void heapSort(int[] a){//建立初始堆for(int i=(a.length-1)/2;i>=0;i--) heapOne(a,a.length,i);//边输出堆顶,边调整int n=a.length; //剩余元素数while (n>0){System.out.print(a[0]+" ");//输出堆顶元素a[0]=a[n-1];//最后一个元素移动到堆顶n--;//要排序的数组的长度减1heapOne(a,n,0);}System.out.println();}//节点K进行筛选//a:堆数据 , n:堆中有效数据的个数 ,K:待筛选的节点public static void heapOne(int[] a,int n,int k){int k1=2*k+1; //K节点的左子节点int k2=2*k+2; //K节点的右子节点if(k1>=n && k2>=n)  return;//已经是叶子了int a1=Integer.MAX_VALUE;int a2=Integer.MAX_VALUE;if(k1<n) a1=a[k1]; //左孩子值if(k2<n) a2=a[k2]; //右孩子值if(a[k]<=a1&&a[k]<=a2) return;//已经符合堆的要求了//找到左右孩子中最小的,和它交换if(a1<a2){int t=a[k];a[k]=a[k1];a[k1]=t;heapOne(a,n,k1);//继续筛选子树}else {int t=a[k];a[k]=a[k2];a[k2]=t;heapOne(a,n,k2);//继续筛选子树
        }}
}
View Code

 ------------------------------------------------------------------------------------------------------------------------------------------------

参考链接:

http://www.iqiyi.com/v_19rrhzzs1k.html

转载于:https://www.cnblogs.com/hezhiyao/p/7552566.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/428737.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Codeforces Global Round 15 (A-D)没有C

A 太简单&#xff0c;写完删了B 我写的繁了&#xff0c;但是意思是这么个意思&#xff0c;就遍历打擂台一样&#xff0c;找到最后的胜者&#xff0c;然后在遍历一遍找是不是最厉害的 #include <bits/stdc.h> using namespace std; #define int long long int op[200095…

Codeforces Round #434 (Div. 2)【A、B、C、D】

Codeforces Round #434 (Div. 2) codeforces 858A. k-rounding【水】 题意&#xff1a;已知n和k&#xff0c;求n的最小倍数x&#xff0c;要求x后缀至少有k个0。 题解&#xff1a;答案就是10^k和n的最小公倍数。 1 #include<cstdio>2 #include<cstring>3 #include&l…

Codeforces Round #735 (Div. 2)(A-D)没有B

Codeforces Round #735 (Div. 2) A 一道小思维题 #include <bits/stdc.h> using namespace std; #define int long long const int N 1000100; int a[N]; signed main() {int t;cin>>t;while(t--){int n;cin>>n;int cou 0;for (int i1;i<n;i){cin>&…

Educational Codeforces Round 112 (Rated for Div. 2)(A-D)

Educational Codeforces Round 112 (Rated for Div. 2) A 我写的挺烦的&#xff0c;其实判断一下奇偶数和有没有a>0就行 #include <bits/stdc.h>using namespace std;#define int long longsigned main(){int t;cin>>t;while (t--){int n;cin>>n;int a n…

PLC与触摸屏练习

电机正反转 触摸屏 要用触摸屏进行仿真是不要忘了先启动梯形图测试 效果 1-2例 行程开关控制的自动循环 梯形图 触摸屏 下面只是用了四个开关&#xff0c;可以根据自己想要实现的按照梯形图添加 题目 梯形图 电动机星三角减压启动控制 题目及要求 触摸屏截图 运算 把显示的数值…

Django里面是文件静态化的方法

看Django官网的时候&#xff0c;由于自己的英语基础较差&#xff0c;而实现的谷歌翻译比较烂&#xff0c;只能看懂个大概。在文件静态化的时候&#xff0c;讲的比较繁琐一点&#xff0c;没怎么看懂&#xff0c;遂询问了一下其他人&#xff0c;明白了许多&#xff0c;但是细节需…

Codeforces Round #736 (Div. 2)(B-C)

Codeforces Round #736 (Div. 2) 花了十分钟帮朋友写了B&#xff0c;C就睡觉了&#xff0c;自己没打 B 先看上&#xff0c;再看左后看右 #include <iostream> #include <cstring> #include <algorithm> using namespace std; #define int long long signed…

RabbitMQ 声明Queue时的参数们的Power

RabbitMQ 声明Queue时的参数们的Power 参数们的Power 在声明队列的时候会有很多的参数 public static QueueDeclareOk QueueDeclare(this IModel model, string queue "", bool durable false, bool exclusive true, bool autoDelete true, IDictionary<strin…

解决Firefox已阻止运行早期版本Adobe Flash

解决Firefox已阻止运行早期版本Adobe Flash 类别 [随笔分类]web 解决Firefox已阻止运行早期版本Adobe Flash 最近火狐浏览器不知抽什么风&#xff0c;每次打开总提示"Firefox已阻止(null)运行早期版本的Adobe Flash"。要命的是它提示的解决办法根本不管用&#xf…

误删path怎么办(已重启)

我是在设置环境变量的时候不懂&#xff0c;新建了一个path&#xff0c;导致我原来的path没了。 但是居然jdk能用。。。。。不太懂。 不要慌&#xff0c;大不了重装系统。其实只要再重新新建就行了。 C:\Program Files\Common Files\Siemens\Automation\Simatic OAM\bin;%Syste…

一个容易被忽视的css选择器

之前学的的迷糊了&#xff0c;也不知道什么会什么不会了&#xff0c;跑去面试了。别人列出一堆css选择器&#xff0c;本以为选择器没啥的&#xff0c;结果到那个多类选择器翻车了&#xff0c;.a.b选择同时含a,b类名的&#xff0c;很尴尬所以回来仔细整理了一下。目前根据W3C手册…

Codeforces Round #756 (Div. 3)

Codeforces Round #756 (Div. 3) A. Make Even 思路&#xff1a;如果末尾是偶数&#xff0c;不需要操作&#xff1b;如果开头是偶数&#xff0c;一次操作&#xff0c;即全翻转&#xff1b;如果开头和末尾都是 奇数&#xff0c;判断里面是否有偶数&#xff0c;如果没有&#xff…

使用MyBatista----上传图像

使用MyBatis上传图像&#xff0c;使用的是Oracle的数据库表&#xff0c;有一个TEACHER表&#xff0c;有7列&#xff0c;有1列是存储图片的&#xff0c;类型用BLOB&#xff0c;最大容量是4G&#xff0c;以二进制的形式写入数据库表。 建立这个表的对应实体类Teacher&#xff0c;…

189A. Cut Ribbon

A. Cut Ribbon:题目地址 题意&#xff1a;一条长为n的彩带切割&#xff0c;切割后每段长度是a或者是b或者是c#include <bits/stdc.h> using namespace std; typedef long long ll; vector<int> a((int)4e5); vector<int> b((int)4e5); int main() {int n,a,…

作业1.3

public class Work{   public static void main(String[] args)   {     System.out.println(" J A V V A");     System.out.println(" J A A V V A A"); //直接输出就好了     System.out.println("J J …

476B. Dreamoon and WiFi

B. Dreamoon and WiFi:题目链接 题意&#xff1a;给你一个正常的走向&#xff0c;在给你一个虚假和不确定的走向&#xff0c;问到达的可能性#include <bits/stdc.h> using namespace std; string str1, str2; double C(double A, double B) {double res 1.0;for (int i…

简易观察者模式

var Event {   on(event,callback){     if(!this.handles){       this.handles {};     }     if(!this.handles[event]){       this.handles[event] [];     }     this.handles[event].push(callback);   },   emit(event){   …

1360E. Polygon

E. Polygon&#xff1a;题目 题意&#xff1a;在一个n*n的方块空间内&#xff0c;上下都有大炮&#xff0c;发射数量和先后由你决定。问能否得到他给的地图。 思路&#xff1a;如果他不是靠下边或者右边&#xff0c;右或者下必有一个炮弹阻挡。所以直接遍历判断就行#include &…

1470A. Strange Birthday Party

A. Strange Birthday Party&#xff1a;题目 题意&#xff1a;有n个朋友&#xff0c;要么给他钱&#xff0c;要么给他买礼物&#xff0c;礼物每样只能买一个 思路&#xff1a;sort&#xff0c;给钱不如给礼物的给礼物&#xff0c;礼物给完了&#xff0c;或者礼物本身太贵不如给…

_INTSIZEOF

在_INTSIZEOF中该有的都有了 1.这其中最小非负剩余和最大正余数例子如下: 设n为4&#xff0c;当r为1时&#xff0c;最小非负剩余就是1&#xff0c;最大非正剩余就是1 - 4 -3&#xff0c;最大正余数为4 - 1 3 2.x nq r推导出qn ((x n - 1) / n) * n的过程如下 1)当x % n等…