C++_优先级队列(priority_queue) & 仿函数

文章目录

  • 1.priority_queue的介绍
  • 2 priority_queue的使用
    • 2.1 代码示例
  • 3.模拟实现priority_queue
  • 4.例题链接
    • 4.1 代码解析
  • 5.仿函数的介绍
  • 6.仿函数的优点
  • 7.仿函数代码示例
  • 8.priority_queue中的仿函数

1.priority_queue的介绍

template <class T, class Container = vector<T>,
class Compare = less<typename Container::value_type> > class priority_queue;
  1. 优先队列是一种容器适配器,根据严格的弱排序标准,它的第一个元素总是它所包含的元素中最大/小的。
  2. 此上下文类似于堆,在堆中可以随时插入元素,并且只能检索最大堆元素(优先队列中位于顶部的素)。
  3. 优先队列被实现为容器适配器,容器适配器即将特定容器类封装作为其底层容器类,queue提供一组特定的成员函数来访问其元素。元素从特定容器的“尾部”弹出,其称为优先队列的顶部
  4. 标准容器类vector和deque满足这些需求。默认情况下,如果没有为特定的priority_queue类实例化指定容器类,则使用vector
  5. 需要支持随机访问迭代器,以便始终在内部保持堆结构。容器适配器通过在需要时自动调用算法函数make_heap、push_heap和pop_heap来自动完成此操作。
  6. 底层容器可以是任何标准容器类模板,也可以是其他特定设计的容器类。容器应该可以通过随机访问迭代器访问,并支持以下操作:
    C++_优先级队列(priority_queue) & 仿函数_第1张图片

2 priority_queue的使用

  • 优先级队列默认使用vector作为其底层存储数据的容器,在vector上又使用了堆算法将vector中元素构造成堆的结构,因此priority_queue就是堆,所有需要用到堆的位置,都可以考虑使用priority_queue。
  • 有关堆的讲解在我的另一篇博客有详解 》link 。
  • 注意:默认情况下priority_queue是大堆。( class Compare = less < typename Container::value_type> )

2.1 代码示例

#include
#include 
#include 

using namespace std;
void TestPriorityQueue()
{
	vector<int> v{ 3,2,7,6,0,4,1,9,8,5 };
	priority_queue<int> q1(v.begin(), v.end());

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

	priority_queue<int, vector<int>, greater<int>> q2(v.begin(), v.end());
	while (!q2.empty())
	{
		cout << q2.top() << " ";
		q2.pop();
	}
}
int main()
{
	TestPriorityQueue();
	return 0;
}

C++_优先级队列(priority_queue) & 仿函数_第2张图片

3.模拟实现priority_queue

#pragma once
#include
#include
#include
//仿函数
template<class T>
class Less
{
public:
	bool operator()(const T& A, const T& B)
	{
		return A < B;
	}
};
//仿函数
template<class T>
class Great
{
public:
	bool operator()(const T& A, const T& B)
	{
		return A > B;
	}
};
//模拟实现Mypriority_queue
namespace Mypriority_queue
{
    //模板
	template<class T,class container = std::vector<T>,class compare = Great<T>>
	class priority_queue
	{
	public:
		//强制默认生成构造函数
		priority_queue() = default;
		
		template <class InputIterator>
		priority_queue(InputIterator first, InputIterator last)
			:_con(first,last)
		{
			// 从下往上建堆
			for (int i = (_con.size() - 1 - 1) / 2; i >= 0; --i)
			{
				AdjustDown(i);
			}
		}
		//从下往上建堆
		void AdjustUp(int child)
		{
			int parent = (child - 1) / 2;
			while (child > 0)
			{
				if (_com(_con[child], _con[parent]))
				{
					std::swap(_con[child], _con[parent]);
					child = parent;
					parent = (child - 1) / 2;
				}
				else
				{
					break;
				}
			}
		}
		//从上往下建堆
		void AdjustDown(int parent)
		{
			size_t child = parent * 2 + 1;
			while (child < _con.size())
			{
				if (child + 1 < _con.size() &&_com(_con[child+1],_con[child]))
				{
					child++;
				}
				if (_com(_con[child],_con[parent]))
				{
					std::swap(_con[child], _con[parent]);
					parent = child;
					child = parent * 2 + 1;
				}
				else
				{
					break;
				}
			}
		}
		//判空
		bool empty() const
		{
			return _con.empty();
		}
		//元素个数
		size_t size() const
		{
			return _con.size();
		}
		//获得队列顶元素
		const T& top() const
		{
			return _con[0];
		}
		//插入元素
		void push(const T& x)
		{
			_con.push_back(x);
			AdjustUp(_con.size() - 1);
		}
		//删除顶上元素
		void pop()
		{
			assert(_con.size() > 0);
			std::swap(_con[0], _con[_con.size() - 1]);
			_con.pop_back();
			AdjustDown(0);
		}

