纸上谈兵: 堆 (heap)

纸上谈兵: 堆 (heap)

作者:Vamei 出处:http://www.cnblogs.com/vamei 欢迎转载,也请保留这段声明。谢谢!

 

堆(heap)又被为优先队列(priority queue)。尽管名为优先队列,但堆并不是队列。回忆一下,在队列中,我们可以进行的限定操作是dequeue和enqueue。dequeue是按照进入队列的先后顺序来取出元素。而在堆中,我们不是按照元素进入队列的先后顺序取出元素的,而是按照元素的优先级取出元素。

这就好像候机的时候,无论谁先到达候机厅,总是头等舱的乘客先登机,然后是商务舱的乘客,最后是经济舱的乘客。每个乘客都有头等舱、商务舱、经济舱三种个键值(key)中的一个。头等舱->商务舱->经济舱依次享有从高到低的优先级。

再比如,封建社会的等级制度,也是一个堆。在这个堆中,国王、贵族、骑士和农民是从高到低的优先级。

封建等级

 

Linux内核中的调度器(scheduler)会按照各个进程的优先级来安排CPU执行哪一个进程。计算机中通常有多个进程,每个进程有不同的优先级(该优先级的计算会综合多个因素,比如进程所需要耗费的时间,进程已经等待的时间,用户的优先级,用户设定的进程优先程度等等)。内核会找到优先级最高的进程,并执行。如果有优先级更高的进程被提交,那么调度器会转而安排该进程运行。优先级比较低的进程则会等待。“堆”是实现调度器的理想数据结构。

(Linux中可以使用nice命令来影响进程的优先级)

 

堆的实现

堆的一个经典的实现是完全二叉树(complete binary tree)。这样实现的堆成为二叉堆(binary heap)。

完全二叉树是增加了限定条件的二叉树。假设一个二叉树的深度为n。为了满足完全二叉树的要求,该二叉树的前n-1层必须填满,第n层也必须按照从左到右的顺序被填满,比如下图:

为了实现堆的操作,我们额外增加一个要求: 任意节点的优先级不小于它的子节点。如果在上图中,设定小的元素值享有高的优先级,那么上图就符合该要求。

这类似于“叠罗汉”。叠罗汉最重要的一点,就是让体重大的参与者站在最下面,让体重小的参与者站在上面 (体重小,优先级高)。为了让“堆”稳固,我们每次只允许最上面的参与者退出堆。也就是,每次取出的优先级最高的元素。

三个“叠罗汉”堆

 

我已经在排序算法简介及其C实现中实际使用了堆。堆的主要操作是插入和删除最小元素(元素值本身为优先级键值,小元素享有高优先级)。在插入或者删除操作之后,我们必须保持该实现应有的性质: 1. 完全二叉树 2. 每个节点值都小于或等于它的子节点。

 

在插入操作的时候,会破坏上述堆的性质,所以需要进行名为percolate_up的操作,以进行恢复。新插入的节点new放在完全二叉树最后的位置,再和父节点比较。如果new节点比父节点小,那么交换两者。交换之后,继续和新的父节点比较…… 直到new节点不比父节点小,或者new节点成为根节点。这样得到的树,就恢复了堆的性质。

我们插入节点2:

插入

 

删除操作只能删除根节点。根节点删除后,我们会有两个子树,我们需要基于它们重构堆。进行percolate_down的操作: 让最后一个节点last成为新的节点,从而构成一个新的二叉树。再将last节点不断的和子节点比较。如果last节点比两个子节点中小的那一个大,则和该子节点交换。直到last节点不大于任一子节点都小,或者last节点成为叶节点。

删除根节点1。如图:

删除根节点

 

下面是代码。与我们在二叉搜索树中使用表不同,我们这里使用数组来表示完全二叉树。数组下标为0的元素不用于储存节点,而用于记录完全二叉树中元素的总数。

