参考资料:《大话数据结构》

栈(Stack)

说起栈,应该都会想起“先进后出”这四个字,之前在考计算机二级的时候看过一些数据结构的知识,当时也就记住了这四个字,也不太清楚具体可以在哪些方面应用,直到后来系统的学习了数据结构,才发现原来可以这么搞。

1. 定义

栈是限定仅在表尾进行插入和删除操作的线性表。故栈是线性结构,可以想象成水杯,水只能从一个口进出。把允许插入和删除的一端(杯口)称为栈顶,另一端(杯底)称为栈底。向栈中插入元素称为压栈,也称进栈、入栈,从栈中删除元素称为弹栈,也称出栈。栈顶指针(top)永远指向最靠近栈顶的元素,压栈和弹栈都是根据栈顶指针来进行操作。

在这里插入图片描述


由于栈也是一个线性表,故其有顺序储存结构和链式储存结构

2.栈的顺序储存结构

栈的顺序储存结构,其底层是用数组实现的,我们把数组下标为0的一端规定为栈底。栈顶指针可为数组的下标,规定当栈为空时,栈顶指针top的值为-1(处于栈底位置),且top的值要小于等于数组长度减一(下图数组长度为5)。
在这里插入图片描述
则定义一个栈需要两个参数:数组和栈顶指针。

int[] Stack = new int[len]; //len为数组长度
int top = -1;  //top为栈顶指针,一般初始化为-1

压栈

在进行压栈操作之前,我们应先判断下栈是否满了(如果水杯中的水满了,还怎么往里面倒水)。方法其实很简单,根据栈顶指针的定义(永远指向最靠近栈顶的元素),只要判断top是否和数组长度减一相等即可,若相等及说明栈满,不等则不满。

 public boolean isFull(){
        if(top == len - 1)
            return true;
        else
            return false;
    }

现在进行压栈操作,如下图,假设数组长度为5,栈中现有三个元素(a1,a2和a3),先往栈中压入a4。我们应先将栈顶指针上移一位,然后再把a4添加到栈中。
在这里插入图片描述

 public boolean push(int val) {  //val为要添加的值

            if(isFull())
                return false;  //栈满,无法压栈

            arr[++top] = val;  //栈顶指针先上移一位,在入值
            return true;
    }

弹栈

和压栈一样,在弹栈之前应该检查一下栈是否为空(水杯里面没有水,怎么往外倒)。栈为空时,其栈顶指针top为-1,故其判断非常简单。

public boolean isEmpty() {
        if(top == -1)
            return true;
        else
            return false;
    }

现在进行弹栈操作,压栈的时候是栈顶指针先上移一位,然后再添加相应元素,而弹栈恰恰相反,我们先取出要删除的值(此时栈顶指针指向的值),再把栈顶指针下移一位(这样保证删除的元素为栈顶元素,满足先进后出,同时保证了弹栈之后栈顶指针始终指向最靠近栈顶的元素)。

public boolean pop(){

        if(isEmpty())
            return false; //栈为空

        val = arr[top--];   //先删除栈顶元素,再将栈顶指针下移一位
        return true;
    }

3.栈的链式储存结构(链栈)

栈的链式存储结构,其底层是链表。由于链表有头指针,所以我们把栈顶放在链表的头部,而头指针可看成栈顶指针(无头结点)。栈为空时,栈顶指针为null。
在这里插入图片描述
压栈

由于其底层为链表,所以不存在满的情况。下图s为新入栈的结点,有点像链表的头插法。
在这里插入图片描述

 public void push(int e){

        Node s = new Node(val);   //先生成一个新结点s
        s.data = e;
        s.next = top; //top现在仍指向原来的栈顶元素ai
        top = s; //top指向s,s现在为栈顶元素(top始终指向栈顶元素)
    }

弹栈

进行弹栈操作之前,先要判断栈是否为空,即top是否为null。

public boolean isEmpty() {
        if(top == null)
            return true;
        else
            return false;
    }

现在进行弹栈操作。如下图,弹出栈顶元素ai。
在这里插入图片描述

 public boolean pop() {

	    if(isEmpty())
            return false; //栈为空
        
        val = top.data;  //出栈的值赋给val,top此时指向要删除的元素
        Node p = top.next;  //p指向top的下一个结点(栈顶元素的下面一个元素)
        top = p; //top指向下一个结点
        return true;
    }

关于栈的应用

主要是利用其先进后出的特点。

  • 函数的调用(学Java的时候画内存图时,有一个栈内存,对于方法的压栈和弹栈)
  • 对于四则表达式求值(后面会有介绍)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
引用\[1\]提供了一个朴素的解法,使用两个来存储字符串,一个用来存储普通字符,另一个用来存储特殊字符。遍历字符串,如果是普通字符则压入第一个,如果是特殊字符则弹出第一个顶元素。最后比较两个是否相同即可判断字符串是否有效。这个解法的时间复杂度是O(M + N),空间复杂度也是O(M + N)。\[1\] 引用\[2\]提供了另一个的应用场景,即判断括号是否有效。遍历字符串,如果是左括号则压入,如果是右括号则判断和顶元素是否匹配,不匹配则返回false,匹配则弹出顶元素。最后判断是否为空即可判断括号是否有效。\[2\] 引用\[3\]也提供了一个判断括号是否有效的解法,使用来操作。遍历字符串,如果是左括号则压入,如果是右括号则判断和顶元素是否匹配,不匹配则返回false,匹配则弹出顶元素。最后判断是否为空即可判断括号是否有效。这个解法使用了HashMap来存储括号的对应关系。\[3\] 综上所述,在解决字符串相关问题中有着广泛的应用,包括判断字符串是否有效、逆波兰表达式等。在解决这些问题时,可以帮助我们保存和处理字符的顺序,从而简化问题的处理过程。 #### 引用[.reference_title] - *1* *3* [Leetcode刷题03-](https://blog.csdn.net/weixin_47802917/article/details/123007699)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v4^insert_chatgpt"}} ] [.reference_item] - *2* [leetCode-类型详解](https://blog.csdn.net/zhiyikeji/article/details/125508011)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v4^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值