	private:
		container _con;
		compare _com;
	};

	void priority_queue_tets()
	{
		priority_queue<int> pri;//大堆
		pri.push(1);
		pri.push(2);
		pri.push(3);
		pri.push(4);
		pri.push(5);


		while (!pri.empty())
		{
			std::cout << pri.top() << " ";
			pri.pop();
		}
		std::cout << std::endl;

		std::vector<int> ret;
		ret.push_back(5);
		ret.push_back(4);
		ret.push_back(3);
		ret.push_back(2);
		ret.push_back(1);
		auto Fit = ret.begin();
		auto Tit = ret.end();

		priority_queue<int,std::vector<int>,Less<int>> pri2(Fit, Tit);//小堆
		while (!pri2.empty())
		{
			std::cout << pri2.top() << " ";
			pri2.pop();
		}
		std::cout << std::endl;
	}
}

C++_优先级队列(priority_queue) & 仿函数_第3张图片

4.例题链接

C++_优先级队列(priority_queue) & 仿函数_第4张图片

  • 题目连接:link

4.1 代码解析

class Solution {
public:
    int findKthLargest(vector<int>& nums, int k) {
        //方法一直接排序,返回倒数第K大数,最简单,面试不推荐
        sort(nums.begin(),nums.end());
        return nums[nums.size()-k];
		//方法二,将所有元素放到优先级队列里面,整体建大堆。
        priority_queue<int> p(nums.begin(),nums.end());
        for(int i=1; i<k; i++)//删除前K个大的,top()就是第K大的。
        {
            p.pop();
        }
         return p.top();
		//方法三,建立K个数的小堆,在从第K个数往后遍历,比堆顶元素大入堆并从新将堆调整。
        priority_queue< int, vector<int>, greater<int> > q(nums.begin(),nums.begin()+k);

        for(int i=k; i<nums.size(); i++)
        {
            if(nums[i] > q.top())
            {
                q.pop();
                q.push(nums[i]);
            }
        }
         return q.top();
    }
};

5.仿函数的介绍

  • 仿函数(Functor)又称为函数对象(Function Object)是一个能行使函数功能的类。仿函数的语法几乎和我们普通的函数调用一样,不过作为仿函数的类,都必须重载 operator() 运算符。因为调用仿函数,实际上就是通过类对象调用重载后的 operator() 运算符。
  • 如果编程者要将某种“操作”当做算法的参数,一般有两种方法:
  1. 一个办法就是先将该“操作”设计为一个函数,再将函数指针当做算法的一个参数。上面的实例就是该做法。
  2. 将该“操作”设计为一个仿函数(就语言层面而言是个 class),再以该仿函数产生一个对象,并以此对象作为算法的一个参数。

6.仿函数的优点

  • 写一个简单类,除了维护类的基本成员函数外,只需要重载 operator() 运算符 。这样既可以免去对一些公共变量的维护,也可以使重复使用的代码独立出来,以便下次复用。而且相对于函数更优秀的性质,仿函数还可以进行依赖组合与继承等,这样有利于资源的管理
  • 简言之:就是一个类,可以定义一些变量,省的使用全局变量,造成命名空间污染

7.仿函数代码示例

#include 
using namespace std;

class A
{
	public:
	 int operator() (int a, int b)
	 {
	    return a+b;
	 }
	 double operator() (double a, double b)
	 {
	    return (a+b)*2;
	 }
};

int main(){
  A a;
  auto c1 =  a(1, 2);
  cout << c1 << endl;
  auto c2 = a(11.3, 2.4);
  cout << c2 << endl;
}

C++_优先级队列(priority_queue) & 仿函数_第5张图片

8.priority_queue中的仿函数

//仿函数
template<class T>
class Great
{
public:
	bool operator()(const T& A, const T& B)
	{
		return A < B;
	}
};
//仿函数
template<class T>
class Less
{
public:
	bool operator()(const T& A, const T& B)
	{
		return A > B;
	}
};
template <class T, class Container = vector<T>,
class Compare = less<typename Container::value_type> > class priority_queue;

小堆

priority_queue<int, vector<int>, greater<int>>

大堆

priority_queue<int, vector<int>, greater<int>>
  • 具体代码使用示例在上面介绍priority_queue中有讲解

你可能感兴趣的:(C/C++,笔记,优先级队列,仿函数,priority_queue)