图解数据结构——二叉堆
来源:互联网 发布:四大台柱 知乎 编辑:程序博客网 时间:2024/04/28 02:50
转载自图解数据结构(8)——二叉堆
================================================================================================================================
十二、二叉堆(Binary Heap)
经历了上一篇实现AVL树的繁琐,这篇就显得非常easy了。
首先说说数据结构概念——堆(Heap),其实也没什么大不了,简单地说就是一种有序队列而已,普通的队列是先入先出,而二叉堆是:最小先出。
这不是很简单么?如果这个队列是用数组实现的话那用打擂台的方式从头到尾找一遍,把最小的拿出来不就行了?行啊,可是出队的操作是很频繁的,而每次都得打一遍擂台,那就低效了,打擂台的时间复杂度为Ο(n),那如何不用从头到尾fetch一遍就出队呢?二叉堆能比较好地解决这个问题,不过之前先介绍一些概念。
完全树(Complete Tree):从下图中看出,在第n层深度被填满之前,不会开始填第n+1层深度,还有一定是从左往右填满。
再来一棵完全三叉树:
这样有什么好处呢?好处就是能方便地把指针省略掉,用一个简单的数组来表示一棵树,如图:
那么下面介绍二叉堆:二叉堆是一种完全二叉树,其任意子树的左右节点(如果有的话)的键值一定比根节点大,上图其实就是一个二叉堆。
你一定发觉了,最小的一个元素就是数组第一个元素,那么二叉堆这种有序队列如何入队呢?看图:
假设要在这个二叉堆里入队一个单元,键值为2,那只需在数组末尾加入这个元素,然后尽可能把这个元素往上挪,直到挪不动,经过了这种复杂度为Ο(logn)的操作,二叉堆还是二叉堆。
那如何出队呢?也不难,看图:
出队一定是出数组的第一个元素,这么来第一个元素以前的位置就成了空位,我们需要把这个空位挪至叶子节点,然后把数组最后一个元素插入这个空位,把这个“空位”尽量往上挪。这种操作的复杂度也是Ο(logn),比Ο(n)强多了吧?
尝试自己写写代码看,当然了,我也写(这个得动动手啦,比AVL容易多了):
#include "stdio.h"#define SWAP_TWO_INT(a, b) \a^=b; b^=a; a^=b;class CBinaryHeap{ public: CBinaryHeap(int iSize = 100); ~CBinaryHeap(); //Return 0 means failed. int Enqueue(int iVal); int Dequeue(int &iVal); int GetMin(int &iVal); #ifdef _DEBUG void PrintQueue(); #endif protected: int *m_pData; int m_iSize; int m_iAmount;};CBinaryHeap::CBinaryHeap(int iSize){ m_pData = new int[iSize]; m_iSize = iSize; m_iAmount = 0;}CBinaryHeap::~CBinaryHeap(){ delete[] m_pData;}#ifdef _DEBUGint CBinaryHeap::Enqueue(int iVal){ if(m_iAmount==m_iSize) return 0; //Put this value to the end of the array. m_pData[m_iAmount] = iVal; ++m_iAmount; int iIndex = m_iAmount - 1; while(m_pData[iIndex] < m_pData[(iIndex-1)/2]) { //Swap the two value SWAP_TWO_INT(m_pData[iIndex], m_pData[(iIndex-1)/2]) iIndex = (iIndex-1)/2; } return 1;}#endifint CBinaryHeap::Dequeue(int &iVal){ if(m_iAmount==0) return 0; iVal = m_pData[0]; int iIndex = 0; while (iIndex*2<m_iAmount) { int iLeft = (iIndex*2+1 < m_iAmount)?(iIndex*2+1):0; int iRight = (iIndex*2+2 < m_iAmount)?(iIndex*2+2):0; if(iLeft && iRight) // Both left and right exists. { if(m_pData[iLeft]<m_pData[iRight]) { SWAP_TWO_INT(m_pData[iIndex], m_pData[iLeft]) iIndex = iLeft; } else { SWAP_TWO_INT(m_pData[iIndex], m_pData[iRight]) iIndex = iRight; } } else if(iLeft) //The iRight must be 0 { SWAP_TWO_INT(m_pData[iIndex], m_pData[iLeft]) iIndex = iLeft; break; } else { break; } } //Move the last element to the blank position. //Of course, if it is the blank one, forget it. if(iIndex!=m_iAmount-1) { m_pData[iIndex] = m_pData[m_iAmount-1]; //Try to move this element to the top as high as possible. while(m_pData[iIndex] < m_pData[(iIndex-1)/2]) { //Swap the two value SWAP_TWO_INT(m_pData[iIndex], m_pData[(iIndex-1)/2]) iIndex = (iIndex-1)/2; } } --m_iAmount; return 1;}int CBinaryHeap::GetMin(int &iVal){ if(m_iAmount==0) return 0; iVal = m_pData[0]; return 1;}void CBinaryHeap::PrintQueue(){ int i; for(i=0; i<m_iAmount; i++) { printf("%d ", m_pData[i]); } printf("\n");}int main(int argc, char* argv[]){ CBinaryHeap bh; bh.Enqueue(4); bh.Enqueue(1); bh.Enqueue(3); bh.Enqueue(2); bh.Enqueue(6); bh.Enqueue(5); #ifdef _DEBUG bh.PrintQueue(); #endif int iVal; bh.Dequeue(iVal); bh.Dequeue(iVal); #ifdef _DEBUG bh.PrintQueue(); #endif return 0;}
- 图解数据结构——二叉堆
- 图解数据结构(8)——二叉堆
- 图解数据结构(8)——二叉堆
- 图解数据结构(8)——二叉堆
- 图解数据结构(8)——二叉堆
- 图解数据结构(8)——二叉堆
- 图解数据结构(8)——二叉堆
- 数据结构——二叉堆
- 数据结构(7)——二叉堆
- 数据结构与算法——二叉堆
- 数据结构——树(1)——二叉堆
- 数据结构学习——二叉堆ADT(程序化)
- Java数据结构与算法解析(十四)——二叉堆
- Java数据结构与算法解析(十四)——二叉堆
- 【数据结构】二叉堆(堆)
- 数据结构 二叉堆 & 堆排序
- 图解数据结构(7)——二叉查找树及平衡二叉查找树
- 图解数据结构(7)——二叉查找树及平衡二叉查找树
- 机房收费系统——概览
- 条款19 设计class 犹如设计type
- Spring事务配置的五种方式
- 软件设计师考点之-设计模式
- 新手使用长按手势将网络图片保存至系统相册出现的问题
- 图解数据结构——二叉堆
- APM相关
- 获取GridView中RowCommand的当前索引行
- (iOS软件开发UI部分)UIButton基本使用
- 面试题 10
- nth_element-第n小数
- Axure学习之简介
- JS中各种继承方式对比
- DataSet与实体类(转)