C++STL-stack与queue以及priority_queue

Posted Booksort

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C++STL-stack与queue以及priority_queue相关的知识,希望对你有一定的参考价值。

在C语言中,我们都是了解过stack(栈)和queue(队列)。

而C++提供了更好的解决方案,有STL可以帮开发者减少大量的工作,也就是说,有大佬已经帮我们写好了这些数据结构,并且封装成了一个库,对于这些基本数据结构,可以像使用int、double一样,创建一个数据结构对象。

stack模拟

介绍stack


这比较”官方“提供的关于stack的描述,STL基本上都是实现一个类模板,这样可以让使用者根据自己的需求创建不同类型的数据结构。

这里描述了,stack作为一个container adaptor,容器适配器,也就是说,stack并不是一个纯粹的容器,并不像vector那样,自己实现了一个顺序表。而是适配其他较为底层的容器,做了一些修改。

也就是说,stack使用其他容器,比如vector、list做了相关调整,模拟出来一个栈的效果。
具体通过class Container=deque<T>,来适配deque这个容器。

类方法

看看stack的类方法

stack作为一个后入先出的数据结构,能够操作的只有栈顶元素,其他元素都是不能操作的。

模拟一个stack的基本功能

namespace cz
{
	template <class T,class Container=std::vector<T>>
	class stack
	{
	public:
		stack()
			:con(T())
		{}
		void pop(void)
		{
			con.pop_back();
		}
		void push(const T& val)
		{
			con.push_back(val);
		}
		size_t size(void)
		{
			return con.size();
		}
		T top(void)
		{
			return con.back();
		}
		bool empty(void)
		{
			return con.empty();
		}
	private:
		Container con;
	};


}

这是在我的命名空间中实现的一个基本类模板。我用stack来适配vector,就相当于使用顺序表来实现一个栈。

弹栈使用的是vector::pop_back()
入栈使用的是vector::push_back()
全部对顺序表的最后一个元素进行操作。

参考题
Leetcode-946.验证栈序列

queue


stack一样,也是作为一个容器适配器。

队列的类方法

模拟实现

namespace cz
{
	template <class T,class Container=std::vector<T>>
	class queue
	{
	public:
		size_t size(void)
		{
			return _con.size();
		}
		void pop(void)
		{
			_con.erase(_con.begin());
		}
		void push(const T& val)
		{
			_con.push_back(val);
		}
		bool empty(void)
		{
			return _con.empty();
		}
		T front(void)
		{
			return _con.front();
		}
		T back(void)
		{
			return _con.back();
		}
	private:
		Container _con;
	};
}

对于队列的出队,可以使用earse与迭代器begin进行擦除操作。

priority_queue

翻译过来是优先队列
虽说,是队列,但实际上,这是一个堆(一种特殊的二叉树)。而且,这也是一个容器适配器。
这个类似于堆,可以随时插入元素,并且只能检索到最大/小堆元素(优先级队列中的顶部)。

优先队列是vector的适配器,因为堆基本上是通过数组进行排列操作。

仿函数

这个class Compare = less<typename Container::value_type>
其实就是一个仿函数,less实际上是一个类。
仿函数,就是通过类来模拟函数的效果。

而这里的仿函数,其实例化的类型是适配的容器的元素类型。这个是起到比较的作用。
因为,当建大/小堆是,需要将子节点与父节点进行比较。满足条件才会进行交换。而且,这个是建大堆还是建小堆可以通过less<>、greater<>来控制。less可以建大堆,greater建小堆。

模拟实现

namespace cz
{
	template<class T,class Container=std::vector<T>,class Compare=std::less<typename Container::value_type> >
	class priority_queue
	{
	public:
		priority_queue(const Compare& comp = Compare(),const Container& ctnr = Container())//构造
			:_con(ctnr)//容器构造
			,comp(comp)//仿函数构造
		{}
		template <class InputIterator>//迭代器
		priority_queue(InputIterator first, InputIterator last,
			const Compare& comp = Compare(),
			const Container& ctnr = Container())
			: _con(ctnr)//容器构造
			, comp(comp)//仿函数构造
		{
			//迭代器深拷贝
		}
		void pop(void)
		{
			std::swap(_con[0], _con[size() - 1]);
			_con.pop_back();
			AdjustDown(0);//向下调整
		}
		void push(const T& val)
		{
			//向上调整算法
			_con.push_back(val);
			AdjustUp(size()-1);
		}


		size_t size(void)
		{
			return _con.size();
		}
		bool empty(void)
		{
			return _con.empty();
		}

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



		void AdjustUp(int child)
		{
			int parent = (child - 1) >> 1;
			while (child > 0)
			{
				if (comp(_con[parent] , _con[child]))
				{
					::swap(_con[child], _con[parent]);
					child = parent;
					parent = (child - 1) >> 1;
				}
				else
					break;
			}
		}

		void AdjustDown(int parent)
		{
			int child = parent * 2 + 1;
			int len = size();
			while (child < len)
			{
				if (child + 1 < len && comp(_con[child], _con[child+1]))
				{
					child += 1;
				}
				if (comp(_con[parent], _con[child]))
				{
					::swap(_con[parent], _con[child]);
					parent = child;
					child = parent * 2 + 1;
				}
				else
					break;
			}
		}
	private:
		Container _con;
		Compare comp;
	};
}

向上调整算法与向下调整算法

大概概括一下,当我们将元素入堆是,是要将元素放在数组最后一个元素的。这个时候,我们都是假设/认为这本身就已经是一个大/小堆。这就最后一个元素有问题,破坏了堆的结构,就需要将这个元素进行调整,对这个元素进行向上调整。

当我们将一个元素出堆的时候,由于只能对堆顶元素进行操作,所以,这给堆顶元素要么是最大值,要么是最小值,一旦pop一定会破坏堆的完整性,所以,一般会选择将最后一个元素替换到堆顶来,这样,除了堆顶元素以外,其左右两个子堆,都是一个结构完整的堆。所以,只有这个堆顶元素影响了整个堆的完整性,就需要将这个元素向下比较,交换。就要使用向下调整算法。

以上是关于C++STL-stack与queue以及priority_queue的主要内容,如果未能解决你的问题,请参考以下文章

UVA Rails(stl-stack)

stl-stack+括号配对问题

[hdu 1062] Text Reverse | STL-stack

Queue 阻塞队列 PriorityBlockingQueue

栈与队列的区别

C++STL之stack和queue以及deque详解