版权声明:本文为博主原创文章,转载请注明出处。 https://blog.csdn.net/WizardtoH/article/details/82707771
stack
stack是一种先进后出的数据结构,它只有一个出口,只能够在顶端新增、移除、取得元素,没有其他方式进行操作。并且stack默认示意deque作为基础容器来实现的,因为vector在扩容的时候有较差的时间复杂度,而list虽然有平稳的时间复杂度,但是总体平均复杂度较高,所以折中使用deque作为stack的底层容器。另外stack没有迭代器,因为只支持先进后出,只有顶端元素能被访问。
stack定义完整列表
stack以底部容器来完成其所有工作,这种修改了原来某物接口形成的新物,被称为adapter,对于容器来说就是container adapter。
template <class T, class Sequence = deque<T> >
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; // 底层容器,默认为deque
public:
//Sequence接口的封装
bool empty() const { return c.empty(); }
size_type size() const { return c.size(); }
reference top() { 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 <class T, class Sequence>
bool operator==(const stack<T, Sequence>& x, const stack<T, Sequence>& y) {
return x.c == y.c;
}
template <class T, class Sequence>
bool operator<(const stack<T, Sequence>& x, const stack<T, Sequence>& y) {
return x.c < y.c;
}
以list/vector作为stack的底层容器
stack默认的底层容器为deque,但是用list或vector也能实现:
int main()
{
std::stack<int, std::list<int>> stk;
// std::stack<int, std::vector<int>> stk;
stk.push(1);
stk.push(2);
stk.push(3);
std::cout << stk.size() << std::endl;
std::cout << stk.top() << std::endl;
stk.pop();
std::cout << stk.size() << std::endl;
std::cout << stk.top() << std::endl;
stk.pop();
std::cout << stk.size() << std::endl;
std::cout << stk.top() << std::endl;
stk.pop();
std::cout << stk.size() << std::endl;
return 0;
}
他们的差别在于效率,那么效率差别有多大,来做一下测试。通过以下代码输出结果可以发现,deque作为底层容器在刚开始时效率要低于list和vector,但是数量增大时list的效率显著下降,vector仍然优于deque。不过数量为16时,vecotr的效率突然增大,介绍vector的时候说道在,vector扩容的时候是成倍增加空间,所以效率会突然下降。
#include <list>
#include <stack>
#include <chrono>
using namespace std::chrono;
template <typename T>
long long stack_test(int count)
{
// 计算时间差,详见https://blog.csdn.net/WizardtoH/article/details/81738682
time_point<steady_clock> begin_time = steady_clock::now();
std::stack<int, T> stk;
for (int i = 0; i < count; ++i)
{
stk.push(i);
}
time_point<steady_clock> end_time = steady_clock::now();
return duration_cast<microseconds>(end_time - begin_time).count();
}
int main(int argc, char **argv)
{
std::cout << "deque 10: " << stack_test<std::deque<int>>(10) << std::endl;
std::cout << "vector 10: " << stack_test<std::vector<int>>(10) << std::endl;
std::cout << "list 10: " << stack_test<std::list<int>>(10) << std::endl;
std::cout << "deque 1k: " << stack_test<std::deque<int>>(1000) << std::endl;
std::cout << "vector 1k: " << stack_test<std::vector<int>>(1000) << std::endl;
std::cout << "list 1k: " << stack_test<std::list<int>>(1000) << std::endl;
std::cout << "deque 10w: " << stack_test<std::deque<int>>(100000) << std::endl;
std::cout << "vector 10w: " << stack_test<std::vector<int>>(100000) << std::endl;
std::cout << "list 10w: " << stack_test<std::list<int>>(100000) << std::endl;
std::cout << "deque 16: " << stack_test<std::deque<int>>(16) << std::endl;
std::cout << "vector 16: " << stack_test<std::vector<int>>(16) << std::endl;
std::cout << "list 16: " << stack_test<std::list<int>>(16) << std::endl;
return 0;
}
// 输出结果
deque 10: 119
vector 10: 63
list 10: 38
deque 1k: 1215
vector 1k: 1028
list 1k: 1829
deque 10w: 127786
vector 10w: 106870
list 10w: 198175
deque 16: 29
vector 16: 45
list 16: 34
queue
queue是一种先进先出的数据结构,它允许在队尾追加元素和访问队尾元素, 在队头获取和移除元素,除此之外其不支持其它元素的访问。和stack一样,它不需要迭代器,并且也是一种container adapter,默认以deque为底层容器。
queue定义完整列表
template <class T, class Sequence = deque<T> >
class queue
{
friend bool operator== __STL_NULL_TMPL_ARGS (const queue& x, const queue& y);
friend bool operator< __STL_NULL_TMPL_ARGS (const queue& x, const queue& y);
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:
bool empty() const { return c.empty(); }
size_type size() const { return c.size(); }
reference front() { return c.front(); }
const_reference front() const { return c.front(); }
reference back() { 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 <class T, class Sequence>
bool operator==(const queue<T, Sequence>& x, const queue<T, Sequence>& y)
{
return x.c == y.c;
}
template <class T, class Sequence>
bool operator<(const queue<T, Sequence>& x, const queue<T, Sequence>& y)
{
return x.c < y.c;
}