[最大および最小ヒープアルゴリズム]配列内でK番目に大きい要素を見つける/データの中央値を見つける

C ++のSTL優先キュー

最大および最小ヒープを構築する方法

priority_queue<int> big_heap; // 默认构造最大堆
priority_queue<int, vector<int>, greater<int>> small_heap; // 构造最小堆
priority_queue<int, vector<int>, less<int>> big_heap2; // 构造最大堆

優先キューとその機能例

#include <iostream>
#include <stack>
#include <queue>
using namespace std;

// 以下为测试
int main() {
    
    
    
    priority_queue<int> big_heap; // 默认构造最大堆
    priority_queue<int, vector<int>, greater<int>> small_heap; // 构造最小堆
    priority_queue<int, vector<int>, less<int>> big_heap2; // 构造最大堆
    if (big_heap.empty()) {
    
    
        cout << "最大堆为空!" << endl;
    }
    int test[] = {
    
     6,10,1,7,99,4,33 };
    for (int i = 0; i < 7; i++) {
    
    
        big_heap.push(test[i]);
    }
    cout << "最大堆堆顶,即最大值为 " << big_heap.top() << endl;
    big_heap.push(1000);
    cout << "最大堆堆顶,即最大值为 " << big_heap.top() << endl;
    for (int i = 0; i < 3; i++)
    {
    
    
        big_heap.pop();
    }
    cout << "最大堆堆顶,即最大值为 " << big_heap.top() << endl;
    cout << "最大堆的元素个数为:" << big_heap.size() << endl;
    return 0;
}

結果:

最大堆为空!
最大堆堆顶,即最大值为 99
最大堆堆顶,即最大值为 1000
最大堆堆顶,即最大值为 10
最大堆的元素个数为:5

配列内でK番目に大きい要素を見つけます

  1. 問題:ソートされていない配列でk番目に大きい要素を見つけます。見つける必要があるのは、配列をソートした後のk番目に大きい要素であり、k番目に異なる要素ではないことに注意してください。
  2. 解決策:サイズがKの最小チームを維持します。ヒープ内の要素の数がK未満の場合、新しい要素は直接ヒープに入ります。そうでない場合、ヒープの一番上の要素が新しい要素よりも小さい場合、ヒープの一番上がポップされ、新しい要素がヒープに追加されます。
  3. 例:[3,2,1,5,6,4]およびk = 2、k = 2であるため、最初の3および2は最小のヒープに直接入力され、ヒープの最上部は2であり、1より大きいため、操作は不要であり、2は5より大きい。 5がヒープに入ったが、2がポップアウトされた場合など、2つの要素の最小のヒープが形成されます。ヒープの上部は5で、これは必要なK番目の最大数です。その理由は、2つの(k)番号のうち最小のものが、6つの番号の中で2番目に大きいためです。味わい、上品な味わい!
class Solution {
    
    
public:
    int findKthLargest(vector<int>& nums, int k) {
    
    
        priority_queue<int, vector<int>, greater<int>> Q;
        for (int i = 0; i < nums.size(); i++)
        {
    
    
            if (Q.size() < k)
                Q.push(nums[i]);
            else if (Q.top() < nums[i]) {
    
    
                Q.pop();
                Q.push(nums[i]);
            }
        }
        return Q.top();
    }
};

データセットの中央値を見つける

問題

データセットの中央値を見つけます。中央値は、順序付きリストの中央にある数値です。リストの長さが偶数の場合、中央値は中央の2つの数値の平均です。
たとえば
、[2,3,4]の中央値は3です。
[2,3]の中央値は(2 + 3)/ 2 = 2.5です。
次の2つの操作をサポートするデータ構造を設計します。

  • void addNum(int num)-データストリームからデータ構造に整数を追加します。
  • double findMedian()-現在のすべての要素の中央値を返します。

