前言

话说新开的博客十分好用...

所以,我打算开一个坑,名曰【算法系列】。

什么意思——从名字泥应该就猜得出来。。。

废话不多说,进入正文~~


正文

原理

首先,堆是一颗二叉树。。

其次,堆是一棵完全二叉树。。

然后,设有一关系 P(Type X, Type Y)

则,堆的每个元素 Element

满足:

  1. foreach Child Element.Childs do
  2. ASSERT( P(Element.value, Child.value) );

说的明白点,就是每个元素和它的儿子有特定得关系。。。(忽略错别字)

所以,利用堆の性质,我们可以在O(lg n)的时间复杂度内做一些好的事情。。。


解释(?)& 代码

1. 关于堆的存储

设v是堆里一点,则:

v*2 是 v的左儿子

v*2+1 是 v的右儿子

在实际操作中,我们常用位运算加速操作。

即:

  1. inline int LEFT(int x) {return (x<<1);}
  2. inline int RIGHT(int x) {return (x<<1|1);}
  3. inline int FATHER(int x) {return (x>>1);}

2. 初始化堆

  1. heapnum = 0;
  2. memset(heap, 0, sizeof(heap));

3. 维护堆的性质

这是堆比较重要的一个函数。

Heapify(x) 维护以为根的字树保持堆的性质。

代码:

  1. void Heapify(int x){
  2. int largest;
  3. if(LEFT(x) <= heapnum && P(heap[x],heap[LEFT(x)]))
  4. largest = LEFT(x);
  5. else largest = x;
  6. if(RIGHT(x) <= heapnum && P(heap[largest], heap[RIGHT(x)]))
  7. largest = RIGHT(x);
  8. if(largest != x){
  9. Exchange(heap[x], heap[largest]);
  10. Heapify(largest);
  11. }
  12. }

4. UPDATE元素

该函数的作用是把x元素改为y,且必须满足P(heap[x],y)

  1. void HeapInc(int x,int y){
  2. heap[x] = y;
  3. while (x > 1 && P(heap[FATHER(i)], heap[x])) {
  4. Exchange(heap[x], heap[FATHER(x)]);
  5. x = FATHER(x);
  6. }
  7. }

5. 添加元素

不说了。。。上代码:

附注:这里假设P(x,y)表示x<y, 如果P(x,y)表示x>y那么请用INF代替-INF

  1. void HeapAdd(int x){
  2. heap[++heapnum] = -INF;
  3. HeapInc(heapnum, x);
  4. }

6. 关于堆首的操作

首先 --- 返回堆首元素(哈哈,这个不会写的话···)

  1. int Top(){
  2. assert(heapnum >= 1); //assert(x)表示断言,如果x为false就停止程
  3. return heap[1];
  4. }

其次 --- 删除堆首元素

  1. void Pop(){
  2. assert(heapnum >= 1);
  3. Exchange(heap[1], heap[heapnum--]);
  4. if(heapnum) Heapify(1);
  5. }

最后 --- 结合上面两个

  1. int Extract(){
  2. int val = Top();
  3. Pop();
  4. return val;
  5. }

7. 其他一些东西

非空:

  1. bool Empty(){
  2. return heapnum == 0;
  3. }

8. 写成一个类

神马是类?你猜····

  1. const int N = 30000;
  2. const int HEAPSIZE = N * 4;
  3. template <class TElement = int, class Operator = less<int> >
  4. class BasicHeap{
  5. private:
  6. TElement Plc;
  7. TElement heap[HEAPSIZE + 5];
  8. int heapnum;
  9. Operator P;
  10. inline int LEFT(int x){return x<<1;}
  11. inline int RIGHT(int x){return x<<1|1;}
  12. inline int FATHER(int x){return x>>1;}
  13. inline void Exchange(TElement & x, TElement & y){TElement t = x; x = y; y = t;}
  14. void Heapify(int x){
  15. int largest;
  16. if(LEFT(x) <= heapnum && P(heap[x],heap[LEFT(x)]))
  17. largest = LEFT(x);
  18. else largest = x;
  19. if(RIGHT(x) <= heapnum && P(heap[largest], heap[RIGHT(x)]))
  20. largest = RIGHT(x);
  21. if(largest != x){
  22. Exchange(heap[x], heap[largest]);
  23. Heapify(largest);
  24. }
  25. }
  26. inline void Assert(bool flg){
  27. if(!flg){
  28. abort();
  29. }
  30. }
  31. public:
  32. BasicHeap(){
  33. heapnum = 0;
  34. P = Operator();
  35. }
  36. void Inc(int x,int y){
  37. heap[x] = y;
  38. while (x > 1 && P(heap[FATHER(x)], heap[x])) {
  39. Exchange(heap[x], heap[FATHER(x)]);
  40. x = FATHER(x);
  41. }
  42. }
  43. void Add(int y){
  44. heap[++heapnum] = y;
  45. int x = heapnum;
  46. while (x > 1 && P(heap[FATHER(x)], heap[x])) {
  47. Exchange(heap[x], heap[FATHER(x)]);
  48. x = FATHER(x);
  49. }
  50. }
  51. int Top(){
  52. Assert(heapnum >= 1);
  53. return heap[1];
  54. }
  55. void Pop(){
  56. Assert(heapnum >= 1);
  57. Exchange(heap[1], heap[heapnum--]);
  58. if(heapnum) Heapify(1);
  59. }
  60. int Extract(){
  61. int val = Top();
  62. Pop();
  63. return val;
  64. }
  65. void Clear(){
  66. heapnum = 0;
  67. }
  68. bool Empty(){
  69. return heapnum == 0;
  70. }
  71. };
  72. typedef BasicHeap<> MaxHeap;
  73. typedef BasicHeap<int, greater<int> > MinHeap;

