首页 > 其他分享 >栈和stack

栈和stack

时间:2022-12-14 14:26:05浏览次数:48  
标签:ab const int top next stack size

1. 栈的实现

特点:先进后出、后进先出

1.1 顺序栈

顺序栈是依赖数组实现的。

其代码实现如下:

class SequenceStack {
public:
    SequenceStack(int size = 10);
    ~SequenceStack();

public:
    // 入栈
    void push(int val);
    // 出栈
    void pop();
    // 返回栈顶元素
    int top() const;
    // 栈是否为空
    bool empty() const;
    // 返回栈大小
    int size() const;
    // 打印
    void print() const;

private:
    // 数组扩容
    void expand(int size);

private:
    int* pStack_;
    int  top_; // 栈顶索引
    int  cap_; // 当前栈容量
};

SequenceStack::SequenceStack(int size)
    : pStack_(new int[size])
    , top_(0)
    , cap_(size) {
}

SequenceStack::~SequenceStack() {
    delete[] pStack_;
    pStack_ = nullptr;
}

void SequenceStack::push(int val) {
    if (top_ == cap_)
        expand(cap_ * 2);
    pStack_[top_++] = val;
}

void SequenceStack::pop() {
    if (top_ == 0) return;
    top_--;
}

int SequenceStack::top() const {
    if (top_ == 0)
        throw "Stack is empty";
    return pStack_[top_ - 1];
}

bool SequenceStack::empty() const {
    return top_ == 0;
}
 
int SequenceStack::size() const {
    return top_;
}

void SequenceStack::print() const {
    for (int i = top_ - 1; i >= 0; i--) {
        cout << pStack_[i] << " ";
    }
    cout << endl;
}

void SequenceStack::expand(int size) {
    int* p = new int[size];
    memcpy(p, pStack_, top_ * sizeof(int));
    delete[] pStack_;
    pStack_ = p;
    cap_    = size;
}

1.2 链式栈

链式栈是依赖链表实现的。

其代码实现如下:

class LinkedStack {
public:
    LinkedStack();
    ~LinkedStack();

    // 出栈
    void push(int val);
    // 入栈
    void pop();
    // 返回栈顶
    int top() const;
    // 返回栈大小
    int size() const;
    // 栈是否为空
    bool empty() const;
    // 打印
    void print() const;

private:
    struct Node {
        Node(int data = 0)
            : data_(data)
            , next_(nullptr) {
        }
        int   data_;
        Node* next_;
    };

    Node* head_;
    int   size_;
};

LinkedStack::LinkedStack()
    : head_(new Node)
    , size_(0) {
}

LinkedStack::~LinkedStack() {
    Node* cur = head_->next_;
    while (cur) {
        head_->next_ = cur->next_;
        delete cur;
        cur = head_->next_;
    }
    delete head_;
}

void LinkedStack::push(int val) {
    Node* node   = new Node(val);
    node->next_  = head_->next_;
    head_->next_ = node;
    size_++;
}

void LinkedStack::pop() {
    if (size_ == 0) return;
    Node* node   = head_->next_;
    head_->next_ = node->next_;
    size_--;
    delete node;
}

int LinkedStack::top() const {
    if (size_ == 0)
        throw "Stack is empty";
    return head_->next_->data_;
}

int LinkedStack::size() const {
    return size_;
}

bool LinkedStack::empty() const {
    return size_ == 0;
}

void LinkedStack::print() const {
    Node* node = head_->next_;
    while (node) {
        cout << node->data_ << " ";
        node = node->next_;
    }
    cout << endl;
}

2. 常见的算法问题

2.1 括号匹配问题

如下图所示,对于括号的匹配问题,可以使用栈结构来模拟括号匹配。

其基本的过程如下:

  • 如果遇到左括号就入栈
  • 如果遇到右括号
    • 如果栈为空则返回 false
    • 如果栈顶元素与当前的右括号不匹配则返回 false
    • 如果栈顶元素与当前的右括号匹配则弹出栈顶元素

练习题目: 20. 有效的括号 - 力扣(LeetCode)

2.2 逆波兰表达式求解

逆波兰表达式是一种后缀表达式,所谓后缀就是指运算符写在后面。

  • 通常所使用的算式称为中缀表达式,如 (1 + 2) * (3 + 4)
  • 该算式的逆波兰表达式为:( (1 2 +) (3 4 +) * )

逆波兰表达式主要有以下两个优点:

  • 去掉括号后表达式无歧义,上式即使写成 1 2 + 3 4 + * 也可以依据次序计算出正确的结果
  • 适合栈操作运算:遇到数字则入栈;遇到运算符则取出栈顶两个数字进行计算,并将结果压入栈中

例如对于后缀表达式:1 2 + 3 4 + * ,其计算过程如下表:

当前符号 数字栈 计算结果
1 1
2 1 2
+ 3 1 + 2 = 3
3 3 3
4 3 3 4
+ 3 7 3 + 4 = 7
* 3 * 7 = 21

