什么是栈:
栈是一种特殊的线性表,仅能在线性表的一端操作,栈顶允许操作,栈底不允许操作。 栈的特点是:先进后出,或者说是后进先出,从栈顶放入元素的操作叫入栈,取出元素叫出栈。
栈的结构就像一个集装箱,越先放进去的东西越晚才能拿出来,所以,栈常应用于实现递归功能方面的场景,例如斐波那契数列。
代码实现:
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;}@Overridepublic Iterator<T> iterator() {return new StackIterator();}private class StackIterator implements Iterator<T>{private Node n=head;@Overridepublic boolean hasNext() {return n.next!=null;}@Overridepublic 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); //打印最后元素}}}