0
点赞
收藏
分享

微信扫一扫

C++ priority_queue的使用及模拟实现

秀妮_5519 2022-05-01 阅读 97

                                       

好多天没有更新博客了,最近一直在忙着学linux和自己的专业课(因为博主不是科班的~)。现在在学校感觉时间有些紧,等到期末考完了,博主就全身心把linux博客总结并分享给大家~

       优先级队列也是STL库中非常实用的一个容器。底层实现和堆很相似,这个容器又和之前讲的string、vector、list...模板参数上有些区别,今天来和老铁们一起见识一下这个容器~

目录

priority_queue的介绍

 priority_queue的使用

construct

priority_queue() 

priority_queue(first, last)

我们在上面看到了它有三个模板参数,那么我们应该怎么把控呢?

empty()

top()

push()

pop()

size()

swap() 

 priority_queue模拟实现

Compare仿函数实现

less

greater

priority_queue()

priority_queue(InputIterator first, InputIterator last)

void adjust_down(int parent)

void push(const T& x)

void adjust_up(int child)

void pop()

const T& top() const

size_t size()

bool empty()

完整代码

priority_queue.h

Date.h

测试代码

 总结

注意


priority_queue的介绍

我们先来看一下C++文档的介绍:

我们翻译成中文:

 priority_queue的使用

construct

priority_queue() 

举个栗子:

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

int main()
{
	/*explicit priority_queue(const Compare & comp =Compare(),
	        const Container & ctnr = Container()); */
	priority_queue<int> q; 
	return 0;
}

我们调试一下看看情况:

priority_queue(first, last)

举个栗子:

int main()
{
	/*template <class InputIterator>
         priority_queue (InputIterator first, InputIterator last,
                         const Compare& comp = Compare(),
                         const Container& ctnr = Container());*/

	//传vector迭代器
	vector<int> v = { 1,2,3,4,5 }; //C++11支持的语法
	priority_queue<int> q1(v.begin(),v.end());

	//传list迭代器
	list<int> l = { 10,20,30,40,50 };//C++11支持的语法
	priority_queue<int> q2(l.begin(), l.end());

	//普通数组
	int arr[] = { 5,4,3,2,1 };
	priority_queue<int> q3(arr, arr + 5);
	return 0;
}

我们调试一下看看情况:

我们在上面看到了它有三个模板参数,那么我们应该怎么把控呢?

举个栗子:

int main()
{
	vector<int> v1 = { 1,2,3,4,5 };
	priority_queue<int, vector<int>, greater<int>> q1(v1.begin(), v1.end());

	vector<int> v2 = { 50,40,30,20,10 };
	priority_queue<int, deque<int>, greater<int>> q2(v2.begin(), v2.end());
	return 0;
}

我们调试一下看看情况:

empty()

举个栗子:

int main()
{
	priority_queue<int> q1;
	cout << q1.empty() << endl;

	vector<int> v = { 1,2,3,4,5 };
	priority_queue<int> q2(v.begin(), v.end());
	cout << q2.empty() << endl;
	return 0;
}

运行结果:

top()

举个栗子:

int main()
{
	vector<int> v = { 1,2,3,4,5 };
	priority_queue<int> q(v.begin(), v.end()); //默认是建大堆
	cout << q.top() << endl;
	return 0;
}

运行结果:

push()

 

举个栗子:

int main()
{
	priority_queue<int> q;
	q.push(1);
	q.push(2);
	q.push(5);
	q.push(4);
	q.push(3);
	return 0;
}

我们来调试一下看看情况:

pop()

举个栗子:

int main()
{
	priority_queue<int> q;
	q.push(1);
	q.push(2);
	q.push(5);
	q.push(4);
	q.push(3);
	q.pop();
	return 0;
}

我们调试一下来看看情况:

size()

 

举个栗子:

int main()
{
	priority_queue<int> q;
	q.push(1);
	q.push(2);
	q.push(3);
	cout << q.size() << endl;
	return 0;
}

运行结果:

swap() 

举个栗子:

int main()
{
	priority_queue<int> q1;
	q1.push(5);
	q1.push(4);
	q1.push(3);
	q1.push(2);
	q1.push(1);

	priority_queue<int> q2;
	q2.push(50);
	q2.push(40);
	q2.push(30);
	q2.push(20);
	q2.push(10);
	q1.swap(q2);
	return 0;
}

