最大堆与最小堆与优先队列

堆的定义及其实现

最小堆:最小堆是一个关键码序列{ K0,K1,...Kn-1},它具有如下特性:

  • Ki ≤K2i+1
  • Ki≤K2i十2
  • 类似可以定义最大堆

堆的性质

  • 可以看出是完全二叉树
  • 堆中的数据是局部有序的,堆不唯一
    • 兄弟节点之间没有限制
  • 从逻辑结构来看堆实际上是树形结构

最小堆的类定义(ADT)

template <class T> class MinHeap { 
private:
    T* heapArray;
    int CurrentSize; 
    int MaxSize;
    void BuildHeap();
public:
    MinHeap(const int n);  //构造函数,n为最大元素数目
    virtual ~MinHeap(){delete []heapArray;};   // 析构函数
    bool isLeaf(int pos) const;
    int leftchild(int pos) const;
    int rightchild(int pos) const;
    int parent(int pos) const;
    bool Remove(int pos, T& node); 
    bool Insert(const T& newNode); 
    T& RemoveMin();// 从堆顶删除最小值
    void SiftUp(int position); // 从position向上开始调整,使序列成为堆
    void SiftDown(int left);// 筛选法函数,参数left表示开始处理的数组下标
 }
复制代码
堆最小堆使用SiftDown和SiftUp
template<class T>
void MinHeap<T>::SiftDown(int position){
	int i = position;
	int j = 2*i+1;//先指向左子节点,但最终存储的是最小子节点
	Temp = headArray[i];
	while(j<CurrentSize){
		if(j<CurrentSize-1 && headArray[j]>headArray[j+1])
			j++;  //最小节点
		if(Temp > headArray[j])
		{
			headArray[i] = headArray[j];  //注意此处j的值不变,以用来其他的值替换
			i=j;
			j=2*i+1;   //继续下降&emsp;
		}
		else break;
	}
	headArray[j] = Temp;
}

template<class T>
void MinHeap<T>::SiftUp(int position) {
	// 从position向上开始调整,使序列成为堆
	int temppos=position;
	// 不是父子结点直接swap
	T temp=heapArray[temppos];
	while((temppos>0) && (heapArray[parent(temppos)] > temp)) {
	heapArray[temppos]=heapArray[parent(temppos)]; temppos=parent(temppos);
	}
	heapArray[temppos]=temp;// 找到最终位置 
}
复制代码

建最小堆过程

首先,将 n 个关键码放到一维数组中

  • 整体不是最小堆
  • 所有叶结点子树本身是堆
  • 当i≥[n/2]时,以关键码 Ki 为根的子树已经是堆
  • 从倒数第二层,i = [n/2- 1] 开始
    • 从右至左依次调整
  • 直到整个过程到达树根
    • 整棵完全二叉树就成为一个堆

实现上比较简单: 首先初始化堆,然后从第一个分支结点heapArray[CurrentSize/2-1]开始,自底向上逐步把以子树调整成堆

template<class T>
void MinHeap<T>::BuildHeap(){
	for(int i=CurrentSize/2 -1;i>=0;i--){
		SiftDown(i);
	}
}
复制代码

插入:

template <class T>
bool MinHeap<T>::Insert(const T& newNode)
{
	//向堆中插入新元素newNode {
	if(CurrentSize==MaxSize) return false;
	// 堆空间已经满
	heapArray[CurrentSize]=newNode; 
	SiftUp(CurrentSize); // 向上调整 
	CurrentSize++;
}
复制代码

删除

template<class T>
bool MinHeap<T>::Remove(int pos, T& node) {
    if((pos<0)||(pos>=CurrentSize)) 
    return false;
    T temp=heapArray[pos]; 
    heapArray[pos]=heapArray[--CurrentSize]; 
    if (heapArray[parent(pos)]> heapArray[pos])
        SiftUp(pos); //上升筛
    else SiftDown(pos); // 向下筛 node=temp;
    return true;
}
复制代码

时间复杂度

建堆效率分析 n个结点的堆,高度d=log2n+1。 根为第 0 层,则第 i 层结点个数为 2i, 考虑一个元素在堆中向下移动的距离。

  • 大约一半的结点深度为d-1,不移动(叶)。
  • 四分之一的结点深度为d-2,而它们至多能向下移动一层。
  • 树中每向上一层,结点的数目为前一层的一半,而子 树高度加一。因而元素移动的最大距离的总数为

堆有logN层深,所以插入删除的平均时间和最差时间都是O(logN)

最大最小堆

能在一个数据结构中同时维护最大值和最小值. 最小最大堆是一棵完全二叉树,且其中每个元素有一个key数据成员。

树的各层交替为最小层和最大层。

根结点在最小层。

设x是最小最大堆的任意结点。若x在最小(最大)层上,则x中的元素的key值在以x为根的子树的所有元素中是最小(最大)的。位于最小(最大)层的结点称为最小(最大)结点。

优先队列(priority_queue)

可以看出,堆可以用于实现优先队列。

  • 优先队列
    • 根据需要释放具有最小(大)值的对象
    • 最大树、 左高树HBLT、WBLT、MaxWBLT
  • 改变已存储于优先队列中对象的优先权
    • 辅助数据结构帮助找到对象

C++优先队列容器与队列一样,只能从队尾添加(插入)元素,从队头(队首)删除元素。但他有一个特性,就是队列中最大的元素总是位于队首,所以出队时,并非按先进先出的原则进行,而是将当前队列中最大的元素出队。

这点类似与给队列里的元素进行了由大到小的顺序排序。

元素的比较规则默认为按元素的值的由大到小排序;当然,可以重载“<”操作符来重新定义比较规则(也就是最大堆与最小堆)。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值