[C++] priority_queue (priority queue)


describe

1. A priority queue is a container adapter whose first element is always the largest among the elements it contains according to strict weak ordering criteria.

2. This context is similar to a heap, where elements can be inserted at any time, and only the largest heap element (the element at the top in the priority queue) can be retrieved.

3. The priority queue is implemented as a container adapter, which encapsulates a specific container class as its underlying container class, and queue provides a set of specific member functions to access its elements. Elements are popped from the "tail" of a particular container, which is called the top of the priority queue.

4. The underlying container can be any standard container class template, or any other specially designed container class. The container should be accessible via a random access iterator and support the following operations:
empty(): check if the container is empty
size(): return the number of valid elements in the container
front(): return a reference to the first element in the container
push_back( ): Insert elements at the end of the container
pop_back(): Delete elements at the end of the container

5. The standard container classes vector and deque meet these requirements. By default, vector is used if no container class is specified for a particular priority_queue class instantiation.

6. Need to support random access iterators so that the heap structure is always maintained internally. The container adapter does this automatically by automatically calling the algorithmic functions make_heap, push_heap, and pop_heap when needed.

1. Common interfaces

insert image description here

2. Simulation implementation

The bottom layer of the priority queue is implemented with a binary tree heap, so the implementation of the queue is roughly the same as the heap, but a new concept is introduced. The syntax of the functor -fun function is almost the same as our ordinary function call, but as a class of functors, both The operator() operator must be overloaded. Because calling the functor is actually calling the overloaded operator() operator through the class object. Using functors helps us implement generic templates more conveniently.

//一个简单的仿函数
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. Common Oj interview questions

topic link

The Kth largest element in the array

Given an integer array nums and an integer k, return the kth largest element in the array.

Note that you are looking for the kth largest element of the sorted array, not the kth distinct element.

You must design and implement an algorithm with time complexity O(n) to solve this problem.

Example 1:

Input: [3,2,1,5,6,4], k = 2
Output: 5

Example 2:

Input: [3,2,3,1,2,4,5,5,6], k = 4
Output: 4

untie:

Method ①

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();
    }
};

Method②

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();
    }
};

Guess you like

Origin blog.csdn.net/Tianzhenchuan/article/details/131837116