C++ priority_queue的使用与简单实现

目录

1. priority_queue的介绍

2. 仿函数

(1). 概念

(2). 特点

3. priority_queue的使用

 4. priority_queue模拟实现

(1). 如何插入时构建堆,删除时维持堆

(2). 成员函数实现具体功能

5. 全部代码

(1). priority_queue.h

(2).  test.cpp


1. priority_queue的介绍

1. 是一种容器适配器

2. 优先使用vector作为其底层存储数据的容器。

3. 使用了堆算法将vector中元素构造成堆的结构,所以priority_queue类似于堆,用的到堆的地方都可以考虑使用priority_queue。

4. 默认情况下priority_queue建立的是大堆

5. 使用时只需包含#include<queue>即可

其底层容器需要支持随机访问迭代器(Random-access iterators)以便自身在内部始终保持堆结构。这些由容器适配器自动完成,通过自动调用算法函数make_heap、push_heap、pop_heap,完成操作

priority_queue的模板参数有三个

上图中的

1. T为存储的数据类型

2. Container为存储数据的底层容器

3. Compare为仿函数

2. 仿函数

(1). 概念

就是模仿函数的对象,它们可以通过重载operator() 来使得对象可以像函数一样被调用,即可以使用圆括号()来传递参数,返回结果

(2). 特点
  1. 通过重载operator(),仿函数对象可接收参数并返回结果,看起来类似于普通的函数

  2. 与普通函数不同,仿函数作为对象,可以拥有成员变量。这意味着它更加灵活

  3. 与模板结合提供类型安全的泛型编程。算法接收仿函数作为参数,已实现算法的灵活性

使用如下所示

#include<algorithm>  
#include<vector>  
#include<iostream>  


int main()
    {
    std::vector<int> vec = { 3, 1, 4, 1, 5, 9, 2 };

    sort(vec.begin(), vec.end());
    for (int n : vec)//auto也可以
    {
        std::cout << n << ' ';
    }
    std::cout << std::endl;
    // 使用 greater 对 vec 进行降序排序  
    sort(vec.begin(), vec.end(), std::greater<int>());
    for (int n : vec)
    {
        std::cout << n << ' ';
    }
    std::cout << std::endl;

    return 0;
}

 以上代码中的greater就是仿函数(模板函数对象)通常用来比较大于,与之相对的less用来比较小于,我们上面传参数相当于传了个匿名对象

3. priority_queue的使用

函数声明接口说明
priority_queue()/priority_queue(first,last)构造一个空的优先级队列/根据迭代器(左开右闭)构造空间
empty()检测优先级队列是否为空
top()返回优先级队列中最大(最小元素),即堆顶元素
push(x)在优先级队列中插入元素x
pop()删除优先级队列中最大(最小)元素,即为堆顶元素

代码如下所示 

#include<algorithm>  
#include<vector>  
#include<iostream>
#include<queue>
using namespace std;
int main() 
{
    vector<int> v{ 1,6,5,9,8,7,3,4 };
    priority_queue<int> pq1;
    priority_queue<int, vector<int>, greater<int>> pq2(v.begin(), v.end());
    for (auto vv : v)
    {
        pq1.push(vv);
    }
    //默认创建的是大堆,由下输出可得
    while(!pq1.empty())
    {
        cout << pq1.top() << " ";
        pq1.pop();
    }
    cout << endl;
    //可以通过greater<int>来创建小堆
    while (!pq2.empty())
    {
        cout << pq2.top() << " ";
        pq2.pop();
    }

    return 0;
}

输出结果如下

如果利用我们自己写的仿函数呢?

#include<algorithm>  
#include<vector>  
#include<iostream>
#include<queue>
using namespace std;
template <class T>
class greaternum
{
public:
    bool operator()(T a, T b)
    {
        return a > b;
    }

};
int main() 
{
    vector<int> v{ 1,6,5,9,8,7,3,4 };
    priority_queue<int> pq1;
    priority_queue<int, vector<int>, greaternum<int>> pq2(v.begin(), v.end());
    for (auto vv : v)
    {
        pq1.push(vv);
    }
    //默认创建的是大堆,由下输出可得
    while(!pq1.empty())
    {
        cout << pq1.top() << " ";
        pq1.pop();
    }
    cout << endl;
    //可以通过greater<int>来创建小堆
    while (!pq2.empty())
    {
        cout << pq2.top() << " ";
        pq2.pop();
    }

    return 0;
}

 运行结果依然为

 4. priority_queue模拟实现

(1). 如何插入时构建堆,删除时维持堆

这里我们就需要使用向上调整算法和向下调整算法了