算法&数据结构系列 -- 堆(优先队列)的更多相关文章

  1. 图论——Dijkstra+prim算法涉及到的优先队列(二叉堆)

    [0]README 0.1)为什么有这篇文章?因为 Dijkstra算法的优先队列实现 涉及到了一种新的数据结构,即优先队列(二叉堆)的操作需要更改以适应这种新的数据结构,我们暂且吧它定义为Dista ...

  2. 《Algorithms算法》笔记:优先队列(2)——二叉堆

    二叉堆 1 二叉堆的定义 堆是一个完全二叉树结构(除了最底下一层,其他层全是完全平衡的),如果每个结点都大于它的两个孩子,那么这个堆是有序的. 二叉堆是一组能够用堆有序的完全二叉树排序的元素,并在数组 ...

  3. 纯数据结构Java实现(6/11)(二叉堆&优先队列)

    堆其实也是树结构(或者说基于树结构),一般可以用堆实现优先队列. 二叉堆 堆可以用于实现其他高层数据结构,比如优先队列 而要实现一个堆,可以借助二叉树,其实现称为: 二叉堆 (使用二叉树表示的堆). ...

  4. 数据结构与算法入门系列教程-C#

    数据结构与算法入门系列教程 (一)为啥要学习数据结构与算法 曾经我也以为自己很牛逼,工作中同事也觉得我还可以,领导也看得起我,啥啥啥都好,就这样过了几年,忽然发现自己学新东西没劲.时代都变了,而我还只 ...

  5. 经典算法研究系列:二、Dijkstra 算法初探

    July   二零一一年一月 本文主要参考:算法导论 第二版.维基百科. 一.Dijkstra 算法的介绍 Dijkstra 算法,又叫迪科斯彻算法(Dijkstra),算法解决的是有向图中单个源点到 ...

  6. 【JavaScript数据结构系列】00-开篇

    [JavaScript数据结构系列]00-开篇 码路工人 CoderMonkey 转载请注明作者与出处 ## 0. 开篇[JavaScript数据结构与算法] 大的计划,写以下两部分: 1[JavaS ...

  7. 经典面试题(二)附答案 算法+数据结构+代码 微软Microsoft、谷歌Google、百度、腾讯

    1.正整数序列Q中的每个元素都至少能被正整数a和b中的一个整除,现给定a和b,需要计算出Q中的前几项, 例如,当a=3,b=5,N=6时,序列为3,5,6,9,10,12 (1).设计一个函数void ...

  8. 【C#数据结构系列】查找

    一:查找 1.1 基本概念和术语 查找(Search)是在数据结构中确定是否存在关键码等于给定关键码的记录的过程.关键码有主关键码和次关键码.主关键码能够唯一区分各个不同的记录,次关键码通常不能唯一区 ...

  9. 【JavaScript数据结构系列】03-队列Queue

    [JavaScript数据结构系列]03-队列Queue 码路工人 CoderMonkey 转载请注明作者与出处 1. 认识队列Queue结构 队列,跟我们的日常生活非常贴近,我们前面举例了食堂排队打 ...

随机推荐

  1. 解决JSONObject.fromObject数字为null时被转换为0

    在使用JSONObject.fromObject的时候会遇到一种情况就是当对象的某一个Double型或Integer型的属性为空的时候,转JSON的时候会变成0.当一个布尔型的属性为空的时候,转JSO ...

  2. Windows7下设置定时启动(关闭)虚拟机

    曾记否,忆当年,开启或者关闭虚拟机,度秒如年~ ⒈石头,剪刀,布,C.D.E盘随便找一个,然后在里面找个静谧的墙角, 新建一个文件:vmstart.bat 添加:"C:\Program Fi ...

  3. windows server 2008使用nginx转发API异常解决办法

    公司比较传统,一直使用的JSP做项目,没有遇到过跨域问题. 最近因为公司接到一个微信spa项目,因为考虑到项目需要调用老接口,斗胆选择nginx(1.12.1)做接口转发服务, 开发环境使用的win1 ...

  4. phpstudy php5.4以上版本伪静态设置 thinkphp

    http://www.thinkphp.cn/topic/35958.html <IfModule mod_rewrite.c> Options +FollowSymlinks -Mult ...

  5. element-ui中upload组件如何传递文件及其他参数

    最近项目用到了vuethink,里面集成了element-ui,之前一直用的是bootstrap框架,对js也是一知半解,然后也用过vue.js,但也是学的不通透的,然后就各种入坑. 下面就分析一下我 ...

  6. dede的pagelist标签的listsize数字属性详解

    转载▼http://blog.sina.com.cn/s/blog_a4f3bd4e01012c8n.html dede的pagelist标签的listsize数字属性详解.见远seo经常用织梦搭建各 ...

  7. 微信小程序版2048

    最近流行微信"跳一跳"小游戏,我也心血来潮写了一个微信小程序版2048,本篇文章主要分享实现2048的算法以及注意的点,一起来学习吧!(源码地址见文章末尾)   算法 1.生成4* ...

  8. QT5 Thread线程

    QT5 Thread线程继承QThread方式 一.首先分析一下 QTimer Class与 Sleep()函数之间的秘密 QTimer *t = new QTimer(*parent); //创建Q ...

  9. [知了堂学习笔记]_Java代码实现MySQL数据库的备份与还原

    通常在MySQL数据库的备份和恢复的时候,多是采用在cmd中执行mysql命令来实现. 例如: mysqldump -h127.0.0.1 -uroot -ppass test > d:/tes ...

  10. IOS 使用 ZbarSDK 二维码扫描

    1. 下载SDK   https://github.com/bmorton/ZBarSDK 2. 引用到项目中 3. 添加引用 4. AppDelegate中添加下面代码 5. 在需要使用扫描的con ...