C ++ 实现大顶堆

堆这种数据结构在面试中还是经常容易被问到的,除了基本的堆排序,还有就是经典的TopK问题都可以用堆来实现。堆其实是一种完全二叉树。它可以方便的用数组来存储,而不是采用二叉链表存储。所以说堆底层维护的还是一个数组,只不过对其进行了封装。下面我们就来实现一个大顶堆吧。

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

template <typename Item>
class MaxHeap{
private:
    Item *data;
    int count;
    int capacity;
    // 对 数组中索引为k 位置的元素进行shiftUp操作
    void shiftUp(int k){
        while(k > 1 && data[k/2] < data[k]){
            swap(data[k/2], data[k]);
            k /= 2;
        }
    }
    void shiftDown(int k){
        while(2*k <= count){
            int j = 2*k; // j首先默认为左孩子
            // 下移操作时,如果既有左孩子,又有右孩子,应该与左右孩子中较大的交换
            if(j+1 <= count && data[j+1] > data[j]){
                j++;
            }
            if(data[k] >= data[j]){
                break;
            }
            swap(data[k], data[j]);
            k = j;
        }
    }

public:
    // 构造函数
    MaxHeap(int capacity){
        // 堆的底层其实是维护一个数组
        // 数组的0索引位置不放元素,从1索引位置放
        // 这样更清晰一些
        data = new Item[capacity + 1];
        count = 0;
        this -> capacity = capacity;
    }
    // 析构函数
    ~MaxHeap(){
        delete[] data;
    }

    int size(){
        return  count;
    }
    bool isEmpty(){
        return count == 0;
    }

    // 向堆中插入元素,插入元素后,堆仍然是一个堆
    void insert(Item item){
        // 断言 插入元素后不能超过数组的容量
        assert(count + 1 <= capacity);

        data[count + 1] = item;
        count++;
        shiftUp(count);

    }
    Item extractMax(){
        assert(count > 0);
        // 弹出 堆顶元素,
        Item ret = data[1];
        // 继续保持堆结构
        swap(data[1], data[count]);
        count--;
        shiftDown(1);

        return ret;
    }

    Item getMax(){
        assert( count > 0 );
        return data[1];
    }
};

堆这种数据结构,对入堆操作和弹出最大值操作的时间复杂度都是O(logN),通过这种平衡,使其得到很好的平衡。追重要的两个操作就是  shiftUp和shiftDown操作,其他的书籍中可能介绍的叫做heapAdjust操作。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值