namespace Pc
{
	template<class T,class container=vector<T>,class compare=greater<T>>
	class priority_queue
	{
	public:
		void AdjustUp(int child)
		{
			compare adjust;
			int parent = (child - 1) / 2;
			while (child > 0)
			{
				//if(con[child]> con[parent])
				if (adjust(con[child] , con[parent]))
				{
					swap(con[child] ,con[parent]);
					child = parent;
					parent = (parent - 1) / 2;
				}
				else
					break;
			}
		}
		void AdjustDown(int head)
		{
			compare adjust;
			int parent = head;
			int child = parent * 2 + 1;
			int n = con.size();
			while (child < con.size())
			{
				//if (con.size()<child + 1 && con[child + 1]< con[child])
				if (adjust(con.size() , child + 1) && adjust(con[child + 1], con[child]))
				{
					child ++;
				}
				//if (con[child]< con[parent])
				if (adjust(con[child] , con[parent]))
				{
					swap(con[child], con[parent]);
					parent = child;
					child = child * 2 + 1;
				}
				else
					break;
			}
		}
	private:
		container con;
	};
}

这里应用了仿函数,实现如下

template <class T>
class lessnum
{
public:
	bool operator()( T a,T b)
	{
		return a < b;
	}

};
template <class T>
class greaternum
{
public:
	bool operator()(T a, T b)
	{
		return a > b;
	}

};

比起用C语言实现堆少了一些参数,具体思路并没发生改变

(2). 成员函数实现具体功能

插入,删除,返回堆顶元素,判空,返回队列里元素个数

		void push(const T& x)
		{
			con.push_back(x);
			AdjustUp(con.size()-1);

		}
		void pop()
		{
			swap(con[0], con[con.size()-1]);
			con.pop_back();
			AdjustDown(0);
		}
		T& top()
		{
			return con.back();
		}
		const T& top() const
		{
			return con.back();
		}
		bool empty()
		{
			return con.empty();
		}
		size_t size()
		{
			return con.size();
		}
		//void print()//用来方便观测优先级队列
		//{
			//for (int i = 0; i < size(); i++)
		//	{
		//		cout << con[i] << "   ";
		//	}
		//	cout << endl;
		}

5. 全部代码

(1). priority_queue.h
namespace Pc
{
	template<class T,class container=vector<T>,class compare=greater<T>>
	class priority_queue
	{
	public:
		priority_queue() {}

		void AdjustUp(int child)
		{
			compare adjust;
			int parent = (child - 1) / 2;
			while (child > 0)
			{
				//if(con[child]> con[parent])
				if (adjust(con[child] , con[parent]))
				{
					swap(con[child] ,con[parent]);
					child = parent;
					parent = (parent - 1) / 2;
				}
				else
					break;
			}
		}
		void AdjustDown(int head)
		{
			compare adjust;
			int parent = head;
			int child = parent * 2 + 1;
			int n = con.size();
			while (child < con.size())
			{
				//if (con.size()<child + 1 && con[child + 1]< con[child])
				if (adjust(con.size() , child + 1) && adjust(con[child + 1], con[child]))
				{
					child ++;
				}
				//if (con[child]< con[parent])
				if (adjust(con[child] , con[parent]))
				{
					swap(con[child], con[parent]);
					parent = child;
					child = child * 2 + 1;
				}
				else
					break;
			}
		}
		void push(const T& x)
		{
			con.push_back(x);
			AdjustUp(con.size()-1);

		}
		void pop()
		{
			swap(con[0], con[con.size()-1]);
			con.pop_back();
			AdjustDown(0);
		}
		T& top()
		{
			return con.back();
		}
		const T& top() const
		{
			return con.back();
		}
		bool empty()
		{
			return con.empty();
		}
		size_t size()
		{
			return con.size();
		}
		void print()
		{
			for (int i = 0; i < size(); i++)
			{
				cout << con[i] << "   ";
			}
			cout << endl;
		}
	private:
		container con;
	};
}
(2).  test.cpp

priority_queue.h中的代码在以下代码#include"priority_queue.h"  处展开

#include<iostream>
#include<stack>
#include<vector>
#include<algorithm>
using namespace std;

#include"priority_queue.h"
template <class T>
class lessnum
{
public:
	bool operator()( T a,T b)
	{
		return a < b;
	}

};
template <class T>
class greaternum
{
public:
	bool operator()(T a, T b)
	{
		return a > b;
	}

};
int main()
{
	//Pc::priority_queue<int, vector<int>, lessnum<int>> pq;
	//Pc::priority_queue<int, vector<int>, greaternum<int>> pq;
	Pc::priority_queue<int, vector<int>> pq;
	pq.push(1);
	pq.push(12);
	pq.push(123);
	pq.push(1234);
	while (!pq.empty())
	{
		pq.print();
		cout << "最后一个元素: " << pq.top() << "   元素还有:"<<pq.size() << endl;
		pq.pop();
	}
	return 0;
}

到此为止了

(๑′ᴗ‵๑)I Lᵒᵛᵉᵧₒᵤ❤

  • 14
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值