背景

Heap 可以用来实现优先级队列,也可以用来做堆排序,本文简单的做个介绍。

Heap

规则

  • 是一个完全二叉树,隐含的意思是:他是平衡的、使用数组进行存储也是连续的。
  • 给定的任意节点,该节点小于等于其父亲节点,大于他们的孩子节点。

基础知识

对于一个完全二叉树,如果将其存储到数组中,给定父节点的索引为:x,则:

  • left child's index is:2*x + 1。
  • right child's index is:2*x + 2。
  • root's index is:0.

说明:上面的公式很容易自己推到出来,有兴趣的朋友可以推到一下,这样就不用记住这个特性了。

图示

存储到数组的顺序为:先存储第一层,然后是第二层,直到第 N 层。

操作

添加和删除后还必须保证 Heap 满足规则。

添加

添加前

添加 6

先将 6 添加到完全树的下一个节点,然后沿着祖先路径,将其插入到合适的节点(不一定是根节点)。

代码

  1. public void Insert(T item)
  2. {
  3. if (this.IsFull())
  4. {
  5. throw new InvalidOperationException("容量已满,不能插入!");
  6. }
  7.  
  8. _items[_length++] = item;
  9. this.MoveUp(_length - );
  10. }

结果

删除最大值

接着上面的例子执行删除

先将删除根节点(6),再将完全树最后的节点(2)直接移动到根节点。

接着将 2 向下插入到合适的节点,比如:5 > 4 && 5 > 2,因此结果是:

代码

  1. public T Remove()
  2. {
  3. if (this.IsEmpty())
  4. {
  5. throw new InvalidOperationException("容量已空,不能删除!");
  6. }
  7.  
  8. var result = _items[];
  9. _items[] = _items[--_length];
  10.  
  11. this.MoveDown();
  12.  
  13. return result;
  14. }

