二叉堆

5 阅读2分钟

代码

#include <iostream>
#include <functional>
#include <string.h>
#include <stdlib.h>
#include <time.h>

using namespace std;

// 优先级队列实现
class PriorityQueue {

public:
  using Comp = function<bool(int, int)>;
  PriorityQueue(int cap = 20, Comp comp = greater<int>()) // 默认是大根堆
        : size_(0)
        , cap_(cap)
        , comp_(comp) {
          que_ = new int[cap_];
        };

  PriorityQueue(Comp comp)
  : size_(0)
  , cap_(20)
  , comp_(comp) {
    que_ = new int[cap_];
  };

  ~PriorityQueue() {
    delete[] que_;
    que_ = nullptr;
  };

public:
  // 入堆操作
  void push(int val) {

    // 是否需要扩容
    if (size_ == cap_) {
      int* p = new int[2 * cap_];
      memcpy(p, que_, cap_ * sizeof(int));
      delete[]que_;
      que_ = p;
      cap_ *= 2;
    }

    if (size_ == 0) {
      // 只有一个元素,不用进行堆的上浮调整
      que_[size_] = val;
    } else {
      // 堆里面有多个元素,需要进行上浮调整
      siftUp(size_, val);
    }
    size_++;
  }


  // 出堆操作
  void pop() {
    if (size_ == 0) {
      throw "empty";
    }

    size_--;

    if (size_ > 0) {
      // 删除堆顶元素,还有剩余的元素,要进行堆的下沉调整
      siftDown(0, que_[size_]);
    }
  }


  // 判断空
  bool empty() const { return size_ == 0; }


  // 获取堆顶元素
  int top() const {
    if (size_ == 0) {
      throw "empty";
    }

    return que_[0];
  }

  // 元素个数
  int size() const {
    return size_;
  }


private:
  // 入堆上浮调整
  void siftUp(int i, int val) {
    while (i > 0) // 最多计算到根节点
    {
      int father = (i - 1) / 2;  // 计算父节点

      if (comp_(val, que_[father])) {
        que_[i] = que_[father];  // 调整父节点数据位置

        i = father;  // 接着进行比较
      } else {
        break;  // 满足关系了,跳出
      }
    }

    // 把val放到i的位置
    que_[i] = val;
    
  }

  // 出堆下沉调整
  void siftDown(int i, int val) {
    while (i <= (size_ - 1 - 1) / 2) {  // 与子节点进行比较,没子节点的话就不用比较了
      int child = 2 * i + 1; // 第i个节点的左孩子

      if (child + 1 < size_ && comp_(que_[child + 1], que_[child])) {
        // 如果i节点右孩子大于左孩子,child记录右孩子的下标
        child = child + 1;
      }

      if (comp_(que_[child], val)) {
        que_[i] = que_[child];
        i = child;
      } else {
        break;  // 已经满足堆的性质,提前结束
      }
    }

    que_[i] = val;
  }

private:
  int* que_;  // 指向动态扩容的数组
  int size_;  // 数组元素的个数
  int cap_;   // 数组的总内存空间大小
  Comp comp_;  // 比较器对象

};

int main() {
  PriorityQueue que;
  srand(time(NULL));

  for (int i = 0; i < 10; i++) {
    que.push(rand() % 100);
  }

  while (!que.empty())
  {
    cout << que.top() << " ";
    que.pop();
  }
  
  cout << endl;

}

测试

➜  build git:(main) ✗ ./BinaryHeap 
98 97 71 70 63 54 34 23 7 3