stl标准库系列之--stack

1、什么是容器适配器

理解容器适配器之前,我们需要了解什么是适配器,其实和我们现实中的适配器是差不多的理解。也可以去了解下设计模式中的适配器模式

容器适配器是一个封装了序列容器的类模板。是在一般的序列容器的基础上提供了一些功能。所谓的容器适配器,目的就是为了适配基础容器现有的接口来提供不同的功能。

适配器类在基础序列容器的基础上实现了一些自己的操作。它们提供的优势是简化了公共接口,而且提高了代码的可读性。

STL标准库中目前有3种容器适配器。stack、queue、priority_queue。
下表显示了stl标准库中的3种容器适配器的比较。

容器适配器基础序列容器满足条件基础序列容器默认序列容器
stack先进后出(FILO)
push_back()
pop_back()
vector、list、dequedeque
queue先进先出(FIFO)
front()
back()
push_back()
pop_front()
listdeque
priority_queue有权重,默认第一个元素权重最高vector、dequevector

我们今天主要来看stack适配器

2、stack 容器的定义

stack是一种先进后出(FILO)的数据结构,只有一个出口,通常被称作是栈顶。因为只有一个出口,因此对于数据的存取,访问元素只能访问离开口最近的元素,只有当这个元素被移除之后,才能访问下一个元素。

我们先大概的看一下stack的图形示意。
在这里插入图片描述

看下stl中stack的源码:

template <class _Tp, class _Sequence>
class stack {

// requirements:

__STL_CLASS_REQUIRES(_Tp, _Assignable);
__STL_CLASS_REQUIRES(_Sequence, _BackInsertionSequence);
typedef typename _Sequence::value_type _Sequence_value_type;
__STL_CLASS_REQUIRES_SAME_TYPE(_Tp, _Sequence_value_type);

public:
    typedef typename _Sequence::value_type      value_type;
    typedef typename _Sequence::size_type       size_type;
    typedef          _Sequence                  container_type;

    typedef typename _Sequence::reference       reference;
    typedef typename _Sequence::const_reference const_reference;
protected:
    _Sequence c;
public:
    stack() : c() {}
    explicit stack(const _Sequence& __s) : c(__s) {}

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

通过上面的源码我们能够看到,基本上stack的成员函数操作都只是调用了其内置序列容器的方法。

3、stack 容器创建

#include <stack>
using namespace std;

1、 创建一个不包含任何元素的 stack 适配器,并采用默认的 deque 基础容器

std::stack<int> data;

2、创建指定底层容器的 stack 适配器

上面我们介绍容器适配器的时候,看到,满足 stack 容器适配器功能的底层序列容器有3个,vector、list、deque。stack 默认是以deque为底层容器的。下面我们看看另外两种的创建。

std::stack<int, std::vector<int>> data;  //以vector为底层容器,创建一个空的stack

//以有元素的vector为基础序列容器创建的stack含有vector的元素
std::vector<int> vec{1, 2, 3};
std::stack<int, std::vector<int>> data(vec);
stack<int, std::list<int>> data; //以list为底层容器,创建一个空的stack

std::list<int> values {5, 6, 7, 8};
std::stack<int, std::list<int>> data(values);

3、赋值

std::list<int> values {5, 6, 7, 8};
std::stack<int, std::list<int>> data(values);

std::stack<int, std::list<int>> data1 = data;

通过这种赋值的方法来创建新的stack适配器,是不会影响第一个适配器的,也就是是不会影响data的。

4、迭代器

stack没有其他的访问元素的方法,也就意味着,stack是不能被遍历的,因此也不提供迭代器。

5、成员函数

成员函数函数说明
empty()判断stack是否为空,为空返回true,否则返回false
size()返回stack中的元素的实际个数
(const) top()返回栈顶元素的引用(const),栈为空则报错
push(const T& val)调用底层的push_back函数,先复制,压入副本
push(T&& obj)移动元素的方式压入栈,底层容器支持
pop()弹出栈顶元素
emplace(arg…)arg… 可以是一个参数,也可以是多个参数,但它们都只用于构造一个对象,并在栈顶直接生成该对象,作为新的栈顶元素
swap(stack & other_stack)将两个 stack 适配器中的元素进行互换,两个栈的基础容器、元素类型必须相同

6、使用

我们通过一个例子来看下stack的创建以及使用。

#include <iostream>
#include <stack>
#include <list>
#include <vector>
#include <cstring>

using namespace std;

template<class T>
void display(T& data)   //注意函数的入参,会修改传入的变量
{
//    int nCount = data.size();
//    for(int nIndex = 0; nIndex < nCount; ++nIndex)  //如果使用for循环遍历,则不能用data.size()直接代替nCount,因为data.pop()会改变data.size()
    while (!data.empty())
    {
        cout << data.top() << " ";
        data.pop();
    }
    cout << endl;
}

int main(int argc, char* argv[])
{
    stack<int> data0;
    for(int nIndex = 0; nIndex < 10; ++nIndex)
    {
        data0.push(nIndex);
    }
    display(data0);     // 9 8 7 6 5 4 3 2 1 0

    stack<int, vector<int>> data;
    for(int nIndex = 0; nIndex < 10; ++nIndex)
    {
        data.push(nIndex);
    }
    display(data);      // 9 8 7 6 5 4 3 2 1 0

    vector<int> primes {1, 2, 3, 4};
    stack<int, vector<int>> data1(primes);
    display(data1);     // 4 3 2 1

    stack<int, list<int>> data2;
    for(int nIndex = 1; nIndex <= 10; ++nIndex)
    {
        data2.push(nIndex * 2);
    }
    display(data2);     // 20 18 16 14 12 10 8 6 4 2

    list<int> values {5, 6, 7, 8};
    stack<int, list<int>> data3(values);
    display(data3);     // 8 7 6 5

    list<int> value {11, 12, 13, 14};
    stack<int, list<int>> data4(value);
    stack<int, list<int>> data5 = data4;
    display(data5);     // 14 13 12 11
    display(data4);     // 14 13 12 11
    return 0;
}

运行结果:
在这里插入图片描述
需要注意的是:display函数的入参的形式,会影响传入的stack。比如:如果传入的是引用,则进行一轮打印遍历之后,则传入的stack中的元素会全部被pop掉。此时的stack为空。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值