完整代码

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using System.Threading.Tasks;
  6.  
  7. namespace DataStuctureStudy.Heaps
  8. {
  9. class HeapTest
  10. {
  11. public static void Test()
  12. {
  13. var heap = new Heap<int>();
  14. heap.Insert();
  15. heap.Insert();
  16. heap.Insert();
  17. heap.Insert();
  18. heap.Insert();
  19. heap.Insert();
  20. heap.Display();
  21. heap.Remove();
  22. heap.Display();
  23. }
  24.  
  25. class Heap<T>
  26. where T : IComparable<T>
  27. {
  28. private T[] _items;
  29. private int _length;
  30.  
  31. public Heap(int size)
  32. {
  33. _items = new T[size];
  34. }
  35.  
  36. public void Display()
  37. {
  38. Console.WriteLine("数组表示");
  39. Console.Write("[");
  40. for (var i = ; i < _items.Length; i++)
  41. {
  42. if (i < _length)
  43. {
  44. Console.Write(_items[i]);
  45. }
  46. else
  47. {
  48. Console.Write('-');
  49. }
  50. }
  51. Console.WriteLine("]");
  52. Console.WriteLine();
  53.  
  54. Console.WriteLine("树形表示");
  55. var row = ;
  56. var column = ;
  57. var level = (int)Math.Ceiling(Math.Log(_length + , ));
  58. var width = (int)Math.Pow(, level);
  59. for (var i = ; i < _length; i++)
  60. {
  61. this.Display(_items[i], width, row, column);
  62.  
  63. if ((i + ) == Math.Pow(, row + ) - )
  64. {
  65. row++;
  66. column = ;
  67. Console.WriteLine();
  68. }
  69. else
  70. {
  71. column++;
  72. if (i == _length - )
  73. {
  74. Console.WriteLine();
  75. }
  76. }
  77. }
  78.  
  79. Console.WriteLine();
  80. }
  81.  
  82. private void Display(T item, int width, int row, int column)
  83. {
  84. var step = (int)((width * ) / Math.Pow(, row));
  85. var itemLength = item.ToString().Length;
  86. Console.Write(item.ToString().PadLeft((step + itemLength) / ).PadRight(step));
  87. }
  88.  
  89. public void Insert(T item)
  90. {
  91. if (this.IsFull())
  92. {
  93. throw new InvalidOperationException("容量已满,不能插入!");
  94. }
  95.  
  96. _items[_length++] = item;
  97. this.MoveUp(_length - );
  98. }
  99.  
  100. private void MoveUp(int index)
  101. {
  102. var bottom = _items[index];
  103. var current = index;
  104.  
  105. while (current > )
  106. {
  107. var parent = (current - ) / ;
  108. if (_items[parent].CompareTo(bottom) > )
  109. {
  110. break;
  111. }
  112.  
  113. _items[current] = _items[parent];
  114. current = parent;
  115. }
  116.  
  117. _items[current] = bottom;
  118. }
  119.  
  120. public T Remove()
  121. {
  122. if (this.IsEmpty())
  123. {
  124. throw new InvalidOperationException("容量已空,不能删除!");
  125. }
  126.  
  127. var result = _items[];
  128. _items[] = _items[--_length];
  129.  
  130. this.MoveDown();
  131.  
  132. return result;
  133. }
  134.  
  135. private void MoveDown(int index)
  136. {
  137. var top = _items[index];
  138. var current = index;
  139.  
  140. while (current < _length)
  141. {
  142. var large = ;
  143. var left = * current + ;
  144. var right = left + ;
  145.  
  146. if (left < _length && right < _length)
  147. {
  148. if (_items[left].CompareTo(_items[right]) >= )
  149. {
  150. large = left;
  151. }
  152. else
  153. {
  154. large = right;
  155. }
  156. }
  157. else if (left < _length)
  158. {
  159. large = left;
  160. }
  161. else
  162. {
  163. break;
  164. }
  165.  
  166. if (_items[large].CompareTo(top) <= )
  167. {
  168. break;
  169. }
  170.  
  171. _items[current] = _items[large];
  172. current = large;
  173. }
  174.  
  175. _items[current] = top;
  176. }
  177.  
  178. public bool IsFull()
  179. {
  180. return _length == _items.Length;
  181. }
  182.  
  183. public bool IsEmpty()
  184. {
  185. return _length == ;
  186. }
  187. }
  188. }
  189. }

备注

下篇简单的介绍一下堆排序。

