《STL源码剖析》笔记-stack、queue

版权声明:本文为博主原创文章,转载请注明出处。 https://blog.csdn.net/WizardtoH/article/details/82707771

上一篇:《STL源码剖析》笔记-deque

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;
}

下一篇:《STL源码剖析》笔记-priority_queue、heap算法

猜你喜欢

转载自blog.csdn.net/WizardtoH/article/details/82707771