最大堆, 最小堆, priority_queue

  • 最大堆,最小堆

    最大堆:每个节点的孩子节点都小于该节点
    最小堆:每个节点的孩子节点都大于该节点

    由于堆是一棵完全二叉树,所以

    1. 如果堆中的节点i有左右孩子节点,则:
      左孩子节点:i x 2 + 1
      右孩子节点:i x 2 + 2
    2. 如果堆中的节点j有父节点,则:
      父节点:(j-1)/2
    • 建立最大堆:

      • 从最后的非叶子节点开始调整堆,一直到根节点
      • 以某个节点为根,调整堆
        a. 如果孩子节点大于该节点,将该节点与左右孩子节点中最大的节点交换,然后调整其孩子节点
        b. 否则,无需调整
        c. 反复这个过程,直至叶子节点或者直至无需调整
      void AdjustHeap(std::vector<int> & heap, int cur, int length)
      {
          int left = cur * 2 + 1, right = cur * 2 + 2;
          int large = cur;
          if (left < length && heap[left] > heap[large]) {
              large = left;
          }
          if (right < length && heap[right] > heap[large]) {
              large = right;
          }
      
          if (large != cur) {
              std::swap(heap[large], heap[cur]);
              AdjustHeap(heap, large, length);
          }
      }
      
      //从最后的非叶子节点开始调整堆,一直到根节点
      void buildHeap(std::vector<int> & data)
      {
          for(int i = (data.size() - 1 - 1)>> 1; i >= 0; i--) {
              AdjustHeap(data, i, data.size());
          }
      }
      
    • AdjustHeap的非递归方式:

      • 使用循环, 找到每个需要调整的孩子节点,直至当前节点找到合适的位置
      void AdjustHeap_NotRec(std::vector<int> & heap, int cur, int length)
      {
          int large = cur;
          for (int child = cur * 2 + 1; child < length; child = cur * 2 + 1) {
              if (heap[child] > heap[large]) {
                  large = child;
              }
              child++;
              if (child < length && heap[child] > heap[large]) {
                  large = child;
              }
              if (large != cur) {
                  std::swap(heap[large], heap[cur]);
                  cur = large;
              } else {
                  break;
              }
          }
      }
      
    • 堆排序:

      • 将每个根节点与最后的节点交换,然后调整除开最后一个节点的数据为最大堆
      void sortHeap(std::vector<int> & data)
      {
          int length = data.size();
          for(int i = data.size() - 1; i >= 0; i--) {
              std::swap(data[i], data[0]);
              AdjustHeap(data, 0, length - 1);
              --length;
          }
      }
      

      ps:如果寻找第k个最大值,可以将for循环的条件为:i > data.size() - k,并且返回data[0]

    • 在堆中加入节点:

      • 将节点加入到数据中
      • 向上调整节点,将该节点交换到可以到达的最靠近根的地方
      void pushHeap(std::vector<int> & data, int num)
      {
          data.push_back(num);
      
          int cur = data.size() - 1;
          for (int parent = (cur - 1) >> 1; parent >= 0; parent = parent >> 1) {
              if (data[cur] > data[parent]) {
                  std::swap(data[cur], data[parent]);
                  cur = parent;
              } else {
                  break;
              }
          }
      }
      
    • 验证的main:

      int main(int argc, char * argv[])
      {
          std::vector<int> data = {3, 2, 3, 1, 2, 4, 5, 5, 6};
      
          buildHeap(data);
          pushHeap(data, 8);
          sortHeap(data);
      
          for(auto & num : data) {
              std::cout << num << " ";
          }
          std::cout << std::endl;
          return 0;
      }
      

      输出:

      1 2 2 3 3 4 5 5 6 8
      
  • priority_queue

    在c++中,可以通过优先队列priority_queue这个类管理最大堆或者最小堆。
    其头文件在<queue>中,定义如下:
    priorityqueuepriority_queue<T, Container, std::less<T>>为最大堆
    priority_queue<T, Container, std::greater<T>>为最小堆

    #include <iostream>
    #include <queue>
    #include <vector>
    
    template<typename T>
    void print_queue(T q)
    {
        while(!q.empty()) {
            std::cout << q.top() << " ";
            q.pop();
        }
        std::cout << std::endl;
    }
    
    int main(int argc, char * argv[])
    {
        const auto data = {3, 2, 3, 1, 2, 4, 5, 5, 6};
    
        std::priority_queue<int, std::vector<int>, std::less<int>> q1;
        for (auto & num : data) {
            q1.push(num);
        }
        print_queue(q1);
    
        // another init way
        std::priority_queue<int, std::vector<int>, std::less<int>> q2(data.begin(), data.end());
        print_queue(q2);
    
        // using lambda to compare elements
        auto cmp = [](int left, int right) {return left < right;};
        std::priority_queue<int, std::vector<int>, decltype(cmp)> q3(data.begin(), data.end(), cmp);
        print_queue(q3);
    
        return 0;
    }
    

    输出为:

    6 5 5 4 3 3 2 2 1 
    6 5 5 4 3 3 2 2 1 
    6 5 5 4 3 3 2 2 1
    

    https://en.cppreference.com/w/cpp/container/priority_queue

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值