栈的概念与使用

 

目录

 

      一. 栈的概念:

        什么是入栈?出栈?

         二. 栈的初始化:

        栈的 方法 的使用:

        三 . 关于使用栈实现的题目:

         1.括号匹配 。 题目链接

        2.逆波兰表达式求值。题目链接

        3.出栈入栈次序匹配。题目链接

        4.最小栈。题目链接


      一. 栈的概念:

         是⼀种特殊的线性表,其只允许在固定的一端进行插入和删除元素操作。进行数据插入和删除操作的一端称为栈顶,另一端称为栈底。栈中的数据元素遵守后进先出的原则。

        那么,后进先出怎么理解?

        如图:

                

         假如,里面的不同颜色代表元素,那么可以知道,这个栈没有元素之前,红色元素是最先进去的,再到绿色元素,最后到蓝色元素,那么,元素出栈时,遵循后进先出原则,也就是蓝色元素先出出栈,再到绿色元素出栈,最后是红色元素出栈。

        

        什么是入栈?出栈?

        1. 栈的插入数据操作叫做 入栈 或者 压栈 或者叫 进栈 。

        2. 栈的删除数据操作叫做 出栈。

        注意:入栈和出栈都是在 栈顶 操作的。

        

         二. 栈的初始化:

         栈是利用Stack < > 进行初始化的:

