堆与优先队列

堆与优先队列

一、概念特性

–以最小堆为例

  • 最小堆是一个关键码序列(数组),第i个元素Ki,满足

    • Ki<=K2i+1
    • Ki<=K2i+2
  • 可以用完全二叉树来表示最小堆,即逻辑结构上来看,堆实际上是一种树形结构
    在这里插入图片描述

二、堆的定义
template class<T>
class MinHeap{
private 
 T* heapArray; // 存放堆数据的数组
 int CurrentSize; // 当前堆中元素数目
 int MaxSize; // 堆所能容纳的最大元素数目 
 void BuildHeap(); // 建堆
public:
 MinHeap(const int n)// 构造函数,n为最大元素数目
 virtual ~MinHeap(){delete []heapArray;}; // 析构函数
 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)// 向堆中插入新元素newNode
 T& RemoveMin()// 从堆顶删除最小值
 void SiftUp(int position); // 从position向上开始调整,使序列成为堆
 void SiftDown(int left)// 筛选法函数,参数left表示开始处理,使其成为堆
三、筛选法使数组(完全二叉树)成为堆

–注意这里仅仅是对某一个位置的元素进行位置的调整,整个数组的调整还需要用一个循环

从position位置向下筛选
  1. 将position记为i,并将其数据存放至temp中,

  2. 找到结点i的两个子节点中较小的数j,

  3. 判断j是否还在数组中(j与maxsize比较),在则将较小的数赋值给父结点,不在数组则5

  4. 令i=j,j=2*j+1,向下继续2

  5. 将1中方储存的temp中的值放到i结点中

    void MinHeap<T>::SiftDown(int position) {
     int i = position; // 标识父结点
     int j = 2*i+1; // 标识关键值较小的子结点
     T temp = heapArray[i]; // 保存父结点
     while (j < CurrentSize) {
      if((j < CurrentSize-1)&&(heapArray[j] > heapArray[j+1]))
        j++; // j指向数值较小的子结点
      if (temp > heapArray[j]) {
        heapArray[i] = heapArray[j];
        i = j;
        j = 2*j + 1; // 向下继续
        }
       else break;
     } 
     heapArray[i]=temp;
    }
    
从position向上调整
  • 同SiftDown类似,

    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]-1)开始用siftDown()函数依次调整,直到整个完全二叉树为一个最小堆

    template<class T>
    void MinHeap<T>:BuildHeap()
    {
     int i=CurrentSize/2-1;
     for(;i>=0;i--)
      SiftDown(i);//SiftDown()函数只对某一位置进行调整,使其满足最小堆的要求,要使整个数组为最小堆,要用一个循环,需要从倒数第二层最右端位置调用SiftDown()函数,直到头。
    }
    
    
插入元素
  • 判断数组是否满了
  • 将新元素加入数组的最后,用Siftup()向上调整heapArray[CurrentSize]=newNode;SiftUp(CurrentSize); // 向上调整
删除元素
  • 将数组的最后一个数拿到要删除的位置

  • 判断该数和其父结点的大小,如果大于其父结点的值,说明该结点和上面的结点的值摆放没问题,但其下面的数摆放必定出了问题因此从这个结点向下调整SiftDown,如果小于,同理,SiftUp

在这里插入图片描述

  • 上面这个例子,分别删除68 16 进行比较

    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];//数组个数CurrentSize个,最后一个表示为heapArray[CurrentSize-1]
        if(heapArray[pos]<heapArray[parent(pos)]
           SiftUp(pos);
         else 
           SiftDown(pos);
         node=temp
         return true;
    }
    
五、时间复杂度–时间代价
  • 时间代价为O(n)
  • 由于堆只有logn层,故删除、插入元素时间代价都为O(logn)
优先队列
  • 堆可以用于实现优先队列,根结点就是最大值或者最小值
  • 优先队列能让一个队列中,最小值(最大值)最先出队
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值