ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

08 stack、queue和priority_queue的使用和模拟实现

2021-11-11 22:33:40  阅读:133  来源: 互联网

标签:priority const 队列 08 queue push return con


stack和queue在STL中并没有将其划分在容器的行列,而是将其称为容器适配器,这是因为stack和queue只是对其他容器的接口进行了包装,STL中stack和queue默认使用deque容器。


文章目录


一、容器适配器

容器适配器 是一个封装了序列容器的类模板,它在一般序列容器的基础上提供了一些不同的功能。 之所以称作适配器类,是因为它可以通过适配容器现有的接口来提供不同的功能。

说白了就是通过一种容器来实现另一种容器的功能,比如用链表实现栈,栈的push操作就可以用链表的push_back来实现,而栈的pop操作用链表的pop_back实现,至于链表的其他接口(栈用不到的接口,比如头插头删)则不对外进行暴露,因此虽然表面上看上去是一个栈,但是在底层实现上确是一个链表。
STL中的stack和queue在底层上默认用的是双端队列deque:
在这里插入图片描述

Container是一个缺省参数,我们在使用的时候可以自定义这个容器适配器,比如不想用deque而想用vector或list,直接在实例化对象的时候传入vector或list即可。


二、stack

stack是STL中的栈,其功能和数据结构中的栈一样。
常用接口:

成员函数功能
empty()判断栈是否为空
size()获取栈中有效元素个数
top()获取栈顶元素
push(x)将元素x入栈
pop()栈顶元素出栈
swap()交换两个栈中的数据
#include <iostream>
#include <stack>
#include <list>
using namespace std;

int main()
{
	stack<int, list<int>> st;//用list作为容器适配器
	st.push(1);
	st.push(2);
	st.push(3);
	st.push(4);
	cout << st.size() << endl; //4
	while (!st.empty())
	{
		cout << st.top() << " ";
		st.pop();
	}
	cout << endl; //4 3 2 1

	stack<int, list<int>> st1;
	st1.swap(st);//交换st到st1

	cout << st.size() << endl; //0
	while (!st.empty())
	{
		cout << st.top() << " ";//空
		st.pop();
	}
	cout << endl; 

	return 0;
}

模拟实现stack

#include<deque>
namespace hjl //防止命名冲突
{
	template<class T, class Container = std::deque<T>>
	class stack
	{
	public:
		//元素入栈
		void push(const T& x)
		{
			_con.push_back(x);
		}
		//元素出栈
		void pop()
		{ 
			_con.pop_back();
		}
		//获取栈顶元素
		T& top()
		{
			return _con.back();
		}
		const T& top() const
		{
			return _con.back();
		}
		//获取栈中有效元素个数
		size_t size() const
		{
			return _con.size();
		}
		//判断栈是否为空
		bool empty() const
		{
			return _con.empty();
		}
		//交换两个栈中的数据
		void swap(stack<T, Container>& st)
		{
			_con.swap(st._con);
		}
	private:
		Container _con;
	};
}

三、queue

queue是STL中的队列,功能和数据结构中的队列一样。

成员函数功能
empty()判断队列是否为空
size()获取队列中有效元素个数
front()获取队头元素
back()获取队尾元素
push(x)将x入到队尾
pop()队头出队列
swap()交换两个队列中的数据
#include <iostream>
#include <list>
#include <queue>
using namespace std;

int main()
{
	queue<int, list<int>> q;
	q.push(1);
	q.push(2);
	q.push(3);
	q.push(4);
	cout << q.size() << endl; //4
	while (!q.empty())
	{
		cout << q.front() << " ";
		q.pop();//队头出队列
	}
	cout << endl; //1 2 3 4
	return 0;
}

模拟实现queue

#include<deque>
namespace hjl //防止命名冲突
{
	template<class T, class Container = std::deque<T>>
	class queue
	{
	public:
		//队尾入队列
		void push(const T& x)
		{
			_con.push_back(x);
		}
		//队头出队列
		void pop()
		{
			_con.pop_front();
		}
		//获取队头元素
		T& front()
		{
			return _con.front();
		}
		const T& front() const
		{
			return _con.front();
		}
		//获取队尾元素
		T& back()
		{
			return _con.back();
		}
		const T& back() const
		{
			return _con.back();
		}
		//获取队列中有效元素个数
		size_t size() const
		{
			return _con.size();
		}
		//判断队列是否为空
		bool empty() const
		{
			return _con.empty();
		}
		//交换两个队列中的数据
		void swap(queue<T, Container>& q)
		{
			_con.swap(q._con);
		}
	private:
		Container _con;
	};
}

四、priority_queue

priority_queue又被称为优先级队列,它和队列的区别在于,默认使用vector作为底层存储数据的容器,并且在vector上又使用了堆算法将vector中元素构成堆的结构,这也就意味着如果入队一组无序的数据,在出队列时会变成有序,默认情况下priority_queue是大堆,也就是降序。
在这里插入图片描述

它相比于队列多了第三个参数,这个参数默认是less,建大堆(也就是降序,大数先出队列),也可以换成greater,建小堆(升序,小数先出队列)。

其接口和队列一样,只是在入队和出队时作了排序

成员函数功能
push(x)插入元素x到队尾然后排序
pop()弹出队头元素(堆顶元素)
top()访问队头元素(堆顶元素)
size()获取队列中有效元素个数
empty()判断队列是否为空
swap()交换两个队列的内容
#include <iostream>
#include <functional>
#include <queue>
using namespace std;
int main()
{
	priority_queue<int> q;
	q.push(3);
	q.push(6);
	q.push(0);
	q.push(2);
	q.push(9);
	q.push(8);
	q.push(1);
	while (!q.empty())
	{
		cout << q.top() << " ";
		q.pop();
	}
	cout << endl; //9 8 6 3 2 1 0

	priority_queue<int,vector<int>,greater<int>> q1;
	q1.push(3);
	q1.push(6);
	q1.push(0);
	q1.push(2);
	q1.push(9);
	q1.push(8);
	q1.push(1);
	while (!q1.empty())
	{
		cout << q1.top() << " ";
		q1.pop();
	}
	cout << endl; //0 1 2 3 6 8 9
	return 0;
}