我们来调试一下看看情况:

 priority_queue模拟实现

Compare仿函数实现

less

	//仿函数
	template<class T>
	struct less //大堆
	{
		bool operator()(const T& x, const T& y) const
		{
			return x < y;
		}
	};

	//特化 -- 针对比如日期类这样的自定义类型 ->new出来的Date对象走这个
	template<>
	struct less<Date*>
	{
		bool operator()(const Date*& x, const Date*& y)const
		{
			return *x < *y;
		}
	};

greater

	template<class T>
	struct greater
	{
		bool operator()(const T& x, const T& y)
		{
			return x > y;
		}
	};

	//特化 -- 针对比如日期类这样的自定义类型 ->new出来的Date对象走这个
	template<>
	struct greater<Date*>
	{
		bool operator()(const Date*& x, const Date*& y) const
		{
			return *x > *y;
		}
	};

priority_queue()

//无参的构造函数
priority_queue()
{}

priority_queue(InputIterator first, InputIterator last)

template<class InputIterator>
priority_queue(InputIterator first, InputIterator last)
	:_con(first, last) //先把数据录入_con中,实际上调用了_con的构造函数
{
	//建堆
	for (int i = (_con.size() - 1 - 1) / 2; i >= 0; i--)
	{
		adjust_down(i);
	}
}

void adjust_down(int parent)

void adjust_down(int parent)
{
	Compare com;//仿函数对象
	int child = parent * 2 + 1;//默认是左孩子
	while (child < _con.size()) //_con.size()-1的位置就是最后一个数据下标的位置了。child == _con.size()就会越界!
	{
		//if (child + 1 < _con.size() && _con[child + 1] > _con[child])
		if (child + 1 < _con.size() && com(_con[child], _con[child+1]))
		{
			child += 1;
		}
		if (com(_con[parent], _con[child]))
		{
			swap(_con[parent], _con[child]);
			parent = child;
			child = parent * 2 + 1;
		}
		else
		{
			break;
		}
	}
}

void push(const T& x)

void push(const T& x)
{
	_con.push_back(x);
	adjust_up(_con.size() - 1);//插入的数据向上调整
}

void adjust_up(int child)

void adjust_up(int child)
{
	Compare com; //定义一个仿函数对象
	int parent = (child - 1) / 2;
	while (child > 0)
	{
		if (com(_con[parent], _con[child]))
		{
			swap(_con[parent], _con[child]);
			child = parent;
			parent = (child - 1) / 2;
		}
		else
		{
			break;
		}
	}
}

void pop()

void pop()
{
	swap(_con[0], _con[_con.size() - 1]);
	_con.pop_back();
	adjust_down(0);
}

const T& top() const

const T& top() const
{
	return _con[0];
}

size_t size()

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

bool empty()

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

完整代码

priority_queue.h

#pragma once
#include<iostream>
#include"Date.h"
#include<vector>
#include<deque>
#include<algorithm>
using namespace std;

namespace cyq
{
	//仿函数
	template<class T>
	struct less //大堆
	{
		bool operator()(const T& x, const T& y) const
		{
			return x < y;
		}
	};

	//特化 -- 针对比如日期类这样的自定义类型 ->new出来的Date对象走这个
	template<>
	struct less<Date*>
	{
		bool operator()(const Date*& x, const Date*& y)const
		{
			return *x < *y;
		}
	};

	template<class T>
	struct greater
	{
		bool operator()(const T& x, const T& y)
		{
			return x > y;
		}
	};

	//特化 -- 针对比如日期类这样的自定义类型 ->new出来的Date对象走这个
	template<>
	struct greater<Date*>
	{
		bool operator()(const Date*& x, const Date*& y) const
		{
			return *x > *y;
		}
	};

