二叉堆

满足如下结构性和堆序性,即为二叉堆。

结构性质:堆是一棵被完全填满的二叉树,有可能的例外是在底层,底层上的元素从左到右填入。这样的树称为完全二叉树。


容易证明,一棵高为 h 的完全二叉树有 2h 到 2h+1-1 个节点。这意味着完全二叉树的高是⌊ log N ⌋,显然它是 O( log N )。

一个重要的观察发现,因为完全二叉树这么有规律,所以它可以用一个数组表示而不需要使用链。


对于数组中任一位置 i 上的元素,其左儿子在位置 2i 上,右儿子在左儿子后的单元(2i + 1)中,它的父亲则在位置 ⌊ i/2 ⌋上。

堆序性质:任意节点都小于它的所有后裔。



基本的堆操作

insert( 插入 )

为将一个元素 X 插入到堆中,我们在下一个可用位置创建一个空穴,否则该堆将不是完全数。如果 X 可以放在该空穴中而不破坏堆的序,那么插入完成。否则,我们把空穴的父节点上的元素移入该空穴中,这样,空穴就朝着根的方向上冒一步。继续改过程直到 X 能被放入空穴中为止。



这样一般的策略叫做上滤( percolate up );新元素在堆中上滤直到找出正确的位置。

	public void insert( T x ){if( currentSize == array.length - 1 ){enlargeArray( array.length*2 + 1 );}//上滤int hole = ++currentSize;for( ; hole>1 && x.compareTo( array[ hole/2 ])<0; hole/=2 ){array[ hole ] = array[ hole/2 ];}array[ hole ] = x;}

如果欲插入的元素是新的最小元从而一直上滤到根处,那么这种插入的时间将长达 O( log N );

平均看来,上滤终止得要早,业已证明,执行一次插入平均需要 2.607 次比较,因此平均 insert 操作上移元素 1.607层。


deleteMin(删除最小元)

当删除一个最小元时,要在根节点建立一个空穴。由于现在堆少了一个元素,因此堆中最后一个元素 X 必须移动到该堆的某个地方。如果 X 可以直接被放到空穴中,那么 deleteMin 完成。不过这一般不太可能,因此我们将空穴的两个儿子中比较小者移入空穴,这样就把空穴向下推了一层。重复该步骤直到 X 可以被放入空穴中。因此,我们的做法是将 X 置入沿着从根开始包含最小儿子的一条路径上的一个正确的位置。



这种一般的策略叫做下滤(percolate down)。

	public T deleteMin(){if( isEmpty() )throw new UnderflowException();T minItem = array[1];array[1] = array[ currentSize-- ];percolateDown( 1 );return minItem;}private void percolateDown( int hole ){int child;T tmp = array[ hole ];for( ; hole*2 <= currentSize; hole=child ){child = hole*2;if( child != currentSize && array[child+1].compareTo( array[child] ) <0 ){child++;}if( array[child].compareTo( tmp ) < 0 ){array[hole] = array[child];}else{break;}}array[hole] = tmp;}

这种操作最坏情形运行时间为 O( log N )。平均而言,被放到根处得元素几乎下滤到堆的底层(即它所来自的那层),因此平均运行时间为 O( log N )。


decreaseKey(降低关键字的值)

decreaseKey( p, △ ) 操作降低在位置 p 处得项的值,降值幅度为正量△。由于这可能破坏堆序性质,因此必须通过上滤对堆进行调整。

该操作对系统管理员是有用的:系统管理员能够使他们的程序以最高的优先级来运行。


increaseKey(增加关键字的值)

increaseKey( p, △ )操作增加在位置 p 处得项的值,增值的幅度为正的量△。这可以用下滤来完成。

许多调度程序自动地降低正在过多地消耗 CPU 时间的进程的优先级。


delete(删除)

delete( p ) 操作删除堆中位置 p 上的节点。该操作通过首先执行 decreaseKey( p, ∞ )然后再执行 deleteMin( ) 来完成。

当一个进程被用户中止(而不是正常终止)时,它必须从优先队列中除去。


上述三种操作均以对数最坏情形时间运行。


buildHeap(构建堆)

有时二叉堆是 由一些项的初始集合构造而得。这种构造方法以 N 项作为输入,并把它们放到一个堆中。显然,这可以使用 N 个相继的 insert 操作来完成。由于每个 insert 将花费O( 1 )平均时间,以及 O(log N) 的最坏时间,因此该算法的总的运行时间是 O(N) 平均时间而不是 O(N log N) 最坏时间。

一般的算法是将 N 项以任意顺序放入树中,保持结构特性。此时,如果 percolateDown( i ) 从节点 i 下滤,那么 buildHeap 程序则可以由构造方法用于创建一棵堆序的树。


图6-15中的第一棵树是无序树。从图6-15到图6-18中其余7棵树表示出 7 个 percolateDown 中每一个的执行结果。每条虚线对应两次比较:一次是找出较小的儿子节点,另一个是较小的儿子与该节点的比较。注意,在整个算法中只有 10 跳虚线,它们对应 20 次比较。

	public BinaryHeap( T[] items ){currentSize = items.length;array = (T[]) new Comparable[ (currentSize + 2) * 11 / 10 ];int i=1;for( T item : items ){array[ i++ ] = item;}buildHeap();}private void buildHeap(){for( int i = currentSize/2; i>0; i-- )percolateDown( i );}
为了确定 buildHeap 的运行时间的界,我们必须确定虚线的条数的界。这可以通过计算堆中所有节点的高度的和来得到,它是虚线最大条数。现在我们想说明的是:该和为 O(N)。

定理:包含 2h+1-1 个节点、高为 h 的理想二叉树的节点的高度的和为 2h+1-1 - ( h+1 )。

也就是: 节点的个数(N) ≈ 节点高度的和

完整代码:

public class BinaryHeap<T extends Comparable<? super T>> {private static final int DEFAULT_CAPACITY = 10;/*** 堆中元素个数*/private int currentSize;private T[] array;public BinaryHeap() {super();currentSize = 0;array = (T[]) new Comparable[ DEFAULT_CAPACITY ];}public BinaryHeap( T[] items ){currentSize = items.length;array = (T[]) new Comparable[ (currentSize + 2) * 11 / 10 ];int i=1;for( T item : items ){array[ i++ ] = item;}buildHeap();}private void buildHeap(){for( int i = currentSize/2; i>0; i-- )percolateDown( i );}private void enlargeArray( int size ){Comparable[] newArray = new Comparable[size];for( int i=1 ; i<array.length ; i++ ){newArray[i] = array[i];}array = (T[]) newArray;}public void insert( T x ){if( currentSize == array.length - 1 ){enlargeArray( array.length*2 + 1 );}//上滤int hole = ++currentSize;for( ; hole>1 && x.compareTo( array[ hole/2 ])<0; hole/=2 ){array[ hole ] = array[ hole/2 ];}array[ hole ] = x;}public boolean isEmpty(){return currentSize == 0;}/*** 删除最小* @return** Date	  :2012-7-6* Author :GongQiang*/public T deleteMin(){if( isEmpty() )throw new UnderflowException();T minItem = array[1];array[1] = array[ currentSize-- ];percolateDown( 1 );return minItem;}/*** 下滤* @param hole** Date	  :2012-7-6* Author :GongQiang*/private void percolateDown( int hole ){int child;T tmp = array[ hole ];for( ; hole*2 <= currentSize; hole=child ){child = hole*2;if( child != currentSize && array[child+1].compareTo( array[child] ) <0 ){child++;}if( array[child].compareTo( tmp ) < 0 ){array[hole] = array[child];}else{break;}}array[hole] = tmp;}
}class UnderflowException extends RuntimeException{}


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

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

相关文章

linux模式匹配运算符,linux之正则表达式

文件查找的需要&#xff1a;grep:(GLOBAL Research) 根据模式(网)去搜索文本&#xff0c;而后将符合模式的文本行显示出来。【部分匹配&#xff0c;显示时显示一行】Pattern&#xff1a;模式。(文本字符以及正则表达式元字符组合而成的匹配条件)例子&#xff1a;grep‘root’/e…

伯克利AI研究院解析「反向课程学习」,改善「强化学习智能体」并应用于机器人技术

原文来源&#xff1a;arXiv作者&#xff1a;Wieland Brendel、Jonas Rauber、Matthias Bethge「雷克世界」编译&#xff1a;嗯~阿童木呀、哆啦A亮众所周知&#xff0c;强化学习&#xff08;RL&#xff09;是一种强大的技术&#xff0c;它能够解决诸如移动&#xff08;locomotio…

《Science》评选2017年十大科学突破,看看有哪些吧!

来源&#xff1a;材料科学与工程概要&#xff1a;美国《科学》杂志21日公布了其评选出的2017年十大科学突破&#xff0c;人类首次观测到双中子星并合事件被选为头号科学突破。美国《科学》杂志21日公布了其评选出的2017年十大科学突破&#xff0c;人类首次观测到双中子星并合事…

linux 第三章红帽子,红帽子 Linux_命令全解

118.Ctrlz 把程序放入后台运行-暂停状态&#xff0c;Ctrlc 终止进程&#xff0c;整洁关闭119.jobs 作业列表120.bg [%作业号] 后台恢复运行121.fg [%作业号] 前台恢复运行122.(date;who | wc -l ) >> logfile 聚集命令()&#xff0c;生成subshell全部发送123.echo $? 保…

PL/SQL-FOR UPDATE 与 FOR UPDATE OF的区别

数据库 oracle for update of 和 for update区别 select * from TTable1 for update 锁定表的所有行&#xff0c;只能读不能写 2 select * from TTable1 where pkid 1 for update 只锁定pkid1的行 3 select * from Table1 a join Table2 b on a.pkidb.pkid for u…

2017年深度学习重大研究进展全解读

来源&#xff1a;机器之心概要&#xff1a;想知道哪些深度学习技术即将影响我们的未来吗&#xff1f;本文将给你作出解答。2017 年只剩不到十天&#xff0c;随着 NIPS 等重要会议的结束&#xff0c;是时候对这一年深度学习领域的重要研究与进展进行总结了。来自机器学习创业公司…

linux管道符加空格吗,管道符,作业控制,变量以及变量配置文件

一、管道符前面已经提过过管道符 “|”, 就是把前面的命令运行的结果丢给后面的命令。# cat 1.txt | wc -l //显示1.txt文件行数二、作业控制当运行进程时&#xff0c;你可以使它暂停(按CtrlZ组合键)&#xff0c;然后使用fg(foreground的简写)命令恢复它&#xff0c;或是利用bg…

PL/SQL 连接配置

PLSQL连接oracle数据库配置 方法一&#xff1a; 1&#xff09;点击Net Configuration Assistant 2) 在弹出的对话框中选择本地Net服务名配置&#xff0c;点下一步 3&#xff09; 在服务名配置对话框中选择添加&#xff0c;点下一步 4&#xff09;在如下对话框中填写要访问的ora…

自动驾驶汽车硬件与软件技术介绍

来源&#xff1a;知乎概要&#xff1a;本文详细介绍了自动驾驶汽车的硬件和软件&#xff0c;以及所需要做的准备工作&#xff0c;每个研发者或者准备投身于无人驾驶领域的人都应该好好看一下。全球有数不清的公司在忙着研发自动驾驶汽车&#xff0c;他们的产品也千奇百怪&#…

linux数组随机数,随机数与数组

随机数数组变量清屏时间延迟静态网站HTML随机数srand()函数用于播种函数头文件: stdlib.h函数定义: void srand(unsigned int seed)函数功能:设置随机数种子函数说明:通常可以用getpid(获取当前进程的进程识别码)或者time(NULL)(获取当前系统的时间信息)来充当种子&#xff0c;…

DeepMind 的2017:有 AlphaGo,更有社会责任

来源&#xff1a;AI科技评论概要&#xff1a;DeepMind 相信 AI 在更复杂的问题上也能起到同样的作用&#xff0c;它可以是科学技术工具&#xff0c;也可以是人类创造力的倍增器。AlphaGo 团队现在已经把注意力转向了另一组宏伟的目标&#xff0c;DeepMind 自己也希望这些研究人…

脏读、不可重复读和幻读

1. 脏读 &#xff1a;脏读就是指当一个事务正在访问数据&#xff0c;并且对数据进行了修改&#xff0c;而这种修改还没有提交到数据库中&#xff0c;这时&#xff0c;另外一个事务也访问这个数据&#xff0c;然后使用了这个数据。2. 不可重复读 &#xff1a;是指在一个事务内…

c++语言中break的作用,C++ break和continue用法详解

用于 switch 中的 break 语句也可以放在循环中&#xff0c;当遇到 break 时&#xff0c;循环立即停止&#xff0c;程序跳转到循环后面的语句。以下是一个带有 break 语句的循环示例。程序段中的 while 循环看起来要执行 10 次&#xff0c;但 break 语句导致它在第 5 次迭代后即…

2018年人工智能13大预测

来源&#xff1a;英伟达概要&#xff1a;2017 年人工智能领域取得了许多里程碑式的成果。那么&#xff0c;以后人工智能又会如何发展呢&#xff1f;2017年被《华尔街日报》、《福布斯》和《财富》等刊物称为“人工智能之年”。各种深度学习在线课程不断推出&#xff0c;接受相关…

ORACLE 多版本读一致性

先来看看这段代码&#xff1a;while s in (select * from table1) loopinsert into table1 values(s.field1,s.field2,s.field3,s.field4,s.field5);end loop;如果是SQL server的开发人员&#xff0c;看到这段代码&#xff0c;肯定会摇头&#xff1a;这段代码有问题&#xff0c…

自动点名系统c语言,用C语言编写一个随机点名系统

/*编写一个随机点名系统&#xff0c;运行该系统后&#xff0c;按空格键可以显示出一名同学&#xff0c;以前被选中的同学&#xff0c;将不会再次被选中*/#include /*standard input & output*/#include /*standard libary*/#include /*string*/#include /*Console Input/Ou…

2017年全球AI芯片公司大盘点

来源&#xff1a;芯师爷概要&#xff1a;2017年&#xff0c;我们被AI公司的融资信息一次次刷屏&#xff0c;从2千万到1亿美金&#xff0c;让我惊诧道&#xff0c;AI的黄金年代真的来了吗&#xff1f;2017年&#xff0c;我们被AI公司的融资信息一次次刷屏&#xff0c;从2千万到1…

Oracle常用sql操作总结

一、选择行 1. 简单的SELECT 语句 SELECT 字段名1 [AS] 字段名1 解释 FROM table; 2. 处理NULL NVL函数可把NULL转换成其它类型的符号 编程技巧: NVL函数在多条件模糊查询的时候比较有用 NVL函数可返回多种数据类型: 返回日期 NVL(start_date,2002-02-01) 返回字符串 NVL(title…

51单片机 驱动步进电机 C语言 lcd,51单片机红外遥控控制步进电机的LCD显示源程序...

/******************************************************************************** 实验名 : 红外控制步进电机1602显示值实验* 使用的IO : 电机用P2口* 实验效果 : LCD1602显示出读取到的红外线的值&#xff0c;步进电机作出…

邬贺铨:工业物联网的技术与前景

来源&#xff1a;走向智能论坛概要&#xff1a;工业物联网是企业信息化的进程&#xff0c;我们经历了流程电子化、管理数字化、生产自动化到企业互联网化和企业智能化。邬贺铨&#xff1a;工业物联网靠花钱是买不到的&#xff01;12月20日&#xff0c;2017第八届中国物联网产业…