算法:堆(Heap)的更多相关文章

  1. 数据结构与算法--堆(heap)与栈(stack)的区别

    堆和栈的区别 在C.C++编程中,经常需要操作的内存可分为以下几个类别: 栈区(stack):由编译器自动分配和释放,存放函数的参数值,局部变量的值等,其操作方式类似于数据结构中的栈. 堆区(heap ...

  2. 算法与数据结构基础 - 堆(Heap)和优先级队列(Priority queue)

    堆基础 堆(Heap)是具有这样性质的数据结构:1/完全二叉树 2/所有节点的值大于等于(或小于等于)子节点的值: 图片来源:这里 堆可以用数组存储,插入.删除会触发节点shift_down.shif ...

  3. 堆heap和栈Stack(百科)

    堆heap和栈Stack 在计算机领域,堆栈是一个不容忽视的概念,堆栈是两种数据结构.堆栈都是一种数据项按序排列的数据结构,只能在一端(称为栈顶(top))对数据项进行插入和删除.在单片机应用中,堆栈 ...

  4. python数据结构之堆(heap)

    本篇学习内容为堆的性质.python实现插入与删除操作.堆复杂度表.python内置方法生成堆. 区分堆(heap)与栈(stack):堆与二叉树有关,像一堆金字塔型泥沙:而栈像一个直立垃圾桶,一列下 ...

  5. 纸上谈兵: 堆 (heap)

    纸上谈兵: 堆 (heap)   作者:Vamei 出处:http://www.cnblogs.com/vamei 欢迎转载,也请保留这段声明.谢谢! 堆(heap)又被为优先队列(priority ...

  6. 堆(heap)和栈(stack)几点认识

    堆(heap)和栈(stack)主要的区别由以下几点:1.管理方式不同:2.空间大小不同:3.产生碎片不同:4.生长方向不同:5.分配归属不同:6.分配效率不同:7.存取效率不同:管理方式:对于栈来讲 ...

  7. (转)堆heap和栈stack

    一 英文名称 堆和栈是C/C++编程中经常遇到的两个基本概念.先看一下它们的英文表示: 堆――heap 栈――stack 二 从数据结构和系统两个层次理解 在具体的C/C++编程框架中,这两个概念并不 ...

  8. 每日一问2:堆(heap)和栈(stack)的区别

    因为这里没有明确指出堆是指数据结构还是存储方式,所以两个尝试都回答一下. 一.堆和栈作为数据结构 1.堆(heap),也叫做优先队列(priority queue),队列中允许的操作是先进先出(FIF ...

  9. 最短路模板(Dijkstra & Dijkstra算法+堆优化 & bellman_ford & 单源最短路SPFA)

    关于几个的区别和联系:http://www.cnblogs.com/zswbky/p/5432353.html d.每组的第一行是三个整数T,S和D,表示有T条路,和草儿家相邻的城市的有S个(草儿家到 ...

  10. JVM的堆(heap)、栈(stack)和方法区(method)

    JVM主要由类加载器子系统.运行时数据区(内存空间).执行引擎以及与本地方法接口等组成.其中运行时数据区又由方法区Method Area.堆Heap.Java stack.PC寄存器.本地方法栈组成. ...

随机推荐

  1. input文本框 输入限制三则

    其一,只允许输入数字和小数点. <input onKeypress="return (/[\d.]/.test(String.fromCharCode(event.keyCode))) ...

  2. pyqt5猜数小程序

    程序界面用qt设计师制作,并用pyuic5命令转换成form.py文件 #-*- coding:utf-8 -*- from PyQt5.QtWidgets import QApplication,Q ...

  3. 8-3 4Values Whose Sum is Zero 和为0的四个值

    给定四个n元素集合 ABCD   要求分别从中取一个元素 abcd   使得他们的合为0   问有多少中取法 map果然炸了 #include<bits/stdc++.h> using n ...

  4. mysql 拾遗提高(函数、事务、索引)

    目录 1.tips 2.事务(transaction) 3.索引(index) 4.数据库的导出和备份 5.函数 6.防SQL注入 7.使用Explain分析SQL语句 8.视图(view) 1.ti ...

  5. Java 集合补充

    集合大致可以分List,Set,Queue,Map四种体系. 集合和数组不一样,数组元素可以是基本类型的值,也可以是对象(的引用变量),集合里只能保存对象(的引用变量). 访问:如果访问List集合中 ...

  6. PAGELATCH_EX Contention on 2:1:103

    This blog post is meant to help people troubleshoot page latch contention on 2:1:103. If that’s what ...

  7. javascript面向对象系列第五篇

    <style> .test{height: 50px;width: 50px;background-color: pink;position:absolute;} #test2{left: ...

  8. [ 转载 ] Centos 安装mysql后启动失败 出现 ERROR 2002 (HY000): Can’t connect to local MySQL server through socket ‘/var/lib/mysql/mysql.sock’

    MySQL Daemon failed to start Mysql出问题一定要学会查看log https://blog.csdn.net/shuai825644975/article/details ...

  9. MongoDB 进阶

    一.MongoDB 复制(副本集) MongoDB复制是将数据同步在多个服务器的过程. 复制提供了数据的冗余备份,并在多个服务器上存储数据副本,提高了数据的可用性, 并可以保证数据的安全性. 复制还允 ...

  10. HDU 4348 To the moon 主席树 在线更新

    http://acm.hdu.edu.cn/showproblem.php?pid=4348 以前做的主席树没有做过在线修改的题做一下(主席树这种东西正经用法难道不是在线修改吗),标记永久化比较方便. ...