复制代码
/* By Vamei Use an big array to implement heapDECLARE: int heap[MAXSIZE] in calling functionheap[0] : total nodes in the heapfor a node i, its children are i*2 and i*2+1 (if exists)its parent is i/2  */void insert(int new, int heap[]) 
{int childIdx, parentIdx;heap[0] = heap[0] + 1;heap[heap[0]] = new;/* recover heap property */percolate_up(heap);
}static void percolate_up(int heap[]) {int lightIdx, parentIdx;lightIdx  = heap[0];parentIdx = lightIdx/2;/* lightIdx is root? && swap? */while((parentIdx > 0) && (heap[lightIdx] < heap[parentIdx])) {/* swap */swap(heap + lightIdx, heap + parentIdx); lightIdx  = parentIdx;parentIdx = lightIdx/2;}
}int delete_min(int heap[]) 
{int min;if (heap[0] < 1) {/* delete element from an empty heap */printf("Error: delete_min from an empty heap.");exit(1);}/* delete root move the last leaf to the root */min = heap[1];swap(heap + 1, heap + heap[0]);heap[0] -= 1;/* recover heap property */percolate_down(heap);return min;
}static void percolate_down(int heap[]) {int heavyIdx;int childIdx1, childIdx2, minIdx;int sign; /* state variable, 1: swap; 0: no swap */heavyIdx = 1;do {sign     = 0;childIdx1 = heavyIdx*2;childIdx2 = childIdx1 + 1;if (childIdx1 > heap[0]) {/* both children are null */break; }else if (childIdx2 > heap[0]) {/* right children is null */minIdx = childIdx1;}else {minIdx = (heap[childIdx1] < heap[childIdx2]) ?childIdx1 : childIdx2;}if (heap[heavyIdx] > heap[minIdx]) {/* swap with child */swap(heap + heavyIdx, heap + minIdx);heavyIdx = minIdx;sign = 1;}} while(sign == 1);
}
复制代码

你可以尝试一下构建自己的main函数,测试相关的操作。

 

总结

堆,优先级

插入元素,删除最大优先级元素

 

欢迎继续阅读“纸上谈兵: 算法与数据结构”系列。

转载于:https://www.cnblogs.com/Alandre/p/3705483.html

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

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

相关文章

C语言 取模运算 保证正数,c语言的取模运算

我们对C的%运算知多少呢&#xff1f;当是正整数时&#xff0c;可能大家都知道。例如&#xff1a;5%3等于2, 3%5等于3。当存在负数时呢&#xff1f;先看看例子&#xff1a;例一&#xff1a;int main(){int x;x -6%5; printf("%2d/n",x);x 6%-5; printf("%2d/n&…

操作系统上机题目(多线程2)

主线程创建4个子线程T1、T2、T3、T4&#xff0c;主线程在4个子线程退出后&#xff0c;才退出线程T1、T2、T3、T4的运行时代码如下&#xff1a; #include <unistd.h> // sleep函数声明在该头文件中void *T1_entry(void *arg) {sleep(2); // 睡眠2秒&#xff0c;不准删除…

图形GUI名称

15句柄图形(Handle Graphics)15.1图形窗的产生和控制(Figure window creation and control)clf 清除当前图close 关闭图形figure 打开或创建图形窗口gcf 获得当前图的柄openfig 打开图形refresh 刷新图形shg 显示图形窗15.2轴的产生和控制(Axis creation and control)axes 在任…

c语言编程非线性方程求解,c语言计算机编程三种方法求解非线性方程.doc

c语言计算机编程三种方法求解非线性方程.doc本 科 专 业 学 年 论 文题 目非线性方程求解比较姓 名 何 娟 专 业 计算机科学技术系 班 级 08 级本科(2)班 指 导 老 师 刘 晓 娜 完成日期 2010 年 11 月 21 日计算机学年专业论文 非线性方程求解- 1 -题 目非线性方程求解比较摘 …

最近用到这个强大的工具 PhysicsEditor (转)

今天收到PhysicsEditor作者发过来的license key&#xff0c;所以顺便把PhysicsEditor也尝试了一下。主要是尝试将PhysicsEditor与cocos2dx&#xff0c;box2d结合开发的一些步骤。之前大概网络检索了一下&#xff0c;知道PhysicsEditor的功能其实很简单。一句话就是给图片的边缘…

浅谈块级元素和内联元素的嵌套规则

1. 替换和不可替换元素 从元素本身的特点来讲&#xff0c;可以分为替换和不可替换元素。 a) 替换元素 替换元素就是浏览器根据元素的标签和属性&#xff0c;来决定元素的具体显示内容。 例如浏览器会根据<img>标签的src属性的值来读取图片信息并显示出来&#xff0c;而如…

如何更新Chrome

在浏览器的地址栏中输入chrome://help即可进行自动更新&#xff0c;如下图&#xff1a;

c语言用指针实现打开和关闭文件,我用rewind函数没把指针直到开始,关闭文件然后打开就行。帮忙看看...

该楼层疑似违规已被系统折叠 隐藏此楼查看此楼高手啊&#xff0c;我试了&#xff0c;结果是回到文件头了&#xff0c;把123覆盖了&#xff0c;为ABC 但我这个程序就能直接不关闭文件而用rewind函数到开头&#xff0c;你帮忙看看&#xff0c; //二进制文件的输入输出--数据块的读…

最佳适应算法模拟内存分配

