【java快速入门-集合篇】- Stack (栈)

对比Queue 来说 栈(Stack)是一种后进先出(LIFO:Last In First Out)的数据结构。(相当于把前面的通道给封死)。

Stack是这样一种数据结构:只能不断地往Stack中压入(push)元素,最后进去的必须最早弹出(pop)来。

Stack只有入栈和出栈的操作:

  • 把元素压栈:push(E)
  • 把栈顶的元素“弹出”:pop(E)
  • 取栈顶元素但不弹出:peek(E)

为什么Java的集合类没有单独的Stack接口呢?因为有个遗留类名字就叫Stack,出于兼容性考虑,所以没办法创建Stack接口,只能用Deque接口来“模拟”一个Stack了。

当我们把Deque作为Stack使用时,注意只调用push()/pop()/peek()方法,不要调用addFirst()/removeFirst()/peekFirst()方法,这样代码更加清晰。

Stack的作用

Stack在计算机中使用非常广泛,JVM在处理Java方法调用的时候就会通过栈这种数据结构维护方法调用的层次。例如

static void main(String[] args) {
    foo(123);
}

static String foo(x) {
    return "F-" + bar(x + 1);
}

static int bar(int x) {
    return x << 2;
}

JVM会创建方法调用栈,每调用一个方法时,先将参数压栈,然后执行对应的方法;当方法返回时,返回值压栈,调用方法通过出栈操作获得方法返回值。

因为方法调用栈有容量限制,嵌套调用过多会造成栈溢出,即引发StackOverflowError

public class Main {
    public static void main(String[] args) {
        increase(1);
    }

    static int increase(int x) {
        return increase(x) + 1;
    }
}

另一个Stack的用途,对整数进行进制的转换就可以利用栈。

例如,我们要把一个int整数12500转换为十六进制表示的字符串

首先我们准备一个空栈;

然后计算12500÷16=781…4,余数是4,把余数4压栈;

然后计算781÷16=48…13,余数是1313的十六进制用字母D表示,把余数D压栈;

然后计算48÷16=3…0,余数是0,把余数0压栈;

最后计算3÷16=0…3,余数是3,把余数3压栈。

得到

当商是0的时候,计算结束,我们把栈的所有元素依次弹出,组成字符串30D4,这就是十进制整数12500的十六进制表示的字符串。

练习1:请利用Stack把一个给定的整数转换为十六进制:

import java.util.*;

public class Main {
    public static void main(String[] args) {
        String hex = toHex(12500);
        if (hex.equalsIgnoreCase("30D4")) {
            System.out.println("测试通过");
        } else {
            System.out.println("测试失败");
        }
    }

    static String toHex(int n) {
        Deque<String> hex =new LinkedList<>();
        String string = "";
        var connectString = new StringBuilder();
        for (; n>0 ; n/=16) {
            hex.push(Integer.toHexString(n%16));
        }
        for(String s:hex){
            connectString.append(s);
        }
        return connectString.toString();
    }
}

 练习2:请利用Stack把字符串中缀表达式编译为后缀表达式,然后再利用栈执行后缀表达式获得计算结果:

(在编写程序的时候,我们使用的带括号的数学表达式实际上是中缀表达式,即运算符在中间,例如:1 + 2 * (9 - 5)。但是计算机执行表达式的时候,它并不能直接计算中缀表达式,而是通过编译器把中缀表达式转换为后缀表达式,例如:1 2 9 5 - * +。)

package StackDemo;

import java.util.*;

public class testMain {
    public static void main(String[] args) {
        String exp = "1 + 2 * (9 - 5)";
        SuffixExpression se = compile(exp);
        float result = se.execute();
        System.out.println(exp + " = " + result + " " + (result == 1 + 2 * (9 - 5) ? "✓" : "✗"));
    }

    static SuffixExpression compile(String exp) {
        // TODO:
        Deque<Character> deque = new LinkedList<>();
        char[] charExp = exp.toCharArray();
        String out = "";
        for (char ch : charExp) {
            if(ch == ' ')continue;
            if (ch>='0'&&ch<='9'){//1295
                out += ch;
                continue;
            }
            if(ch=='('){
                deque.push(ch);
            }
            if (ch == '+' || ch =='-') {
                while(!deque.isEmpty() && (deque.peek() != '(')) {
                    out += deque.pop();
                }
                deque.push(ch);
                continue;
            }
            if (ch == '*' || ch =='/') {
                while(!deque.isEmpty() && (deque.peek() == '*' || deque.peek() == '/')) {
                    out += deque.pop();
                }
                deque.push(ch);
                continue;
            }
            if (ch == ')') {
                while(!deque.isEmpty() && deque.peek() != '(') {
                    out += deque.pop();
                }
                deque.pop();
                continue;
            }
        }
        while(!deque.isEmpty()) out += deque.pop();
        System.out.println(out);
        return new SuffixExpression(out);
    }
}

class SuffixExpression {
    private String exp;
    public SuffixExpression(String exp) {
        this.exp = exp;
    }
   public float execute() {
        // TODO:
        Deque<Float> cs= new LinkedList<>();
        char[] cexp = exp.toCharArray();
        for (int i = 0; i < cexp.length; i++) {
            char ch = cexp[i];
            if (ch>='0' && ch<='9') {
                cs.push(Float.valueOf(ch - '0'));
                continue;
            } else {
                cs.push(calculate(ch, cs.pop(), cs.pop()));
            }
        }
        System.out.println(exp);
        return  cs.pop();
    }
    public float calculate(char op, Float f1, Float f2) {
        if (op == '+') return f1 + f2;
        else if (op == '-') return f2 -f1;
        else if (op == '*') return f1 * f2;
        else if (op == '/') return f2/f1;
        else return Float.valueOf(-0);
    }
}

 

 

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值