解決する

  1. アイデア:最大ヒープと最小ヒープを動的に維持します。それぞれがデータの半分を格納します。ただし、最大のヒープの上部が最小のヒープの上部よりも小さい(または等しい、つまりデータがサイズに応じて2つに分割される)場合に限ります。半分。データセット全体の要素数が奇数の場合、一方のヒープにはもう一方の要素よりも1つ多い要素があります。つまり、複数要素のヒープの最上部が中央値です。要素の数が偶数の場合、次に、2つの山の上部要素の平均を中央値とします。
    ここに写真の説明を挿入

  2. アルゴリズムは主に、新しいデータを追加するときに最大ヒープと最小ヒープを維持します。次の3つの状況があります。

    • ケース1、現在の最大ヒープ要素と最小ヒープ要素が同じである場合は、次のことを確認します。新しい要素が最大ヒープの上限よりも小さい場合は、最大ヒープに追加します。新しい要素が最小ヒープの上限よりも大きい場合は、最小ヒープに追加します。
    • ケース2:最大のヒープが最小のヒープより1要素多い場合は、次のことを確認します。新しい要素が最大のヒープ要素よりも大きい場合は、最小のヒープに追加します。そうでない場合は、新しい要素が最大のヒープ要素以下である場合は注意してください。現時点では、最大のヒープに直接追加することはできません(最大のヒープ操作は、最小のヒープより2つ多い要素で完了します)。正しくは、バランスを維持するために、最大のヒープの一番上の要素を最小のヒープに追加してポップしてから、新しい要素を最大のヒープに追加する必要があります。若い女の子。
    • ケース3:最小ヒープには、最大ヒープよりも1つ多い要素があります。これは、上記の考え方と一致しています。

完全なコード:

#include <iostream>
#include <stack>
#include <queue>
using namespace std;

class MedianFinder {
    
    
public:
    /** initialize your data structure here. */
    MedianFinder() {
    
    
    }

    // 数据加入及最大堆和最小堆的维护
    void addNum(int num) {
    
    
        if (big_heap.empty()) {
    
    
            big_heap.push(num);
            return;
        }
        // 情况1
        if (big_heap.size() == small_heap.size()) {
    
    
            if (num < big_heap.top()) {
    
    
                big_heap.push(num);
            }
            else {
    
    
                small_heap.push(num);
            }
        }
        // 情况2
        else if (big_heap.size() > small_heap.size()) {
    
    
            if (num > big_heap.top())
                small_heap.push(num);
            else {
    
    
                small_heap.push(big_heap.top());
                big_heap.pop();
                big_heap.push(num);
            }
        }
        // 情况3
        else if (big_heap.size() < small_heap.size()) {
    
    
            if (num < small_heap.top())
                big_heap.push(num);
            else {
    
    
                big_heap.push(small_heap.top());
                small_heap.pop();
                small_heap.push(num);
            }
        }
    }

    // 求中位数
    double findMedian() {
    
    
        if (big_heap.size() == small_heap.size()) {
    
    
            return (double(big_heap.top()) + small_heap.top()) / 2.0;
        }
        else if (big_heap.size() > small_heap.size())
            return big_heap.top();
        return small_heap.top();
    }
private:
    priority_queue<int, vector<int>, less<int>> big_heap;  // 构造最大堆
    priority_queue<int, vector<int>, greater<int>> small_heap; // 构造最小堆
};

// 以下为测试
int main() {
    
    
    
    MedianFinder m;
    m.addNum(1);
    m.addNum(2);
    cout << m.findMedian() << endl;
    m.addNum(3);
    cout << m.findMedian() << endl;
    return 0;
}

結果:

1.5
2

ps:この記事はリトルエレファントアカデミーチュートリアルのメモです:https
://www.bilibili.com/video/BV1GW411Q77S t = 7029&p = 2 LeetCodeタイトル番号:215,295

おすすめ

転載: blog.csdn.net/weixin_44427114/article/details/107911651