最大ヒープ、最小ヒープ、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;
              }
          }
      }
      
    • 検証済みのメイン:

      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
      
  • 優先キュー

    C++ では、priority_queue最大ヒープまたは最小ヒープは、優先キュー クラスを通じて管理できます。
    そのヘッダー ファイルは<queue>次のように定義されています。
    優先キューpriority_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

おすすめ

転載: blog.csdn.net/iamanda/article/details/116562934