Java栈

1 栈

1.1栈的概念

栈是一种特殊的线性表,其只允许在固定的一端进行插入和删除操作。栈中的元素遵循先进后出的原则。

  • 压栈:栈的插入操作(入数据在栈顶)
  • 出栈:栈的删除操作(出数据在栈顶)

1.2 栈的使用

注意注释

package stackdemo;

import java.util.Stack;

public class TestDemo {
    public static void main(String[] args) {
        Stack<Integer> stack=new Stack<>();

        //给栈里面放元素
        stack.push(12);
        stack.push(23);
        stack.push(34);
        stack.push(45);

        //出栈
        //pop弹出并且删除元素
        int ret=stack.pop();
        System.out.println(ret);//45出,栈中已经没有了45
        //peek获取元素但是不删除
        int ret1=stack.peek();
        System.out.println(ret1);

        //栈是否为空
        System.out.println(stack.empty());
        System.out.println(stack.isEmpty());
    }
}

2 栈的应用

1 若进栈序列为1,2,3,4,进栈过程中可以出栈,则下列不可能的一个出栈序列是()A :1,4,3,2       

B :2,3,4,1     

C :3,1,4,2       

D :3,4,2,1

答案:C

进栈过程中可以出栈,比如A选项,先进1 再出1,再进2、进3、进4,再出4、出3、出2,即符合题意。

2 一个栈的初始状态为空。现将元素1、2、3、4、5、 A 、 B 、 C 、 D 、 E 依次入栈,然后再依次出栈,则元素出栈的顺序是()。
A :12345ABCDE 

B :EDCBA54321 

C : ABCDE12345 

D :54321EDCBA

答案:B

原因:依次入栈,然后再依次出栈

3 将中缀表达式(a+b+c*d)/e,转成后缀表达式ab+cd*+e/

技巧:(a+b+c*d)/e   ---> 

(1)加括号a+b+c*d/ e

(2)将各个括号里面的运算符拉到括号外面a b+ c d*)+  e /

(3)去掉所有的括号  a b+ c d*+  e /

  • 如果是数字就放到栈中
  • 如果是操作符,就取出栈顶两个元素,进行运算,把结果写会到栈中,继续遍历字符
  • 栈中最后的元素就是表达式的结果

3 练习题

(1)逆波兰表达式求值
有效的算符包括+、—、*、/,每个运算符对象可以是整数,也可以是另一个逆波兰表达式。
注意两个整数之间的除法只保留整数部分。
可以保证给定的逆波兰表达式总是有效的。换句话说,表达式总会得出有效数值且不存在除数为0的情况。

public class TestDemo {
    //求逆波兰表达式
    public int evalRPN(String[] tokens){
        Stack<Integer> stack=new Stack<>();
        for(String x : tokens){
            if(! isOperation(x)) {
                //说明当前的x是一个数字字符串
                stack.push(Integer.parseInt(x));//将字符串变成一个整数
            }else{
                //弹两个元素
                int num2=stack.pop();
                int num1=stack.pop();
                switch (x){
                    case "+" :
                        stack.push(num1+num2);
                        break;
                    case "-" :
                        stack.push(num1-num2);
                        break;
                    case "*" :
                        stack.push(num1*num2);
                        break;
                    case "/" :
                        stack.push(num1/num2);
                        break;
                }
            }
        }
        return stack.pop();
    }

    //判断s(某个字符串)是不是运算符
    private boolean isOperation(String s){
        if(s.equals("+") || s.equals("-") || s.equals("*") || s.equals("/")){
            return true;
        }
        return false;
    }
}

(2)递归逆序打印单链表

class ListNode {//节点
    public int val;
    public ListNode next;//类型是Node
    public ListNode(int val){
        this.val=val;
    }
}
public class SingleLinkedList {
    public ListNode head;
    //递归逆序打印单链表
    public void printList(ListNode head){//方法1
        if(head==null){
            return;
        }
        if(head.next==null){
            System.out.println(head.val+" ");
            return;
        }

        printList(head.next);
        System.out.print(head.val+" ");
    }

    public void printList2(){//方法2
        Stack<ListNode> stack=new Stack<>();
        ListNode cur=head;
        while (cur!=null){
            stack.push(cur);
            cur=cur.next;
        }
        while (!stack.empty()){//当栈不为空
            ListNode tmp=stack.pop();
            System.out.print(tmp.val+" ");
        }
        System.out.println();
    }

}

(3)括号匹配

给定一个只包括‘(’,‘)’,‘{’,‘}’,‘[’,‘]’的字符串 s ,判断字符串是否有效。
有效字符串需满足:
1.左括号必须用相同类型的右括号闭合。
2.左括号必须以正确的顺序闭合。

1>遍历字符串,如果是左括号,那么入栈。如果是右括号,则看栈顶元素是不是与之相匹配的。匹配的情况下出栈。

  • 当字符串遍历完成之后,栈还不是空的,那么说明左括号多。
  • 当遇到右括号之后,发现栈是空的,那么说明右括号多。 
  • 当 i 是右括号,栈顶元素是左括号,但是这个是不匹配的。此时说明左右括号不匹配。

2>直到栈为空且字符串遍历完成才说明左右括号是匹配的。

//括号匹配
    class Solution{
        public boolean isValid(String s){
            Stack<Character> stack=new Stack<>();
            for(int i=0;i<s.length();i++){
                char ch=s.charAt(i);
                if(ch=='(' || ch=='[' || ch=='{'){
                    //说明此是是左括号
                    stack.push(ch);//将左括号放入栈中
                }else {
                    //说明是右括号
                    //栈空不空  空不匹配-->右括号多,一上来就是右括号
                    if(stack.empty()){
                        return false;
                    }
                    char top=stack.peek();//获取栈顶元素  一定是一个左括号
                    if(ch==')'  &&  top=='(' || ch==']'  &&  top=='[' || ch=='}'  &&  top=='{'){
                        stack.pop();
                    }else {
                        return false;//左右括号不匹配
                    }

                }
            }
            if(!stack.empty()){
                return false;//字符串遍历完成,栈里面还有括号。此时说明左括号多
            }
            return true;
        }
    }

(4)输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否可能为该栈的弹出顺序。假设压入栈的所有数字均不相等。例如序列1,2,3,4,5是某栈的压入顺序,序列
4,5,3,2,1是该压栈序列对应的一个弹出序列,但4,3,5,1,2就不可能是该压栈序列的弹出序列。
1.0<= pushV . length == popV.length <=1000

2.-1000<= pushV [ i ]<=1000
3. pushV 的所有数字均不相同

//出栈入栈次序匹配
    public class Solution{
        public boolean IsPopOrder(int [] pushA,int [] popA){
            Stack<Integer> stack=new Stack<>();
            int j=0;//用来遍历popA数组
            for(int i=0;i<pushA.length;i++){
                stack.push(pushA[i]);
                //j不能越界,栈不能为空
                while (j<popA.length && !stack.empty() && stack.peek()==popA[j]){
                    stack.pop();
                    j++;
                }
            }
            return stack.empty();
        }
    }

栈、虚拟机栈、栈帧的区别

答:栈-->数据结构;虚拟机栈-->JVM的内存;栈帧-->当运行函数时,会在Java虚拟机栈上,开辟栈帧给当前函数。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值