博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
最小堆理解
阅读量:4364 次
发布时间:2019-06-07

本文共 5147 字,大约阅读时间需要 17 分钟。

简介

当一棵二叉树的每个结点都大于它的两个子结点时,被称为堆有序;

如果我们用指针来表示堆有序的二叉树,那么每个元素都需要三个指针来找到它的上下结点;但是如果我们使用完全二叉树,只用数组而不需要指针就可以表示;

什么是最小堆呢?

最小堆就是在二叉堆的基础上,符合了每个结点都比他的子结点要小的规则!

我们会遇到这两种情况,这也是最小堆中特别要注意的两种实现:

  • 上浮:从下至上恢复堆的顺序,在当某个节点的优先级上升时;
  • 下沉:从上至下恢复的顺序,当某个节点的优先级下降的时候;

我们可以从下面的图中观察最小堆是如何运行的:

99371821.jpg

只要不满足小的规则就交换

实现

1.上浮

先看上浮,其思想就是,因为是从下至上,所以根据当前结点,算出父亲结点,然后跟父亲结点进行比较,如果子结点小的话,则需要进行相互交换,反之不用,直到循环到下标到达结尾;

/** *  将end到0的数据都上浮 * *  @param end */void MinHeap::shiftUp(int end) {    int i = end;    while (i > 0) {        int parent = i % 2 == 0 ? i/2 - 1 : i/2;        if (heap[i] < heap[parent]) {            swap(&heap[i], &heap[parent]);            i = parent;        }        else {            --i;        }    }}

2.下沉

接着看下沉,其思想就是,因为是从上至下,所以根据当前结点,算出左右子结点,然后跟当前结点进行比较,如果左右结点小,这里需要注意的是,取左右子结点中小的进行交换,因为其中必然会有三者之中的最小值,反之不用,直到循环到下标到达0;

/** *  将start到end的数据都往下沉 *  将子结点和父结点进行比较 * *  @param start <#start description#> *  @param end   <#end description#> */void MinHeap::shiftDown(int start, int end) {    int i = start;    while (i < end) {        int lchild = i*2 + 1, rchild = i*2 + 2;                if ((heap[i] > heap[lchild] && lchild < currentSize) || (heap[i] > heap[rchild] && rchild < currentSize)) {            bool leftSmall = heap[lchild] < heap[rchild];                        if (leftSmall) {                swap(&heap[i], &heap[lchild]);                i = lchild;            }            else {                swap(&heap[i], &heap[rchild]);                i = rchild;;            }        }        else {            ++i;        }    }}

3.插入删除

还有一个需要注意的点是插入删除;

  • 插入:插到数组的最后一个位置上,增加堆大小,并且上浮;
  • 删除:将数组头元素用数组尾元素进行替换,减小堆大小,并且下沉;

4.整体实现

////  main.cpp//  Heap////  Created by George on 16/11/1.//  Copyright © 2016年 George. All rights reserved.//#include 
#define DefaultSize 10#define Log(content) { std::cout << "Log:" << content << std::endl; }class MinHeap {public: MinHeap(int size = DefaultSize); ~MinHeap(); inline bool isEmpty() { return currentSize == 0; }; inline bool isFull() { return currentSize == maxSize; }; bool insert(const int value); bool removeMin(); int poll(); void shiftDown(int start, int end); void shiftUp(int end); void toString(); private: int * heap; int currentSize; int maxSize; void swap(int *num1, int *num2);};MinHeap::MinHeap(int size) : currentSize(0) { heap = new int[size]; maxSize = size > DefaultSize ? size : DefaultSize;}MinHeap::~MinHeap() { }void MinHeap::toString() { for (int i = 0; i < currentSize; ++i) { std::cout << heap[i] << std::endl; }}void MinHeap::swap(int *num1, int *num2) { int temp = *num1; *num1 = *num2; *num2 = temp;}/** * 将start到end的数据都往下沉 * 将子结点和父结点进行比较 * * @param start <#start description#> * @param end <#end description#> */void MinHeap::shiftDown(int start, int end) { int i = start; while (i < end) { int lchild = i*2 + 1, rchild = i*2 + 2; if ((heap[i] > heap[lchild] && lchild < currentSize) || (heap[i] > heap[rchild] && rchild < currentSize)) { bool leftSmall = heap[lchild] < heap[rchild]; if (leftSmall) { swap(&heap[i], &heap[lchild]); i = lchild; } else { swap(&heap[i], &heap[rchild]); i = rchild;; } } else { ++i; } }}/** * 将end到0的数据都上浮 * * @param end */void MinHeap::shiftUp(int end) { int i = end; while (i > 0) { int parent = i % 2 == 0 ? i/2 - 1 : i/2; if (heap[i] < heap[parent]) { swap(&heap[i], &heap[parent]); i = parent; } else { --i; } }}/** * 删除最小值,也就是堆顶,用最大值替代,并且下沉 * * @return <#return value description#> */bool MinHeap::removeMin() { if (currentSize == 0) { Log("current size is 0!"); return false; } heap[0] = heap[currentSize-1]; --currentSize; shiftDown(0, currentSize-1); return true;}/** * 插入值后要进行上浮 * * @param value <#value description#> * * @return <#return value description#> */bool MinHeap::insert(const int value) { if (currentSize == maxSize) { int *nHeap = heap; heap = new int(maxSize + 10); for (int i = 0; i < maxSize; ++i) { heap[i] = nHeap[i]; } delete [] nHeap; Log("heap is resize!"); } heap[currentSize++] = value; shiftUp(currentSize-1); return true;}/** * 取得堆顶值 * * @return <#return value description#> */int MinHeap::poll() { if (isEmpty()) { Log("heap is null!"); return -1; } return heap[0];}int main(int argc, const char * argv[]) { // insert code here... MinHeap Heap; Log("------------Insert------------"); int arr[8] = {8, 7, 6, 5, 4, 3, 2, 1}; for (int i = 0; i < 8; i++) { Heap.insert(arr[i]); } Heap.toString(); Log("------------Remove------------"); Heap.removeMin(); Heap.toString(); Log("------------Get------------"); std::cout << "poll:" << Heap.poll() << std::endl; return 0;}

看结果:

9815404.jpg

转载于:https://www.cnblogs.com/George1994/p/6399887.html

你可能感兴趣的文章
div+css 设计下拉
查看>>
模拟公交站台竖直排列,两端对齐
查看>>
JavaScript dom 标签属性
查看>>
CSS半透明边框
查看>>
进程上下文和中断上下文
查看>>
unity GUI GUILayout 水平 垂直布局
查看>>
Luogu P2845 [USACO15DEC]Switching on the Lights 开关灯(bfs)
查看>>
潭州课堂25班:Ph201805201 tornado 项目 第六课 用户和图片分享的集成(课堂笔记)...
查看>>
潭州课堂25班:Ph201805201 django 项目 第九课 图片验证码前台实现,判断用户是否注册功能实现 (课堂笔记)...
查看>>
centos7下面ruby的升级
查看>>
札记-20190531
查看>>
简练软考知识点整理-项目监控过程组
查看>>
排序算法 - 函数 Char* Revert(Char* pStr),将字符串pStr逆序
查看>>
Vue.js Client-Side Storage;( Web Storage/localStorage)
查看>>
JavaWeb学习总结(四十九)——简单模拟Sping MVC
查看>>
XOR (莫队)
查看>>
开发环境,生产环境,测试环境的区别
查看>>
|洛谷|排序|P1309 瑞士轮
查看>>
Java简介
查看>>
简单排序实现
查看>>