stack在之前学过,是一种先进后出的的数据结构,我们之前也学过,学习过程中我们知道了stack是可以用链表或顺序表实现出来的,并且在stack中提供的接口有新增元素,移除元素,获得最顶端元素,但是获取元素只能获取stack的最顶端的元素。
因为stack可以在底层使用其他的一些容器来实现,所以这里我们考虑到了可以使用list,vector,还有要新介绍的容器deque。这里在STL源码中是使用了deque这个容器来实现的。
deque介绍
cpp文档查询deque
基本的介绍就不看了,注意deque提供的成员函数,是可以对容器内的元素进行随机访问,头插头删,看起来这是一个完美的容器,好像能解决list不能随机存储,也解决了vector头插的数据移动。
但,真的是这样吗?
这就是deque的基本结构,就是多个同等大小的“vector”链接起来的“list”,但是这个容器有两个最大的问题:一个是在元素内部插入或删除元素,会导致元素移动的问题,造成时间的浪费;其次就是随机访问,deque的通过下标随机访问是计算得出的,就算的过程也不是很简单的,所以多次的随机访问也会造成时间的浪费。
由于stack以底部容器完成其所有工作,这种可以自己选择容器的方法,称为adapter(适配器),这就就是为什么stack不被归类为container(容器),而被归类为contain_adapter
template>
class stack
{
friend bool operator==__STL_NULL_TMPL_ARGS(const stack&, const stack&);
friend bool operator< __STL_NULL_TMPL_ARGS(const stack&, const stack&);
public:
typedef typename Sequence::value_type value_type;
typedef typename Sequence::size_type size_type;
typedef typename Sequence::reference reference;
typedef typename Sequence::const_reference const_reference;
protected:
Sequence c;//底层容器
public:
//借助容器c对元素的操作完成stack的操作
bool empty() const { return c.empty(); }
size_type size() const { return c.size(); }
reference top() const { return c.back(); }
const_reference top() const; { return c.back(); }
void push(const value_type& x) { c.push_back(x); }
void pop() { c.pop_back(); }
};
template
bool operator==(const stack& x, const stack& y)
{
return (x.c == y.c);
}
template
bool operator<(const stack& x, const stack& y)
{
return (x.c < y.c);
}
stack中没有迭代器,stack不提供走访功能,也就不提供迭代器。
queue是一种先入先出的数据结构,具有两个元素,提供了新增,删除元素,从最底端加入元素,取得最顶端元素,但是除了从最底段增加元素,从最顶端删除元素,queue无法以其他的方式获得元素,也就是说,queue不允许有遍历行为。
queue和stack有很多相似的地方,在实现上也是运用了适配器,可以自定义底层容器,也是默认以deque作为底层容器的。只有在一些函数的实现上有所不同,所以话不多说,直接看源码:
template>
class queue
{
friend bool operator==__STL_NULL_TMPL_ARGS(const stack&, const stack&);
friend bool operator< __STL_NULL_TMPL_ARGS(const stack&, const stack&);
public:
typedef typename Sequence::value_type value_type;
typedef typename Sequence::size_type size_type;
typedef typename Sequence::reference reference;
typedef typename Sequence::const_reference const_reference;
protected:
Sequence c;//底层容器
public:
//借助容器c对元素的操作完成queue的操作
bool empty() const { return c.empty(); }
size_type size() const { return c.size(); }
reference front() const { return c.front(); }
const_reference front() const; { return c.front(); }
reference back() const { return c.back(); }
const_reference back() const; { return c.back(); }
void push(const value_type& x) { c.push_back(x); }
void pop() { c.pop_front(); }
};
template
bool operator==(const queue& x, const queue& y)
{
return (x.c == y.c);
}
template
bool operator<(const queue& x, const queue& y)
{
return (x.c < y.c);
}
queue中也没有迭代器,和stack一样,queue也是不可以遍历的。
priority_queue是一个拥有权值观念的queue,它允许加入新元素,移除旧元素,审视元素值等功能。这是一个queue,所以只允许在底端加入元素,并从顶端取出元素。除此之外别无其他存取元素的途径。
权值观念是什么?
就是其内的元素并非按照被推入的次序排列,而是自动依照元素的权值排列,权值最高者排在最前面。
priority_queue也是以底部容器为依据,加上heap处理规则,实现也是很简单的,默认的底部容器是vector。但是增加了一个仿函数,来确定是大堆还是小堆。
模拟实现一个priority_queue
namespace mypriority_queue
{
//大堆
//Compare是比较的仿函数 less->大堆 greater->小堆
template,class Compare = std::less>
class priority_queue
{
private:
Container _con;
public:
priority_queue()
{}
template //迭代器区间的构造函数
priority_queue(InputIterator first, InputIterator last)
{
while (first != last)
{
_con.push_back(*first);
++first;
}
//建堆
for (int i = (_con.size() - 1 - 1) / 2; i >= 0; --i)
{
adjust_down(i);//向下调整建堆
}
}
void adjust_up(size_t child)
{
Compare com;
size_t parent = (child - 1) / 2;
while (child > 0)
{
if (com(_con[parent],_con[child]))
{
std::swap(_con[child], _con[parent]);
child = parent;
parent = (child - 1) / 2;
}
else
{
break;
}
}
}
void adjust_down(size_t parent)
{
Compare com;
size_t 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[child], _con[parent]);
parent = child;
child = parent * 2 + 1;
}
else
break;
}
}
void push(const T& x)
{
_con.push_back(x);
adjust_up(_con.size() - 1);
}
void pop()
{
std::swap(_con[0], _con[_con.size() - 1]);
_con.pop_back();
adjust_down(0);
}
const T& top()
{
return _con[0];
}
size_t size() const
{
return _con.size();
}
};
}
priority_queue没有迭代器,priority_queue的所有元素,进出都有一定的规则,只有queue顶端的元素才可以被外界访问。
最后再提一下仿函数这里,仿函数实际就是一个类,重载了“()”,可以让类内使用这个函数重载来达到目的。
内容就到这里啦,大家学习愉快!!