	template<class T,class Container=vector<T>,class Compare=less<T>>
	class priority_queue
	{
	private:
		void adjust_down(int parent)
		{
			Compare com;//仿函数对象
			int child = parent * 2 + 1;//默认是左孩子
			while (child < _con.size()) //_con.size()-1的位置就是最后一个数据下标的位置了。child == _con.size()就会越界!
			{
				//if (child + 1 < _con.size() && _con[child + 1] > _con[child])
				if (child + 1 < _con.size() && com(_con[child], _con[child+1]))
				{
					child += 1;
				}
				if (com(_con[parent], _con[child]))
				{
					swap(_con[parent], _con[child]);
					parent = child;
					child = parent * 2 + 1;
				}
				else
				{
					break;
				}
			}
		}
		void adjust_up(int child)
		{
			Compare com; //定义一个仿函数对象
			int parent = (child - 1) / 2;
			while (child > 0)
			{
				if (com(_con[parent], _con[child]))
				{
					swap(_con[parent], _con[child]);
					child = parent;
					parent = (child - 1) / 2;
				}
				else
				{
					break;
				}
			}
		}
	public:
		//无参的构造函数
		priority_queue()
		{}

		template<class InputIterator>
		priority_queue(InputIterator first, InputIterator last)
			:_con(first, last) //先把数据录入_con中,实际上调用了_con的构造函数
		{
			//建堆
			for (int i = (_con.size() - 1 - 1) / 2; i >= 0; i--)
			{
				adjust_down(i);
			}
		}
		void push(const T& x)
		{
			_con.push_back(x);
			adjust_up(_con.size() - 1);//插入的数据向上调整
		}
		void pop()
		{
			swap(_con[0], _con[_con.size() - 1]);
			_con.pop_back();
			adjust_down(0);
		}
		const T& top() const
		{
			return _con[0];
		}
		size_t size()
		{
			return _con.size();
		}
		bool empty()
		{
			return _con.empty();
		}
	private:
		Container _con;
		};
}

Date.h

#pragma once
#include<iostream>
using namespace std;

class Date
{
	friend ostream& operator<<(ostream& out, const Date& d);
public:
	Date(int year=1,int month=1,int day=1)
		:_year(year)
		,_month(month)
		,_day(day)
	{}
	// 建立大堆时,需要用户在自定义类型中提供<的重载
	bool operator<(const Date& d) const
	{
		return _year < d._year ||
			(_year == d._year && _month < d._month) ||
			(_year == d._year && _month == d._month && _day < d._day);
	}
	// 建立小堆时,需要用户在自定义类型中提供>的重载
	bool operator>(const Date& d) const
	{
		return _year > d._year ||
			(_year == d._year && _month > d._month) ||
			(_year == d._year && _month == d._month && _day > d._day);
	}
private:
	int _year;
	int _month;
	int _day;
};
ostream& operator<<(ostream& out, const Date& d)
{
	out << d._year << "-" << d._month << "-" << d._day;
	return out;
}

测试代码

int main()
{
	cyq::priority_queue<int> q1;
	q1.push(1);
	q1.push(2);
	q1.push(3);
	q1.push(4);
	q1.push(5);

	vector<int> v = { 50,40,30,20,10 };
	cyq::priority_queue<int> q2(v.begin(), v.end());
	q2.pop();
	cout << q2.top() << endl;

	cyq::priority_queue<int,vector<int>,greater<int>> q4;
	q4.push(5);
	q4.push(4);
	q4.push(3);
	q4.push(2);
	q4.push(1);

	cyq::priority_queue<Date> q3;
	q3.push(Date(2022, 4, 31));
	q3.push(Date(2022, 5, 1));
	q3.push(Date(2021, 5, 1));
	q3.push(Date(2021, 4, 31));
	return 0;
}

通过调试窗口来看:

 总结

如果老铁们还想进一步了解堆这个算法可以看看博主曾经花了2天写的博客:

常见排序算法激烈讲解_暴走的橙子~的博客-CSDN博客

注意

看下面的代码:

	cyq::priority_queue<Date*,vector<Date*>,cyq::greater<Date*>> q3;
	q3.push(new Date(2022, 4, 31));
	q3.push(new Date(2022, 5, 1));
	q3.push(new Date(2021, 5, 1));
	q3.push(new Date(2021, 4, 31));
	q3.push(new Date(2021, 6, 31));
	q3.push(new Date(2022, 5, 31));
	while (!q3.empty())
	{
		cout << *(q3.top()) << endl;
		q3.pop();
	}

我们把new出来的对象的地址放进优先级队列。再看看我们实现的push版本:

void push(const T& x)
{
	_con.push_back(x);
	adjust_up(_con.size() - 1);//插入的数据向上调整
}

运行结果:

看到这里给博主支持下吧~

 

举报

相关推荐

0 条评论