06-数据结构与算法--栈

6 篇文章 0 订阅
5 篇文章 0 订阅

数组实现栈

思路

  1. 使用数组模拟栈
  2. 定义一个top标识为栈顶,初始化为-1
  3. 入栈操作,当有数据加入到栈时,top++ ;stack[top] = data;
  4. 出栈操作,value=stack[top]; top–

代码实现

/**
 * 思路
 * 1、使用数组模拟栈
 * 2、定义一个top标识为栈顶,初始化为-1
 * 3、入栈操作,当有数据加入到栈时,top++ ;stack[top] = data;
 * 4、出栈操作,value=stack[top]; top--
 */
public class ArrayStackDemo {

    public static void main(String[] args) {
        //测试
        ArrayStack arrayStack = new ArrayStack(5);
        String key = "";
        boolean loop = true;
        Scanner scanner = new Scanner(System.in);

        while (loop) {
            System.out.println("show: 表示显示栈");
            System.out.println("exit: 退出程序");
            System.out.println("push: 入栈");
            System.out.println("pop: 出栈");
            System.out.println("请输入你的选择:");
            key = scanner.next();
            switch (key) {
                case "show":
                    arrayStack.list();
                    break;
                case "push":
                    System.out.println("请输入一个值");
                    int value = scanner.nextInt();
                    arrayStack.push(value);
                    break;
                case "pop":
                    try {
                        int pop = arrayStack.pop();
                        System.out.printf("出栈数据:%d",pop);
                        System.out.println();
                    } catch (Exception e) {
//                        e.printStackTrace();
                        System.out.println(e.getMessage());
                    }
                    break;
                case "exit":
                    scanner.close();
                    loop = false;
                    break;
                default:
                    break;
            }
        }
        System.out.println("程序退出。。。");
    }

}

/**
 * 定义一个类,表示栈
 */
class ArrayStack{
    private int maxSize;  //栈大小
    private int[] stack;  //数组模拟栈,数据放入其中
    private int top = -1; //栈顶,初始化为-1

    public ArrayStack(int maxSize){
        this.maxSize = maxSize;
        stack = new int[maxSize];
    }

    //判断栈满
    public boolean isFull() {
        return top == maxSize - 1;
    }

    //判断栈空
    public boolean isEmpty() {
        return top == -1;
    }

    //入栈
    public void push(int value) {
        //判断是否栈满
        if (isFull()) {
            System.out.println("栈满");
            return;
        }
        top++;
        stack[top] = value;
    }

    //出栈,将栈顶数据返回
    public int pop() {
        if (isEmpty()) {
            throw new NullPointerException("栈空,没有数据");
        }
        int value = stack[top];
        top--;
        return value;
    }

    //遍历栈
    public void list() {
        if (isEmpty()) {
            throw  new NullPointerException("栈空");
        }
        for (int i = top; i >= 0; i--) {
            System.out.printf("stack[%d]=%d\n",i,stack[i]);
        }
    }
}

综合计算器实现

表达式

  1. 前缀表达式(波兰表达式)
  2. 中缀表达式(正常数学计算表达式)
  3. 后缀表达式(逆波兰表达式)

