C ++ 实现大顶堆

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

#include 
#include 
using namespace std;

template 
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操作。

你可能感兴趣的:(C++)