Stack<Integer> stack1 = new Stack<>();

        这里构造了一个 引用名为 stack1 的栈,操作元素类型是 整型 。

        

        栈的 方法 的使用:

        以下的列表为栈的使用方法:

        

        

         在这里值得注意的是,empt 方法 返回的类型是 boolean ,如果栈为空返回 true ,否则返回 false .

        

        

        三 . 关于使用栈实现的题目:

         1.括号匹配 。 题目链接

        题解代码

 public boolean isValid(String s) {
        Stack<Character> stack = new Stack<>();
        for(int i =0 ;i < s.length();i++) {
            char ch = s.charAt(i);

            if(isfull(ch)) {
                stack.push(ch);
            }else {
                //先判断栈是否为空
                if(stack.empty()) {
                    return false;
                }
                if(stack.peek() == '(' && ch == ')' || 
                stack.peek() == '[' && ch == ']' || 
                stack.peek() == '{' && ch == '}') {
                    stack.pop();
                } else {
                    return false;
                }
            }
        }

        //字符串遍历完后查看栈是否为空
        if(stack.empty()) {
            return true;
        }
        return false;
    }

    public static boolean isfull(char ch) {
        if(ch == '(' || ch == '[' || ch == '{') {
            return true;
        }
        return false;
    }

        题解思路

        首先,我们要理清一个问题,为什么使用了栈可以解决这个问题。

        因为栈的特点就是 后进先出 ,所以当遇到这种左右括号匹配的问题就可以很好解决。

        一.大致思路:

        先遍历当前的字符串,遇到左括号就放进栈里,遇到右括号就拿出来与栈顶的括号对比,如果是匹配的,栈就出栈一个括号,有三种情况是括号不匹配的:

        

        如果如果最后 字符串遍历完成,且栈为空 说明括号是匹配的,返回true。

        二.具体思路:

        首先定义一个栈 stack, 遍历通过字符串 得到每一个括号,放在 ch 里。

        实现一个方法isfull,判断当前字符 ch 是否为 左括号,如果是就入栈,如果不是就可以拿出来与栈顶元素对比了,但是在那之前,要先判断栈是否为空,如果栈已经空了,说明 当前的是不匹配的,直接返回false 。

        进入到对比阶段,通过栈的peek方法查看栈顶元素是否与当前 ch 匹配,匹配的话就出栈,否则返回false 。

        当字符串遍历完成后,还要判断当前栈是否为空,如果栈为空,返回true;否则返回false。

        

        

        2.逆波兰表达式求值。题目链接

        题解代码

 public int evalRPN(String[] tokens) {
        Stack<Integer> stack = new Stack<>();

        for(int i = 0;i < tokens.length;i++) {
            String s = tokens[i];

            if( !isfull(s)) {
                Integer ret = Integer.valueOf(s);
                stack.push(ret);

            } else {
                    int num1 = stack.pop();
                    int num2 = stack.pop();
                switch(s) {
                    case "+":
                    stack.push(num2+num1);
                    break;

                    case "-":
                    stack.push(num2-num1);
                    break;

                    case "*":
                    stack.push(num2*num1);
                    break;

                    case "/":
                    stack.push(num2/num1);
                    break;
                }
            }
        }
        return stack.pop();
    }
    public boolean isfull(String s) {
        if(s.equals("+") || s.equals("-") || s.equals("*") || s.equals("/")) {
            return true;
        }
        return false;
    }

        题解思路

        首先,这题的计算是这样理解的:

        假如由这个 “ 1 2 3 * + 1 2 * -  ” 组成的逆波兰表达式。

        首先,定义一个栈,再遍历 这个字符串数组,如果遇到数字,把数字字符串转换成数字放进栈里,如果遇到运算符,则弹出 栈里的两个数字,先出栈的作为右操作数,后出栈作为左操作数,把他们的运算结果再放进栈里,直到遍历完这个字符串数组,此时栈里还剩最后一个元素,再返回这最后一个栈里的元素就是结果。

       注意:把数字字符串转换成数字使用了 Integer.valueOf()方法,该方法会尝试解析传入的字符串内容,按照十进制整数的格式规则来识别其中的数字信息,并将其转换为对应的Integer对象。

        

        3.出栈入栈次序匹配。题目链接

        题解代码

  Stack<Integer> stack = new Stack<>();

        int j = 0;
        for(int i =0;i < pushV.length;i++) {
            stack.push(pushV[i]);
            while(!stack.empty() && j < popV.length && stack.peek() == popV[j]) {
                stack.pop();
                j++;
            }
        }
        return stack.empty();

        题解思路

        首先,给pushV 定义一个 i 下标用来遍历,popV 数组用 j 遍历,元素放到栈里,如果当前栈顶元素是 另一个popV数组的 j 下标的元素,那么弹出当前栈顶元素,popV数组下标往后走一步

        如果当前栈顶元素不是另一个popV数组的 j 下标的元素,那么 让 i 下标遍历pushV数组元素放到栈里,直到当前栈顶元素是 另一个popV数组的 j 下标的元素。

        但是要注意,while循环的条件语句不能缺少 !stack.empty() && j < popV.length ;并且还要在其最前面,以防最后的 i 遍历pushV 数组 或者 j 遍历popV 数组导致空指针异常。

        最后,如果栈还有元素,说明其 i 下标已经遍历完 pushV数组了,并且栈顶元素与popV j 下标元素不相等,证明两个数组 次序不匹配。stack.empty( )会返回false;否则返回true

        

        

        4.最小栈。题目链接

        题解代码

 Stack<Integer> stack;
     Stack<Integer> minStack;


    public MinStack() {
        stack = new Stack<>();
        minStack = new Stack<>();

    }
    
    public void push(int val) {
        stack.push(val);
        if(minStack.empty()) {
            minStack.push(val);
        } else {
            if(val <= minStack.peek()) {
                minStack.push(val);
            }
        }
    }
    
    public void pop() {
        int ret = stack.pop();
        if(minStack.peek() == ret) {
            minStack.pop();
        }
    }
    
    public int top() {
       return  stack.peek();
    }
    
    public int getMin() {
       return  minStack.peek();
    }

        题解思路

        我们定义两个栈,一个普通栈,一个最小栈,这里最小栈的特点是每次弹出栈都是其普通栈当中元素的最小值

        1.对于push方法,val 值普通栈都要放,但是对于最小栈来说:

        如果val是第一次入最小栈,直接放进,如果 val 不是第一次入最小栈,则判断 val 与 当前最小栈的栈顶元素大小关系,如果 val 比最小栈的栈顶元素 小或者等于,则把 val 放进去。这是为了维护 pop 方法 的效果

        2.对于pop方法,普通栈都要弹出;对于最小栈,如果普通栈弹出的元素是最小栈的栈顶元素,则最小栈也要弹出。

        3.对于getMin方法,获取堆栈中的最小元素,由于上面方法的实现。每次弹出最小栈的栈顶元素都是普通栈当中的最小元素。
        

评论 28
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值