最佳适应算法 从全部空闲区中找出能满足作业要求的&#xff0c;且大小最小的空闲分区&#xff0c;这种方法能使碎片尽量小。 问题描述 Given five memory partitions of 100 KB, 500 KB, 200 KB, 300 KB, and 600 KB (in order), how would each of the first-fit, best-fit…

单片机c语言 i%3c%3c1,单片机C语言作业及上机习题及答案

《单片机C语言作业及上机习题及答案》由会员分享&#xff0c;可在线阅读&#xff0c;更多相关《单片机C语言作业及上机习题及答案(37页珍藏版)》请在人人文库网上搜索。1、第一次课熟悉winTC编译环境、熟悉C语言程序结构1.使用C 语言编译环境&#xff0c;输入下面的源程序。将你…

基于顺序搜索的动态分区分配算法模拟内存动态分配--最佳适应算法(best fit,BF)

BF算法、男朋友算法&#xff0c;哈哈 要实现动态分区分配&#xff0c;需要考虑三个方面的问题。分别是数据结构、分区分配算法、分区的分配与回收操作。 首数据结构 这里我们使用的是空闲分区链&#xff0c;采用双向链表表示空闲分区。 具体实现如下&#xff1a; typedef …

我也要谈谈大型网站架构之系列(4)——分布式中的异步通信

我们知道在面向对象编程中&#xff0c;总会想着各种办法来实现代码的解耦&#xff0c;从而让项目中的各种人员面对自己熟悉的业务进行开发&#xff0c; 做到术业有专攻&#xff0c;比如大家非常熟悉的三层架构&#xff0c;MVC&#xff0c;MVP以及MVVM模式&#xff0c;让前端设计…

node模块函数图解

已截图方式记录模块信息&#xff1a; HTTP模块&#xff1a; 对于网络返回处理状态封装了很多种&#xff0c;我已截图展现 以上状态也是在http协议中包含的状态。 http函数&#xff1a; path模块&#xff1a; 转载于:https://www.cnblogs.com/kuailingmin/p/4547538.html

android 心跳效果动画,Android实现心跳的效果

最近再做一个教育类的项目。在做一些学习工具的时候&#xff0c;美工提出了一些要求&#xff0c;大致如下&#xff1a;其实实现过程也不难&#xff0c;大致就是对一个视图控件添加一个圆形的背景&#xff0c;然后该视图进行动画处理&#xff0c;膨胀的同时&#xff0c;透明度增…

Oracle超出最大连接数问题及解决

用过Oracle的应该都熟悉如何查看和设置Oracle数据库的最大连接数。这里就再啰嗦一遍。 查看当前的连接数&#xff0c;可以用select count(*) from v$process;设置的最大连接数&#xff08;默认值为150&#xff09;select value from v$parameter where name ‘processes’;修改…

操作系统上机作业--使用系统调用实现mycat

mycat.c的功能与系统cat程序相同mycat将指定的文件内容输出到屏幕&#xff0c;例子如下&#xff1a;要求使用系统调用open/read/write/close实现 $ cat /etc/passwd root:x:0:0:root:/root:/bin/bash daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin bin:x:2:2:bin:/bin:/u…

GCDAynscSocket简单使用-客户端

这是一篇介绍GCDAynscSocket客户端简单使用的文章&#xff08;服务端后续添加&#xff09; 背景&#xff1a;在这篇文章之前我对socket的了解仅限于知道有TCP、UDP两种方式&#xff0c;使用抓包工具时甚至看不懂抓包数据&#xff08;惭愧...&#xff09;&#xff0c;所以本文介…

微信android版字体,微信炫彩字下载-微信七彩字体 安卓版v1.6.2-PC6安卓网

微信七彩字体一款方便的手机字体更换软件&#xff0c;微信炫彩字软件集合了上百款优质中文美化字体&#xff0c;微信七彩发光字里有可爱的喵呜体、卡通体&#xff0c;清秀的静蕾体等多种字体。软件介绍微信、qq上最好用、最个性的聊天字体应用&#xff0c;让你的聊天与众不同&a…

Android SQLite 数据库 增删改查操作

Android SQLite 数据库 增删改查操作 转载▼一、使用嵌入式关系型SQLite数据库存储数据在Android平台上&#xff0c;集成了一个嵌入式关系型数据库——SQLite&#xff0c;SQLite3支持NULL、INTEGER、REAL&#xff08;浮点数字&#xff09;、TEXT(字符串文本)和BLOB(二进制对象…

SIT与UAT的分别

在企业级软件的测试过程中&#xff0c;经常会划分为三个阶段——单元测试&#xff0c;SIT和UAT&#xff0c;如果开发人员足够&#xff0c;通常还会在SIT之前引入代码审查机制&#xff08;Code Review&#xff09;来保证软件符合客户需求且流程正确。下面简单介绍一下SIT和UAT的…