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()
全部对顺序表的最后一个元素进行操作。
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的主要内容,如果未能解决你的问题,请参考以下文章
[hdu 1062] Text Reverse | STL-stack