数据结构:栈

什么是栈:

栈是一种特殊的线性表,仅能在线性表的一端操作,栈顶允许操作,栈底不允许操作。 栈的特点是:先进后出,或者说是后进先出,从栈顶放入元素的操作叫入栈,取出元素叫出栈。

栈的结构就像一个集装箱,越先放进去的东西越晚才能拿出来,所以,栈常应用于实现递归功能方面的场景,例如斐波那契数列。

代码实现:

public class Stack<T> implements Iterable<T>{

    //记录首个节点
    private Node head;
    //记录栈中个数
    private int N;


    public Stack() {
        head=new Node(null,null);
        N=0;
    }

    public void push(T t){ //元素入栈
        Node temp=head.next; //暂时保留目前栈顶元素
        head.next=new Node(t,temp);//相当于头插法
        N++; //元素个数+1
    }

    public T pop(){ //栈顶弹出元素
        Node temp=null;

        if (head.next==null){
            return null;
        }
        //删除首个元素
        temp=head.next;
        head.next=temp.next;
        N--;
        return temp.item; //temp就是被删除的元素
    }

    public int getSize() { //获取与元素个数
        return N;
    }

    @Override
    public Iterator<T> iterator() {
        return new StackIterator();
    }

    private class StackIterator implements Iterator<T>{

        private Node n=head;
        @Override
        public boolean hasNext() {
            return n.next!=null;
        }

        @Override
        public T next() {

                Node node = n.next;
                n = n.next;
                return node.item;

        }
    }


    private class Node{
        private T item;
        private Node next;

        public Node(T item, Node node) {
            this.item = item;
            this.next = node;
        }
    }

}



public class TestStack {
    public static void main(String[] args) {
        Stack<String> stack=new Stack<>();
        stack.push("a");
        stack.push("b");
        stack.push("c");
        for (String s : stack) {
            System.out.println(s);
        }

        String pop = stack.pop();
        String pop2 = stack.pop();
        System.out.println("弹出了元素:"+pop);
        System.out.println("弹出了元素:"+pop2);
    }
}

//运行结果
c
b
a
弹出元素:c
弹出元素:b
括号匹配问题:

思路:

通过一个栈结构,当匹配到一个"("时进行入栈,然后当匹配到")"就进行出栈操作。所以就会出现两种情况:

1.匹配到")"进行出栈操作时,出栈元素为null,那么就表示在这之前没有匹配到"(",表示不是严格按照()规则。

2.当字符串匹配完毕后,发现栈中仍然还有元素,那么就表示(和)数量不对等,同样也不是严格按照()规则。

代码:

public class BracketMatch {

    public static void main(String[] args) {
        String s="(上海((北京))";
        isMatch(s);
    }
    //括号匹配
    public static void isMatch(String str){
        Stack<String> stack=new Stack<>();

        for (int i = 0; i < str.length(); i++) {
            String s = str.charAt(i) + ""; //返回字符串元素
            if (s.equals("(")){  //匹配到一个左括号( 则入栈
                stack.push(s);
                continue;
            }
            if (s.equals(")")){  //如果匹配到) 括号
                String pop = stack.pop();
                if (pop==null){  //如果匹配到) 而弹出的栈是null时 那么就表示该字符串 不是严格的遵守()规则
                    System.out.println("没有严格遵守()规则");
                }
            }
        }
        if (stack.getSize()!=0){ //如果栈中还剩有元素  那就代表(和)数量不对等 同样不符合规则
            System.out.println("没有严格遵守()规则");
        }else {
            System.out.println("该字符串是严格遵守()规则");
        }

    }
}
逆波兰求值问题:

中缀表达式:

中缀表达式就是日常生活中常用的表达式:如1+3*2,中缀表达式的特点就是二元运算符总是置于两个操作数的中间。而这种表达式对于计算机而言,就比较难以解决了,因为不同运算符有优先级问题,所以需要解析表达式语意等大量工作。所以为了解决该问题就引入了后缀表达式。

后缀表达式:

