一行文章让你搞懂什么是前缀、中缀、后缀表达式以及它们之间的相互转换
一、什么前綴、中綴、后綴表達式(使用 8*(5+6)-1的例子)
1.中綴表達式:8*(5+6)-1;(也就是我們平常所見的運算式)
2.后綴表達式:8 5 6 + * 1 - ;計算機是怎么運算的呢?
從左向右進行遍歷,數字放到數據棧中,也就是8 5 6;當遍歷到+號時,從數據棧中彈出兩個距離+號最近的數據進行相加,也就是5 和 6,得到結果13入棧中;接著遍歷,當遇到 *號時,從棧中彈出距離 *最近的兩個數據進行相乘,也就是13和8,將結果104入棧中;遍歷到1入數據棧,接著遍歷到-號,同樣從數據棧中取出距離-號最近的兩個數據進行相減,也就是104和1,最后的結果103入棧中,遍歷結束
3.前綴表達式:- 1 *+ 6 5 8(類似與后綴表達式,只不過是從右向左進行遍歷)
這三個表達式的結果都是相同的,只不過計算機更傾向于后綴表達式(波蘭表達式)
二、中綴表達式轉前綴表達式
1.思路:
*1.如果使用兩個棧進行操作,發現數據棧沒有出棧的操作,所以可以使用List代替數據棧
* 2.遍歷表達式
* 3.如果是數字,則入加入集合
* 4.如果是運算符,需要考慮以下這幾種情況
* 情況一:運算符棧如果為空,則將運算符直接入棧;
* 情況二:如果棧頂為"(",則直接將運算符入棧
* 情況三:如果該運算符大于棧頂的運算符,則直接將該運算符入棧
* 否則,將棧頂運算符添加到集合中,繼續重復這幾種情況,直到該運算符入棧
* 5.如果遇到“)”,判斷棧頂的符號是否是“(”,如果不是,則將棧頂運算符加入到集合中;如果是,則將這兩個括號丟棄
* 6.遍歷表達式結束,就將剩余棧中的數據加入到集合中
* 7.將list反轉,形成前綴表達式
2.代碼
package com.company;import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Stack;/*** @author:抱著魚睡覺的喵喵* @date:2021/2/20* @description:*/ public class InfixToPrefix {public static void main(String[] args) {String str = "8*((6-4)+1)";List<String> strList = toInfixStrList(str);for (String temp : strList) {System.out.printf(temp);}System.out.println();List<String> list = toInfixTransformPrefix(strList);for (String temp : list) {System.out.printf(temp);}int result = cal(list);System.out.printf("結果為:%d",result);}/*** 將表達式存入list集合中* @param str* @return*/public static List<String> toInfixStrList(String str) {char ch;int i = 0;String cs = "";List<String> list = new ArrayList<>();do {if ((ch = str.charAt(i)) < 48 || (ch = str.charAt(i)) > 57) { //數字的區間[48,56]list.add("" + ch);i++;} else { //這里是為了考慮多位數的情況while (i < str.length() && (ch = str.charAt(i)) >= 48 && (ch = str.charAt(i)) <= 57) {cs += ch; //字符的拼接 "5" + "6" = "56";i++;}list.add(cs);cs = "";}} while (i < str.length());return list;}/*** 中綴轉前綴思路:* 1.如果使用兩個棧進行操作,發現數據棧沒有出棧的操作,所以可以使用List代替數據棧* 2.遍歷表達式* 3.如果是數字,則入加入集合* 4.如果是運算符,需要考慮以下這幾種情況* 情況一:運算符棧如果為空,則將運算符直接入棧;* 情況二:如果棧頂為"(",則直接將運算符入棧* 情況三:如果該運算符大于棧頂的運算符,則直接將該運算符入棧* 否則,將棧頂運算符添加到集合中,繼續重復這幾種情況,直到該運算符入棧* 5.如果遇到“)”,判斷棧頂的符號是否是“(”,如果不是,則將棧頂運算符加入到集合中;如果是,則將這兩個括號丟棄* 6.遍歷表達式結束,就將剩余棧中的數據加入到集合中* 7.將list反轉,形成前綴表達式* @param list* @return*/public static List<String> toInfixTransformPrefix(List<String> list) {Stack<String> opStack = new Stack<>();List<String> numList = new ArrayList<>();String temp = "";for (int i = 0; i < list.size(); i++) { //遍歷temp = list.get(i); //使用臨時遍歷temp記錄每一次遍歷的數據if (temp.matches("\\d+")) { //使用正則表達式(/d+),是否是數字numList.add(temp); //如果是則加入集合中} else if (temp.equals(")")) { //判斷是否是“)”,如果是要循環將棧頂的運算符加入到集合中,直到遇到“(”,并將兩個括號丟棄while (!opStack.peek().equals("(")) {numList.add(opStack.pop());}opStack.pop(); //丟棄括號continue;} else if (Operation.isOperation(temp)) { //如果是運算符,考慮三種情況while (!opStack.isEmpty() && !opStack.peek().equals("(") && (Operation.priority(temp) <= Operation.priority(opStack.peek()))) {numList.add(opStack.pop());}opStack.push(temp); //將運算符入棧}else if (temp.equals("(")) { //如果是左括號直接入棧opStack.push(temp);} else {throw new RuntimeException("你輸入的表達式有誤!");}}while (!opStack.isEmpty()) { //遍歷結束,將棧中剩余數據加入到集合中numList.add(opStack.pop());}Collections.reverse(numList); //list反轉return numList;}public static int cal(List<String> list) {Stack<String> stack = new Stack<>();int num1 = 0;int num2 = 0;int result;String ele="";for (int i = list.size() - 1;i >= 0; i--) {ele = list.get(i);if (ele.matches("\\d+")) { //匹配的是一位數或者多位數(\d+)stack.push(ele);} else {result = 0;num1 = Integer.parseInt(stack.pop());num2 = Integer.parseInt(stack.pop());if (ele.equals("+")) {result = num2 + num1;} else if (ele.equals("-")) {result = num2 - num1;} else if (ele.equals("*")) {result = num2 * num1;} else if (ele.equals("/")) {result = num2 / num1;} else {throw new RuntimeException("運算符有誤!");}stack.push(""+result);}}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 DEL = 2;public static boolean isOperation(String s) {return s.equals("+") || s.equals("-") || s.equals("*") || s.equals("/");}/*** 使用1 2 表示運算符的優先級* @param s* @return*/public static int priority(String s) {switch (s) {case "+":return ADD;case "-":return SUB;case "*":return MUL;case "/":return DEL;default:throw new RuntimeException("符號有誤!");}} }三、中綴表達式轉前綴表達式
1.思路:
* 1.定義兩個棧,數據棧numStack和運算符棧opStack* 2.從左到右遍歷中綴表達式* 3.如果是數字則壓入numStack數據棧中* 4.如果是運算符,則需要考慮三種情況:* 第一種:如果opStack棧為空,或者opStack棧頂運算符為(,則將該運算符壓入該棧中* 第二種:讓該運算符與opStack棧頂運算符進行比較優先級,如果該運算符的優先級大于等于opStack棧頂運算符,則將該運算符壓入該棧中* 第二種:不滿足以上兩種情況,則將opStack棧頂的運算符彈出并壓入numStack棧中,再次考慮這三種情況,直到滿足前兩種情況中的某一個情況為止* 5.如果遇到括號:如果是"(",則直接壓入opStack中;如果是“)”,則依此彈出opStack棧中的運算符,并壓入numStack中,直到遇到左括號為止,并將這兩個括號舍棄* 6.當表達式遍歷完畢,結束* 7,將opStack棧中的運算符依次彈出,并壓入numStack棧中* 8.將數據反轉即可2.代碼
package com.company;import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Stack;/*** @author:抱著魚睡覺的喵喵* @date:2021/2/19* @description:*/ public class InfixToSuffix {public static void main(String[] args) {String str = "4 * ( ( 3 + 8 ) - 6 )";List<String> list = transform(str);System.out.println("中綴表達式轉后綴表達式如下:");for (String temp : list) {System.out.printf("%s ", temp);}System.out.println();int result = cal(list);System.out.printf("結果為:%d",result);}/*** 中綴表達式轉后綴表達式步驟* 1.定義兩個棧,數據棧numStack和運算符棧opStack* 2.從左到右遍歷中綴表達式* 3.如果是數字則壓入numStack數據棧中* 4.如果是運算符,則需要考慮三種情況:* 第一種:如果opStack棧為空,或者opStack棧頂運算符為(,則將該運算符壓入該棧中* 第二種:讓該運算符與opStack棧頂運算符進行比較優先級,如果該運算符的優先級大于等于opStack棧頂運算符,則將該運算符壓入該棧中* 第二種:不滿足以上兩種情況,則將opStack棧頂的運算符彈出并壓入numStack棧中,再次考慮這三種情況,直到滿足前兩種情況中的某一個情況為止* 5.如果遇到括號:如果是"(",則直接壓入opStack中;如果是“)”,則依此彈出opStack棧中的運算符,并壓入numStack中,直到遇到左括號為止,并將這兩個括號舍棄* 6.當表達式遍歷完畢,結束* 7,將opStack棧中的運算符依次彈出,并壓入numStack棧中* 8.將數據反轉即可** @param s* @return 轉為后綴表達式之后的list集合*/public static List<String> transform(String s) {Stack<String> numStack = new Stack<>(); //數據棧Stack<String> opStack = new Stack<>(); //運算符棧String str = "";String[] split = s.split(" "); //以空格將數據分割for (int i = 0; i < split.length; i++) { //遍歷分割后的數據str = split[i];if (isOperator(str)) { //如果是操作符if (str.equals(")")) { //如果是右括號的情況while (!opStack.peek().equals("(")) {numStack.push(opStack.pop());}opStack.pop(); //丟棄右括號continue;}while (true) {if (opStack.isEmpty() || opStack.peek().equals("(")) {opStack.push(str);break;} else if (priority(str) >= priority(opStack.peek())) {opStack.push(str);break;} else {numStack.push(opStack.pop());}}} else if (str.matches("\\d+")) { //如果是數字numStack.push(str);} else {throw new RuntimeException("你定義的表達式有誤!~");}}while (!opStack.isEmpty()) { //遍歷結束,將運算符棧中的運算符加入到數據棧中numStack.push(opStack.pop());}List<String> list = new ArrayList<>(); // 存入list集合中while (!numStack.isEmpty()) {list.add(numStack.pop());}Collections.reverse(list); //反轉listreturn list;}/*** 判斷是否是運算符** @param s* @return*/public static boolean isOperator(String s) {return s.equals("*") || s.equals("/") || s.equals("+") || s.equals("-") || s.equals("(") || s.equals(")");}/*** 使用0 1 2定義優先級** @param s* @return*/public static int priority(String s) {if (s.equals("*") || s.equals("/")) {return 1;} else if (s.equals("+") || s.equals("-")) {return 0;} else if (s.equals("(")) {return 2;} else {throw new RuntimeException("表達式有誤!");}}/*** 計算表達式的結果* @param list* @return result*/public static int cal(List<String> list) {Stack<String> stack = new Stack<>();int num1 = 0;int num2 = 0;int result;for (String ele : list) {if (ele.matches("\\d+")) { //匹配的是一位數或者多位數(\d+)stack.push(ele);} else {result = 0;num1 = Integer.parseInt(stack.pop());num2 = Integer.parseInt(stack.pop());if (ele.equals("+")) {result = num2 + num1;} else if (ele.equals("-")) {result = num2 - num1;} else if (ele.equals("*")) {result = num2 * num1;} else if (ele.equals("/")) {result = num2 / num1;} else {throw new RuntimeException("運算符有誤!");}stack.push(""+result);}}return Integer.parseInt(stack.pop());} }愿你孤獨的努力都有回報,愿你前行的路上有人陪伴~
加油~
總結
以上是生活随笔為你收集整理的一行文章让你搞懂什么是前缀、中缀、后缀表达式以及它们之间的相互转换的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 数组模拟栈
- 下一篇: 迷宫问题让你深度理解递归(回溯)