堆的定义是:n个元素的序列{k1,k2,…,kn},当且仅当满足如下关系时被成为堆
- Ki <= k2i 且 ki <= k2i-1 或者
- Ki >= k2i 且 ki >= k2i-1 (i = 1,2,…[n/2])
当满足(1)时,为最小堆,当满足(2)时,为最大堆。
若将此序列对应的一维数组堪称是一个完全二叉树,则2i和2i+1个节点分别是节点i的左右子节点。
如下为一个最大堆:
下面以最小堆为例说明堆的输出:
图1为一个最小堆,当最小节点根节点13输出后,将最后一个节点97作为根节点,移到顶端,如图2. 然后要对堆进行调整。比较此完全树的根节点与其两个子节点大小,因为27 < 38 < 97,所以27是三个节点里最小的,将节点27与根节点97交换。此时以97替代27而产生的右子树为一个新的堆,再以97为根节点,对此最小堆进行调整,同理,知道要将97与49交换,得到图3的完全树。此时以97代替49为根节点的右子树为一个新堆,再对此堆做同样的操作,因为此完全树已经是最小堆,所以可以停止操作,堆的调整完毕。此时再将根节点,对的最小值输出,并进行同样的调整,可以得到如图4的新堆。这个过程被称为“筛选”。
同样以最小堆说明堆的初始化:
从一个无序序列初始化为一个堆的过程就是一个反复“筛选”的过程。由完全二叉树的性质可以知,一个有n个节点的完全二叉树的最后一个非叶节点是节点[n/2],堆的初始化过程就从这个[n/2]节点开始。上图为如下无序数组的初始化:
{49,38,65,97,76,13,27,50}
首先,未处理的数组对应的堆为图1模样。从第四个节点开始([8/2]=4),因为50 < 97,故要交换两节点,交换后还要继续对其新的左子树进行类似输出后那样的筛选。易见其左子树只有节点97,已经为最佳情况,故可以继续堆的初始化,如图2。再考虑第三个节点,因为13 < 27 < 65,即节点13为当前的最小节点,故与节点65交换,并对新的左子树进行筛选,其也为最佳情况,故可继续堆的初始化,结果如图3。然后考虑第二个节点,因为38 < 50 < 76,故已经为最优情况,不用调整。最后再考虑第一个节点,根节点。因为 13 < 38 < 49,故需要将根节点49与其右孩子节点13交换,交换后还要继续对其新的右子树进行类似输出后那样的筛选,可见右子树还需要调整,因为 27 < 49 < 65,故将节点49与节点27交换。此时已经处理完了根节点,初始化结束。最终结果如图5.
package heap; public class Node { private int iData; // 结点数据是整型 public Node(int key) { iData = key; } public void setKey(int id) { iData = id; } public int getKey() { return iData; } }
package heap; public class MinHeap { private Node[] heapArray; // 堆容器 private int maxSize; // 堆得最大大小 private int currentSize; // 堆大小 public MinHeap(int _maxSize) { maxSize = _maxSize; heapArray = new Node[maxSize]; currentSize = 0; } /** * 自上而下调整 * * @param start * @param endOfHeap */ public void filterDown(int start, int endOfHeap) { int i = start; int j = 2 * i + 1; // j是i的左子女位置 Node temp = heapArray[i]; while (j <= endOfHeap) { // 检查是否到最后位置 if (j < endOfHeap // 让j指向两子女中的小者 && heapArray[j].getKey() > heapArray[j + 1].getKey()) { j++; } if (temp.getKey() <= heapArray[j].getKey()) { // 小则不做调整 break; } else { // 否则小者上移,i,j下降 heapArray[i] = heapArray[j]; i = j; j = 2 * j + 1; } } heapArray[i] = temp; } /** * 自下而上的调整:从结点start开始到0为止,自下向上比较,如果子女的值小于双亲结点的值则互相交换 * * @param start */ public void filterUp(int start) { int j = start; int i = (j - 1) / 2; Node temp = heapArray[j]; while (j > 0) { // 沿双亲结点路径向上直达根节点 if (heapArray[i].getKey() <= temp.getKey()) {// 双亲结点值小,不调整 break; } else {// 双亲结点值大,调整 heapArray[j] = heapArray[i]; j = i; i = (i - 1) / 2; } heapArray[j] = temp; // 回送 } } /** * 堆中插入结点 * * @param key * @return * @throws MinHeapException */ public boolean insert(int key) throws MinHeapException { boolean bool = true; if (isFull()) { bool = false; throw new MinHeapException("MinHeap is full!"); } else { Node newNode = new Node(key); heapArray[currentSize] = newNode; filterUp(currentSize); currentSize++; } return bool; } /** * 删除堆中的最小值 * * @return * @throws MinHeapException */ public Node removeMin() throws MinHeapException { if (isEmpty()) { throw new MinHeapException("MinHeap is empty!"); } Node root = heapArray[0]; heapArray[0] = heapArray[currentSize - 1]; currentSize--; filterDown(0, currentSize - 1); return root; } /** * 按某种格式输出堆 */ public void displayHeap() { System.out.print("heapArray: "); for (int i = 0; i < currentSize; i++) { if (heapArray[i] != null) { System.out.print(heapArray[i].getKey() + " "); } else { System.out.print("-- "); } } System.out.println(); int nBlanks = 32; // heap format int itemsPerRow = 1; int column = 0; int j = 0; // current item String dots = "..............................."; System.out.println(dots + dots); // dotted top line while (currentSize > 0) { // for each heap item if (column == 0) { // first item in row for (int k = 0; k < nBlanks; k++) { // preceding blanks System.out.print(" "); } } System.out.print(heapArray[j].getKey()); // display item if (++j == currentSize) { // done? break; } if (++column == itemsPerRow) { // end of row? nBlanks /= 2; // half the blanks itemsPerRow *= 2; // twice the items column = 0; // start over on System.out.println(); // next row } else { // next item on row for (int k = 0; k < nBlanks * 2 - 2; k++) { System.out.print(' '); // interim blanks } } } System.out.println("\n" + dots + dots); } public boolean isEmpty() { return currentSize == 0; } public boolean isFull() { return currentSize == maxSize; } public void makeEmpty() { currentSize = 0; } }
package heap; public class MinHeapException extends Exception { public MinHeapException() { super("MinHeapException"); } public MinHeapException(String exMsg) { super(exMsg); } }
package heap; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; public class MinHeapApp { /** * @param args * @throws IOException * @throws MinHeapException */ public static void main(String[] args) throws IOException, MinHeapException { int value, value2; MinHeap hp = new MinHeap(31); boolean success; hp.insert(53); hp.insert(17); hp.insert(78); hp.insert(9); hp.insert(45); hp.insert(65); hp.insert(87); hp.insert(23); while (true) { System.out.print("Enter first letter of "); System.out.print("show, insert, remove: "); int choice = getChar(); switch (choice) { case 's': hp.displayHeap(); break; case 'i': System.out.print("Enter value to insert: "); value = getInt(); success = hp.insert(value); if (!success) { System.out.println("Can't insert; heap is full"); } break; case 'r': if (!hp.isEmpty()) { hp.removeMin(); } else { System.out.println("Can't remove; heap is empty"); } break; default: System.out.println("Invalid entry\n"); } } } /** * 获得控制台输入流 * * @return * @throws IOException */ public static String getString() throws IOException { return new BufferedReader(new InputStreamReader(System.in)).readLine(); } /** * 获得控制台输入字符 * * @return * @throws IOException */ public static char getChar() throws IOException { return getString().charAt(0); } /** * 获得控制台输入整型 * * @return * @throws NumberFormatException * @throws IOException */ public static int getInt() throws NumberFormatException, IOException { return Integer.parseInt(getString()); } }
分享到:
相关推荐
堆有两种主要类型:最大堆和最小堆。最大堆确保每个父节点的值都大于或等于其子节点的值,而最小堆则相反,每个父节点的值都小于或等于其子节点的值。这两种类型的堆在各种算法中都有应用,例如优先级队列、排序和...
最小堆是一种特殊的树形数据结构,它满足堆的特性:每个父节点的值都小于或等于其所有子节点的值。这种性质使得最小堆在顶部(根节点)总是保持着当前堆中最小的元素,因此得名“最小堆”。在计算机科学中,最小堆常...
c++ 最小堆 还不错 标准库没有 自己做作业用。
在Prim算法的主体部分,首先创建一个最小堆`tt`,初始化所有顶点未加入最小生成树,然后从指定顶点`u`开始,每次从最小堆中取出权重最小的边,将该边的另一个顶点加入到最小生成树中,直到所有顶点都被包含。...
最小堆是一种特殊的树形数据结构,它满足堆的特性:每个节点的值都小于或等于其子节点的值。在最小堆中,根节点总是所有节点中最小的元素。这种数据结构在计算机科学中有着广泛的应用,特别是在排序算法(如优先队列...
最小堆是一种数据结构,常用于优先队列的实现,它能够快速地插入元素和删除最小元素。在解决TSP问题时,最小堆可以用来存储待访问的城市及其距离信息,以确保每次总是选择当前最短距离的城市进行访问。 在TSP的最小...
利用最小堆编程实现给定权值集合下构造相应霍夫曼树的算法,并解决以下问题: 有一电文共使用五种字符a,b,c,d,e,其出现频率依次为4,7,5,2,9。 (1)构造对应的编码哈夫曼树(要求左子树根结点的权小于等于右子树根结点...
最小堆是一种特殊的树形数据结构,它满足堆的特性:每个节点的值都小于或等于其子节点的值。在数组表示法中,如果我们将数组看作是一棵树,那么根节点(数组的第一个元素)是最小的。这种数据结构在算法和计算机科学...
这个算法的核心思想是通过构建一个最小堆(Min Heap)来实现。在本文中,我们将深入探讨哈夫曼编码的原理、最小堆的概念以及如何将它们结合应用于文件写入和输出。 首先,让我们理解哈夫曼编码的基本概念。哈夫曼...
利用最小堆编程实现给定权值集合下构造相应霍夫曼树的算法,并解决以下问题: 有一电文共使用五种字符a,b,c,d,e,其出现频率依次为4,7,5,2,9。 (1)构造对应的编码哈夫曼树(要求左子树根结点的权小于等于右子树根结点...
本主题主要探讨了两种关键的数据结构:搜索二叉树和最小堆,这两种数据结构在实际编程和算法设计中都有着广泛的应用。 搜索二叉树,也称为二叉查找树,是一种特殊的二叉树,其每个节点都具有以下特性: 1. 左子树中...
堆可以分为最大堆和最小堆,最大堆中每个父节点的值都大于或等于其子节点的值,而最小堆则相反,每个父节点的值小于或等于子节点的值。 首先,我们需要理解堆的基本操作。建堆通常从最后一个非叶子节点开始,按照从...
利用最小堆 进行迷宫搜索 class CMinHeap { public: CMinHeap(int nSize) { m_pHeap = new tagPosition[nSize+1]; m_nLast = 0; } void Push(const tagPosition& x) { int i = ++m_nLast; ...
poj2823 最大最小堆实现,话说这题为啥要用最大最小堆。
2. **最小堆**:最小堆是一种特殊的完全二叉树,每个节点的值小于或等于其子节点的值,堆顶元素是最小值。插入和查找的时间复杂度分别为O(log n)和O(1),删除虽然为O(log n),但通过辅助数据结构可以加速。最小堆...
本文将深入探讨两种特定的排序算法——选择排序和堆排序,并重点解析堆排序如何利用最小堆来实现排序过程。这两种算法在Java编程语言中都有广泛应用。 首先,我们来看选择排序。它是一种简单直观的排序算法,其基本...
最小堆排序是一种基于比较的排序算法,其核心思想是利用数据结构中的“堆”来实现。在计算机科学中,堆通常被定义为一个完全二叉树,其中每个父节点的值都小于或等于其子节点的值,这样的堆称为最大堆;反之,如果每...
二叉堆是一种特殊的完全二叉树,它分为两种类型:最大堆和最小堆。在最大堆中,每个节点的值都大于或等于其子节点的值,根节点是整个堆中最大的元素。相反,在最小堆中,每个节点的值都小于或等于其子节点的值,根...
本人编写的堆排序及堆的插入删除等操作演示,用的是java swing,详情可以查看 http://blog.csdn.net/cdnight/article/details/11714005 假如您对堆排序不是很熟悉,可以查看 ...
本资源是数据结构中利用最小堆实现哈夫曼树的一个C++代码,仅供参考,欢迎指正