将一个中缀表达式转化为后缀表达式的过程如下:

  • 从左到右依次扫描中缀表达式
  • 遇到数字则直接放入后缀表达式
  • 如果遇到操作符
    • 如果栈为空,则直接将操作符放入符号栈
    • 如果栈不为空,则比较当前符号和栈顶符号元素的优先级
      • 如果当前符号比栈顶符号的优先级高,则直接入栈
      • 如果当前符号比栈顶符号的优先级相等
        • 如果当前符号为从左到右结合,即 +、-、*、/ 等,那就将当前符号加入后缀表达式
        • 如果当前符号为从右到左结合,即 ^ 等,那就入栈
      • 如果当前符号比栈顶符号的优先级低,那就将当前符号放入后缀表达式
    • 如果遇到的是 (,则直接入栈
    • 如果遇到的是 ),则依次出栈,直到碰到 (

比如对于中缀表达式: ((a + b) c) / ((a - b) a^b) ,其转化过程如下表所示:

当前符号 后缀表达式 符号栈
( (
( ((
a a ((
+ a ((+
b ab ((+
) ab+ (
* ab+ (*
c ab+c (*
) ab+c*
/ ab+c* /
( ab+c* /(
( ab+c* /((
a ab+c*a /((
- ab+c*a /((-
b ab+c*ab /((-
) ab+c*ab- /(
* ab+c*ab- /(*
a ab+c*ab-a /(*
^ ab+c*ab-a /(*^
b ab+c*ab-ab /(*^
) ab+c*ab-ab^*/ /

练习题目: 150. 逆波兰表达式求解 - 力扣(LeetCode)

3. STL实现

STL 的 stack 实现了栈数据结构,它是一种先进后出的数据结构。由于 stack 系以底部容器完成其所有工作,而具有这种 “修改某物接口,形成另一种风貌” 之性质者,称为adapter(配接器),因此stack往往被归类为container adapter(容器适配器)

stack 所有元素的进出都必须符合 “先进后出” 的条件,只有 stack 的顶端元素,才有机会被外界取用。stack 不提供遍历功能,也不提供迭代器

除了使用 deque 作为底层容器外,stack 也可以使用双向链表 list 作为底层容器。

标签:ab,const,int,top,next,stack,size
From: https://www.cnblogs.com/tuilk/p/16981906.html

相关文章

  • 【collection】4.java容器之LinkedList,Stack,CopyOnWriteArrayList
    LinkedList节点数据结构/***泛型结构*@param<E>node*/privatestaticclassNode<E>{ Eitem; //双向链表,向前和向后 Node<E>next; Node<E>prev; N......
  • 使用 ServiceStack 构建跨平台 Web 服务
    WindowsCommunicationFoundation(WCF)是一个相当优秀的服务框架,当我们讨论跨平台的服务的时候,虽然WCF对WebService的支持还行,在面对一些高级应用的不......
  • 获取Openstack认证令牌
    在运行身份管理服务的典型OpenStack部署中,可以指定用于认证的项目名、用户名和密码凭证。下面以使用cURL命令为例进行示范。(1)首先导出环境变量OS_PROJECT_NAME(项目名)、OS_......
  • openstack ceph
    OpenStack集成ceph详细过程可以查看ceph官方文档:​​cephdocument​​OpenStackQueens版本,1台控制节点controller,1台计算节点compute;1.创建存储池Glance:Glance可以把镜像......
  • JVM 命令 jps jstat jstack
    jps显示出所有的JAVA进程以及PIDjstat查看堆内存各部分的使用量,以及加载类的数量jstack–用来查看堆栈信息jps-lvmVtop-Hppid将线程转换为16进制,因为堆......
  • ceph openstack 集成
    前言为什么要集成ceph???ceph官网:https://docs.ceph.com/en/latest/关于ceph:https://blog.csdn.net/mingongge/article/details/100788388参考连接:https://blog.csdn.net/jmil......
  • openstack ceph
    OpenStack集成ceph详细过程可以查看ceph官方文档:cephdocumentOpenStackQueens版本,1台控制节点controller,1台计算节点compute;1.创建存储池Glance:Glance可以把镜像存......
  • 【集成学习(下)】Task13 Stacking
    基于前面对Blending集成学习算法的讨论,我们知道:Blending在集成的过程中只会用到验证集的数据,对数据实际上是一个很大的浪费。为了解决这个问题,我们详细分析下Blending到底哪......
  • openstack介绍及原理
     openstack项目搭建:1、环境布署2、配置keystone服务3、配置glance服务4、配置placement服务5、配置nova服务控制节点6、配置nova服务计算节点7、配置neutron服务控制节点......
  • openstack上传镜像到glance
    以qcow2模板为例1.上传镜像qcow2文件到服务器。2.先转换qcow2格式为raw,例如:qemu-imgconvert-fqcow2-Orawwin2012r2.qcow2win2012r2.raw3.再将raw镜像上传到gl......