【C++】priority_queue(プライオリティキュー)


説明する

1. 優先キューは、厳格な弱い順序付け基準に従って、最初の要素が含まれる要素の中で常に最大となるコンテナ アダプタです。

2. このコンテキストはヒープに似ており、いつでも要素を挿入でき、最大のヒープ要素 (優先キューの先頭の要素) のみを取得できます。

3. 優先キューは、特定のコンテナ クラスをその基礎となるコンテナ クラスとしてカプセル化するコンテナ アダプタとして実装され、キューはその要素にアクセスするための特定のメンバー関数のセットを提供します。要素は、優先キューの先頭と呼ばれる特定のコンテナの「末尾」からポップされます。

4. 基礎となるコンテナには、標準のコンテナ クラス テンプレート、またはその他の特別に設計されたコンテナ クラスを使用できます。コンテナはランダム アクセス イテレータを介してアクセス可能であり、次の操作をサポートする必要があります。
empty(): コンテナが空かどうかを確認します。
size(): コンテナ内の有効な要素の数を返します。front
(): 最初の要素への参照を返します。コンテナ内で
Push_back( ): コンテナの末尾に要素を挿入します。
Pop_back(): コンテナの末尾にある要素を削除します。

5. 標準コンテナ クラスの Vector および deque は、これらの要件を満たします。デフォルトでは、特定の priority_queue クラスのインスタンス化にコンテナ クラスが指定されていない場合は、vector が使用されます。

6. ヒープ構造が常に内部的に維持されるように、ランダム アクセス反復子をサポートする必要があります。コンテナー アダプターは、必要に応じてアルゴリズム関数 make_heap、push_heap、pop_heap を自動的に呼び出すことで、これを自動的に行います。

1. 共通インターフェース

ここに画像の説明を挿入

2. シミュレーションの実装

優先キューの最下層はバイナリ ツリー ヒープで実装されているため、キューの実装はヒープとほぼ同じですが、新しい概念が導入されています。ファンクター -fun 関数の構文は、私たちの関数とほぼ同じです。通常の関数呼び出しですが、ファンクターのクラスとして、operator() 演算子をオーバーロードする必要があります。なぜなら、ファンクターを呼び出すことは、実際にはクラスオブジェクトを通じてオーバーロードされたoperator()演算子を呼び出すことになるからです。ファンクターを使用すると、汎用テンプレートをより簡単に実装できます。

//一个简单的仿函数
template<class T>
class Less
{
    
    
public:
	//重载 '()' 
	bool operator()(const T& x,const T& y)
	{
    
    
		//内置类型直接比大小,自定义大小会调用他们自己的运算符重载 ‘<’ 比较大小
		return x<y;
	}
}
#include<iostream>
#pragma once
#include<vector>

namespace tzc
{
    
    
	//此处的最后一个模板参数使用仿函数,默认调用库中的less 这样建堆默认是大堆
	template<class T,class Container =vector<T>,class Compare =less<int>>
	class priority_queue
	{
    
    
	private:
		//向下调整
		void AdjustDown(int parent)
		{
    
    	
			Compare com;
			//找出左右孩子大的
			int child = parent * 2 + 1;
			while (child < _con.size())
			{
    
    
				if (child + 1 < _con.size() && com(_con[child],_con[child + 1]))
				{
    
    
					++child;
				}
				if (com(_con[parent],_con[child]))
				{
    
    
					//孩子结点比父节点还大
					swap(_con[child], _con[parent]);
					parent = child;
					child = parent * 2 + 1;
				}
				else break;
			}

		}
		//向上调整
		void AdjustUp(int child)
		{
    
    
			Compare com;
			int parent = (child - 1) / 2;
			while (child > 0)
			{
    
    
				//如果孩子结点比父节点大交换
				if (com(_con[parent],_con[child]))
				{
    
    
					swap(_con[child], _con[parent]);
					child = parent;
					parent = (child - 1) / 2;
				}
				else
				{
    
    
					break;
				}
			}
		}


	public:
		priority_queue()
		{
    
    

		}
		template<class InputIterator>
		priority_queue(InputIterator first, InputIterator last)
		{
    
    
			while (first != last)
			{
    
    
				_con.push_back(*first);
				++first;
			}

			//建堆
			for (int i =(_con.size() - 1 - 1) / 2; i >= 0; i--)
			{
    
    
				AdjustDown(i);
			}
		}
		void pop()
		{
    
    
			swap(_con[0], _con[_con.size() - 1]);
			_con.pop_back();
			AdjustDown(0);
		}
		void push(const T& val)
		{
    
    
			_con.push_back(val);
			AdjustUp(_con.size() - 1);
		}
		const T& top()
		{
    
    
			return _con[0];
		}

		bool empty()
		{
    
    
			return _con.empty();
		}

		int size()
		{
    
    
			return _con.size();
		}

	private:
		Container _con;
	};


	void test_priority()
	{
    
    
		priority_queue<int> pq;
		pq.push(3);
		pq.push(5);
		pq.push(1);
		pq.push(4);

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

	}
}

2. Oj 面接でよくある質問

トピックリンク

配列内の K 番目に大きい要素

整数配列 nums と整数 k を指定すると、配列内で k 番目に大きい要素を返します。

検索しているのは、k 番目の個別の要素ではなく、並べ替えられた配列の k 番目に大きい要素であることに注意してください。

この問題を解決するには、時間計算量 O(n) のアルゴリズムを設計して実装する必要があります。

例 1:

入力: [3,2,1,5,6,4]、k = 2
出力: 5

例 2:

入力: [3,2,3,1,2,4,5,5,6]、k = 4
出力: 4

ほどく:

方法①

class Solution {
    
    
public:
    int findKthLargest(vector<int>& nums, int k) {
    
    
        //默认大堆  建大堆 
        priority_queue<int> pq(nums.begin(), nums.end());
		//将比第k个大的元素pop出队
        for (int i = 0; i < k-1; i++)
        {
    
    
            pq.pop();
        }
        //取队头元素即为第k个大元素
        return pq.top();
    }
};

方法②

class Solution {
    
    
public:
    int findKthLargest(vector<int>& nums, int k) {
    
    
        //建小堆  建一个有k个元素的小堆
        priority_queue<int,vector<int>,greater<int>> pq(nums.begin(),nums.begin()+k);
        
        //堆顶元素即为k个元素中最小元素,将剩余元素入队,如果比队头元素大,则进队,
        //将原先队头元素出队,这样可以保证队中元素永远只有k个,将所以元素以此方法进队后,队头元素即为第k个大的元素
        for(int i=k;i<nums.size();i++)
        {
    
    
            if(nums[i]>pq.top())
            {
    
    
                pq.pop();
                pq.push(nums[i]);
            }
        }
        return pq.top();
    }
};

おすすめ

転載: blog.csdn.net/Tianzhenchuan/article/details/131837116