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