计算器实现:使用后缀表达式实现计算器计算。
中缀表达式转后缀表达式(逆波兰表达式)思路:

  1. 初始化两个栈: 运算符栈s1和存储中间结果的栈s2
  2. 从左至右扫描中缀表达式
  3. 遇到操作数(数字)时,将其压入s2
  4. 遇到运算符时,比较s1栈顶运算符的优先级
    4.1、s1栈为空,或栈顶运算符为左括号“(”,则将此运算符入栈;
    4.2、否则,若当前运算符优先级比栈顶优先级符号高,也将运算符压入s1
    4.3、否则,将s1栈顶的运算符弹出并压入到s2中,再次转到(4.1)与s1中新的栈顶运算符比较
  5. 若遇到右括号
    5.1、如果是左括号“(”,则压入s1
    5.2、如果是右括号")",则依次弹出运算符,并压入s2,直到遇到左括号为止,此时将这一对括号丢弃
  6. 重复2至5的步骤,直到表达式的最右边
  7. 将s1中剩余的运算符依次弹出并压入s2
  8. 依次弹出s2中的元素并输出,结果的逆序即为中缀表达式对应的后缀表达式

代码实现:

/**
 * 前缀表达式(波兰表达式)
 * 中缀表达式
 * 后缀表达式(逆波兰表达式)
 *
 * 后缀表达式(逆波兰表达式)实现 计算器
 */

/**
 * 中缀表达式(正常的表达式) 转后拽表达式(逆波兰表达式)
 * 1、初始化两个栈: 运算符栈s1和存储中间结果的栈s2
 * 2、从左至右扫描中缀表达式
 * 3、遇到操作数时,将其压入s2
 * 4、遇到运算符时,比较s1栈顶运算符的优先级
 *  4.1、s1栈为空,或栈顶运算符为左括号“(”,则将此运算符入栈;
 *  4.2、否则,若当前运算符优先级比栈顶优先级符号高,也将运算符压入s1
 *  4.3、否则,将s1栈顶的运算符弹出并压入到s2中,再次转到(4.1)与s1中新的栈顶运算符比较
 * 5、若遇到右括号
 *   5.1、如果是左括号“(”,则压入s1
 *   5.2、如果是右括号")",则依次弹出运算符,并压入s2,直到遇到左括号为止,此时将这一对括号丢弃
 * 6、重复2至5的步骤,直到表达式的最右边
 * 7、将s1中剩余的运算符依次弹出并压入s2
 * 8、依次弹出s2中的元素并输出,结果的逆序即为中缀表达式对应的后缀表达式
 */
public class PolandNotation {

    private static String suffixExpression = "1+((2+3)*4)-5";

    public static void main(String[] args) {
        //先定义一个逆波兰表达式
        //实例: (3+4)*5-6  => 3 4 + 5 * 6 -
        //为了方便,逆波兰表达式的数字和符号用空格隔开
//        String suffixExp = "3 4 + 5 * 6 -";
//        //1、先将"3 4 + 5 * 6 -" 放入ArrayList中
//        //2、将ArrayList 传递给一个方法,配合栈完成计算
//        List<String> expList = getListStr(suffixExp);
//        System.out.println(calculate(expList));

        System.out.println("中缀表达式");
        List<String> list = toInfixExpressionList(suffixExpression);
        System.out.println(list);
        System.out.println("后缀表达式");
        List<String> suffixExpression = parseSuffixExpressionList(list);
        System.out.println(suffixExpression);
        System.out.println("计算结果");
        int calculate = calculate(suffixExpression);
        System.out.println(calculate);

    }

    /**
     * 将得到的中缀表达式的List转化为后缀表达式List
     * 即ArrayList[1,+,(,(,2,3,),*,4,),-,5] => ArrayList[1,2,3,+,4,*,+,5,-]
     */
    public static List<String> parseSuffixExpressionList(List<String> list){
        Stack<String> s1 = new Stack<>(); //符号栈
        List<String> s2 = new ArrayList<>(); //存储中间结果(即后缀表达式)
        //遍历中缀表达式字符集合list
        for (String item : list) {
            //如果是一个数字就入s2
            if (item.matches("\\d+")) { //正则表达式匹配
                s2.add(item);
            }else if (item.equals("(")) { //左括号 直接入符号栈
                s1.push(item);
            }else if (item.equals(")")) { //如果是右括号
                //如果是右括号")",则依次弹出运算符,并压入s2,直到遇到左括号为止,此时将这一对括号丢弃
                while (true) {
                    String str = s1.pop();
                    if (str.equals("(")) { //看到与当前右括号最接近的左括号跳出循环
                        break;
                    }
                    if (str.equals(")") || str.equals("(")) {
                        continue;
                    }
                    s2.add(str);
                }
            }else {
                //当item的优先级小于等于栈顶运算符的优先级,
                //将s1栈顶的运算符弹出并加入到s2中,再次转到(4.1)与s1中新的栈顶运算符比较
                while (s1.size() != 0 && Operation.getValue(s1.peek()) >= Operation.getValue(item)){
                    s2.add(s1.pop());
                }
                //还需要将item入栈s1
                s1.push(item);
            }
        }
        //把s1剩余的运算符加入s2
        while (s1.size() != 0) {
            s2.add(s1.pop());
        }
        return s2; //输出后缀表达式
    }

    /**
     * 中缀表达式转后缀表达式,思路:
     * 1、1+((2+3)*4)-5 => 1 2 3 + 4 * + 5 -
     * 2、因为直接对str操作麻烦,因此现将“1+((2+3)*4)-5” =>中缀表达式转换为List,即ArrayList[1,+,(,(,2,3,),*,4,),-,5]
     */
    //将中缀表达式转为List
    public static List<String> toInfixExpressionList(String str)  {
        List<String> list = new ArrayList<>();
        int i = 0; //一个指针,用于遍历中缀表达式字符串
        String val = ""; //拼接多为数
        char ch;
        while (true) {
            if (i >= str.length()) {
                if (val != ""){
                    list.add(val);
                }
                break;
            }
            //如果ch是一个非数字,直接加入list中,0~9 的Ascall 码 48~57
            if ((ch = str.charAt(i)) < 48 || (ch = str.charAt(i)) > 57) {
                if (val != "") {
                    list.add(val);
                }
                val = "";
                list.add(ch + "");
            }else {
                val += ch;
            }
            i++;
        }
        return list;
    }

    //完成对逆波兰表达式的运算
    public static int calculate(List<String> expList) {
        //创建一个栈
        Stack<String> stack = new Stack<>();
        expList.forEach(item -> {
            //这可使用正则表达式取数据
            if (item.matches("\\d+")) { //匹配多位数
                stack.push(item);
            }else { //运算符
                //pop出两个数,并运算,再入栈
                int num2 = Integer.parseInt(stack.pop());
                int num1 = Integer.parseInt(stack.pop());
                int res = 0;
                if (item.equals("+")) {
                    res = num1 + num2;
                }else if (item.equals("-")) {
                    res = num1 - num2;
                }else if (item.equals("*")) {
                    res = num1 * num2;
                }else if (item.equals("/")) {
                    res = num1 / num2;
                }else {
                    throw new RuntimeException("运算符不支持");
                }
                stack.push(String.valueOf(res));
            }
        });
        return Integer.parseInt(stack.pop());
    }
}

//编写一个类,返回运算符对应的优先级
class Operation{
    private static int ADD = 1;
    private static int SUB = 1;
    private static int MUL = 2;
    private static int DIV = 2;

    //返回对应的优先级数字
    public static int getValue(String operation) {
        int result = 0;
        switch (operation){
            case "+":
                result = ADD;
                break;
            case "-":
                result = SUB;
                break;
            case "*":
                result = MUL;
                break;
            case "/":
                result = DIV;
                break;
            default:
                System.out.println("不存在改运算符:" + operation);
                break;
        }
        return result;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值