数据结构:堆

1 基本概念

  • 堆是一颗完全二叉树
  • 完全二叉树:
    在这里插入图片描述
  • 大顶堆:父节点的值总是大于子节点
  • 小顶堆:父节点的值总是小于子节点

2 相关操作

从小顶堆来描述

2.1 插入操作:

步骤:

  • (1) 在树的叶子节点的一个空闲位置创建一个空穴,把插入的X放入空穴:【对应到数组操作就是在末尾添加元素】
  • (2) 如果此时堆结构不被破坏(X大于等于父节点),插入完成。否则进行步骤(3)
  • (3) 与父节点交换。返回到步骤(2)。
    在这里插入图片描述

2.2 删除操作:

一般都是删除堆顶的元素
步骤:

  • (1) : 把根元素移除,形成空穴,把最后的元素,也就是值最大的元素放置在空穴的位置。【对应到数组的操作就是,把数组最后一位覆盖第一位的值,数组长度-1】
  • (2) : 判断此时堆结构有无破坏。(父节点是否小于子节点)如果没有,删除结束,否则进行第三步。
  • (3): 把此时的父节点与最小的子节点进行交换,转到第二步。

2.3 源程序

#include <vector>
#include <iostream>
using namespace std;

template<typename T>
class cmp{
public:
    bool operator()(T a, T b){
        return a > b;
    }
};

//小顶堆
template<typename T, class F>
class heap{
public:
    std::vector<T> h;
    F f;
public:
    heap():numOfHeap(0){}
    ~heap() = default;
    //插入元素
    void insert(T num);
    //删除根节点元素,并返回根节点的值
    T deleteNode();

private:
    //调整位置为pos的元素,up代表向上调整,返回调整后的位置
    int adjest(int pos, bool up);
    //
    int numOfHeap;
};

template<typename T, class F>
void heap<T, F>::insert(T num){
    //首先添加到尾部
    h.push_back(num);
    ++numOfHeap;
    int n = numOfHeap - 1;
    //如果n位置的父节点比他还大,就说明需要调整
    while(f(num, h[(n-1)/2])){
        n = adjest(n, true);
    }
    
    
}

template<typename T, class F>
int heap<T, F>::adjest(int pos, bool up){
    //上行操作
    if(up){
        //交换父节点和本节点
        T temp = h[(pos-1)/2];
        h[(pos-1)/2] = h[pos];
        h[pos] = temp;
        //返回交换之后的节点位置
        return (pos-1)/2;
    } else {
        //交换较小的子节点
        if(pos * 2 + 2 < numOfHeap && f(h[pos * 2 + 2], h[pos * 2 + 1])){
            //交换子节点和本节点
            T temp = h[pos * 2 + 2];
            h[pos * 2 + 2] = h[pos];
            h[pos] = temp;
            //返回交换之后的节点位置
            return pos * 2 + 2;
        } else {
            //交换子节点和本节点
            T temp = h[pos * 2 + 1];
            h[pos * 2 + 1] = h[pos];
            h[pos] = temp;
            //返回交换之后的节点位置
            return pos * 2 + 1;
        }
    }
}

template<typename T, class F>
T heap<T, F>::deleteNode(){
    if(h.empty()){
        return false;
    }
    T res = h[0];
    h[0] = h[numOfHeap - 1];
    
    h.pop_back();
    --numOfHeap;
    int n = 0;
    while((n*2 + 1 < numOfHeap && f(h[n *2 +1], h[n])) || (n*2 + 2 < numOfHeap && f(h[n *2 + 2], h[n]))){
        n = adjest(n, false);
    }
    return res;
}


int main(int argc, char *argv[]){
    heap<int, cmp<int>> h0;
    for(int i = 12; i != 0; --i)
        h0.insert(i);
    
    while(!h0.h.empty()){
        cout << h0.deleteNode() << " ";
    }
    cout << endl;

    
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值