后缀表达式的特点就是运算符是在操作数(通常是两数)之后。

逆波兰式的求解过程可以用来实现。为了便于理解,举一个带数值的例子:

中缀表达式:6 * ( ( 5 + ( 2 + 3 ) * 8 ) + 3 )

首先,转化为逆波兰式: 6 5 2 3 + 8 * + 3 + *

首先,将前四个数依次入栈:

|-----------------------------------|---|
| Top Of Stack ------------------> | 3 |
| | 2 |
| | 5 |
| | 6 |

然后,遇到第一个符号为加号,记录并弹出栈顶的两个元素,计算结果后压入栈中

|-----------------------------------|---|
| | |
| Top Of Stack ------------------> | 5 |
| | 5 |
| | 6 |

继续操作,遇到便数字压入栈中,遇到符号,弹出栈顶两元素并压入其结果

(特别提醒:在减法和除法的计算中,数字弹出顺序与其计算顺序刚好相反)

|-----------------------------------|-----|
| | |
| | |
| | |
| Top Of Stack ------------------> | 288 |

代码实现:

public class ReversePolish {
    public static void main(String[] args) {
        //中缀表达式6 * ( ( 5 + ( 2 + 3 ) * 8 ) + 3 )
        //对应的后缀表达式
        String str="6523+8*+3+*";
        caculate(str);

    }



    public static void caculate(String str){
        Stack<String> stack=new Stack<>();
        for (int i = 0; i < str.length(); i++) {
            String s = String.valueOf(str.charAt(i));
            //进行运算符判断
            switch (s){
                case "+": //如果匹配到+ 则弹出栈顶的两个元素进行+
                    Integer num1 = Integer.valueOf(stack.pop());
                    Integer num2 =Integer.valueOf( stack.pop());
                    Integer integer = num1 + num2;
                    stack.push(String.valueOf(integer));  //将操作完的数再入栈
                    break;
                case "-": //-和除需要注意顺序 应该是第二个弹出栈的-去第一个弹出栈的
                    Integer minus1 = Integer.valueOf(stack.pop());
                    Integer minus2 = Integer.valueOf(stack.pop());
                    int minus = minus2 - minus1;
                    stack.push(String.valueOf(minus));
                    break;
                case "*":
                    Integer mulit1 = Integer.valueOf(stack.pop());
                    Integer mulit2 =Integer.valueOf( stack.pop());
                    Integer mulit = mulit1 * mulit2;
                    stack.push(String.valueOf(mulit));
                    break;
                case "/"://-和除需要注意顺序 应该是第二个弹出栈的-去第一个弹出栈的
                    Integer divide1 = Integer.valueOf(stack.pop());
                    Integer divide2 = Integer.valueOf(stack.pop());
                    int divide = divide2 / divide1;
                    stack.push(String.valueOf(divide));
                    break;
                default: stack.push(s); //如果是数字 则直接入栈
                    break;
            }
        }
        for (String s : stack) {
            System.out.println(s);  //打印最后元素
        }
    }
    
}
相关推荐
customer0813 分钟前
【开源免费】基于SpringBoot+Vue.JS体育馆管理系统(JAVA毕业设计)
java·vue.js·spring boot·后端·开源
Miketutu1 小时前
Spring MVC消息转换器
java·spring
乔冠宇1 小时前
Java手写简单Merkle树
java·区块链·merkle树
LUCIAZZZ2 小时前
简单的SQL语句的快速复习
java·数据库·sql
来恩10032 小时前
C# 类与对象详解
开发语言·c#
komo莫莫da2 小时前
寒假刷题Day19
java·开发语言
Rachela_z2 小时前
代码随想录算法训练营第十四天| 二叉树2
数据结构·算法
细嗅蔷薇@2 小时前
迪杰斯特拉(Dijkstra)算法
数据结构·算法
ElseWhereR2 小时前
C++ 写一个简单的加减法计算器
开发语言·c++·算法
S-X-S3 小时前
算法总结-数组/字符串
java·数据结构·算法