使用优先级队列排序日期类

自定义类要使用less,必须要重载操作符<,要使用greater,必须要重载操作符>,并且也可以传入一个自定义的仿函数:

#include<iostream>
#include<assert.h>
#include<queue>
#include<vector>
#include <functional>
using namespace std;

class Date
{
public:
	Date(int year = 0, int month = 0, int day = 0);
	void Print();
	//比较日期的大小
	friend bool operator>(const Date& a,const Date& b);
	friend bool operator<(const Date& a, const Date& b);
	friend bool operator==(const Date& a, const Date& b);

	//日期减日期
	int operator-(const Date& d);

	friend ostream& operator<<(ostream& out, const Date& d);

private:
	int _year;
	int _month;
	int _day;
};

//获取某年某月的天数,因为要多次调用,可以写成内联函数
inline int GetMonthDay(int year, int month)
{
	static int dayArray[13] = { 0,31,28,31,30,31,30,31,31,30,31,30,31 };
	int day = dayArray[month];
	if (month == 2 && ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0)))
	{
		day = 29;
	}
	return day;
}
//构造函数
Date::Date(int year, int month, int day)
{
	//检查日期的合法性
	if (year >= 0
		&& month > 0 && month < 13
		&& day>0 && day <= GetMonthDay(year, month))
	{
		_year = year;
		_month = month;
		_day = day;
	}
	else
	{
		cout << "非法日期";
		cout << year << "-" << month << "-" << day << endl;
	}
}


//比较大小只需要实现>和==即可,其他比较操作符都可以用这两个操作符实现,提高代码复用率
bool operator>(const Date& a, const Date& b)
{
	if (a._year > b._year)
	{
		return true;
	}
	else if (a._year == b._year)
	{
		if (a._month > b._month)
		{
			return true;
		}
		else if (a._month == b._month)
		{
			if (a._day > b._day)
			{
				return true;
			}
		}
	}
	return false;
}

bool operator<(const Date& a, const Date& b)
{
	return !(a == b) && !(a > b);
}

bool operator==(const Date& a, const Date& b)
{
	return a._year == b._year && a._month == b._month && a._day == b._day;
}

ostream& operator<<(ostream& out, const Date& d)
{
	cout << d._year << "-" << d._month << "-" << d._day << endl;
	return out;
}
struct cmp
{
	bool operator()(Date a, Date b) 
	{
		return a > b;
	}
};

int main()
{
	//priority_queue<Date,vector<Date>,greater<Date>> q;
	//priority_queue<Date, vector<Date>, less<Date>> q;
	priority_queue<Date, vector<Date>,cmp> q;//传入仿函数cmp
	q.push(Date(1, 5, 15));
	q.push(Date(10, 4, 6));
	q.push(Date(7, 7, 1));
	q.push(Date(10, 12, 8));
	q.push(Date(5, 11, 9));
	q.push(Date(10, 7, 1));

	while (!q.empty())
	{
		cout << q.top();
		q.pop();
	}

	return 0;
}

在这里插入图片描述

模拟实现priority_queue

#include<vector>
#include<iostream>
namespace hjl
{
	//比较方式(使内部结构为大堆)
	template<class T>
	struct less
	{
		bool operator()(const T& l, const T& r)
		{
			return l < r;
		}
	};
	//比较方式(使内部结构为小堆)
	template<class T>
	struct greater
	{
		bool operator()(const T& l, const T& r)
		{
			return l > r;
		}
	};
	//仿函数默认为less
	template<class T, class  Container = std::vector<T>,class Compare=less<T>>
	class priority_queue
	{
	public:
		//向上调整算法,每push一个数都要调用向上调整算法,保证插入后是一个大堆
		void AdjustUp(int child)
		{
			Compare com;
			int parent = (child - 1) / 2;
			while (child > 0)
			{
				if (com(_con[parent],_con[child]))
				{
					std::swap(_con[parent], _con[child]);
					child = parent;
					parent= (child - 1) / 2;
				}
				else
				{
					break;
				}
			}
		}
		//向下调整算法,每次调用pop都要进行向下调整算法重新构成大堆
		void AdjustDwon(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]))
				{
					std::swap(_con[parent], _con[child]);
					parent = child;
					child = parent * 2 + 1;
				}
				else
				{
					break;
				}
			}
		}
		//迭代器初始化
		template<class InputIterator>
		priority_queue(InputIterator first, InputIterator last)
			:_con(first, last)//在这里传迭代器进行初始化
		{
			for (size_t i = 1; i <_con.size(); i++)
			{
				AdjustUp(i);//向上调整建堆
			}
		}

		void push(const T& x)
		{
			_con.push_back(x);

			AdjustUp(_con.size() - 1);
		}
		void pop()
		{
			std::swap(_con[0], _con[_con.size() - 1]);
			_con.pop_back();
			AdjustDwon(0);
		}
		T top()
		{
			return _con[0];
		}
		size_t size()
		{
			return _con.size();
		}
		bool empty()
		{
			return _con.empty();
		}
	private:
		Container _con;
	};
}

在这里插入图片描述

标签:priority,const,队列,08,queue,push,return,con
来源: https://blog.csdn.net/qq_52670477/article/details/121273589

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有