算法:逆波兰表达式求值
背景
运算符求值的一种常见做法是:先将中缀表达式转换为后缀表达式(逆波兰表达式),然后再对后缀表达式求值,之所以这么做的原因是后缀表达式的求值非常简单。
代码实现
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.Threading.Tasks; 6 7 namespace DataStuctureStudy.Stacks 8 { 9 public static class Calculator 10 { 11 private static readonly Dictionary<string, int> _operators = new Dictionary<string, int> 12 { 13 { "+", 1 }, 14 { "-", 1 }, 15 { "*", 2 }, 16 { "/", 2 }, 17 { "%", 2 } 18 }; 19 20 public static void Test(string expression) 21 { 22 var postfixTokens = GetPostfixTokens(GetTokens(expression)); 23 Console.WriteLine(expression + " = " + Calculate(postfixTokens)); 24 } 25 26 private static int Calculate(IEnumerable<string> postfixTokens) 27 { 28 var stack = new Stack<int>(); 29 30 foreach (var item in postfixTokens) 31 { 32 if (IsOperator(item)) 33 { 34 switch (item) 35 { 36 case "+": 37 stack.Push(stack.Pop() + stack.Pop()); 38 break; 39 case "-": 40 stack.Push(stack.Pop() - stack.Pop()); 41 break; 42 case "*": 43 stack.Push(stack.Pop() * stack.Pop()); 44 break; 45 case "/": 46 stack.Push(stack.Pop() / stack.Pop()); 47 break; 48 case "%": 49 stack.Push(stack.Pop() % stack.Pop()); 50 break; 51 } 52 } 53 else 54 { 55 stack.Push(int.Parse(item)); 56 } 57 } 58 59 return stack.Pop(); 60 } 61 62 private static IEnumerable<string> GetPostfixTokens(IEnumerable<string> infixTokens) 63 { 64 var postfixTokens = new List<string>(); 65 var stack = new Stack<string>(); 66 67 foreach (var token in infixTokens) 68 { 69 if (IsOperator(token)) 70 { 71 var curOperator = token; 72 73 if (stack.Count == 0) 74 { 75 stack.Push(curOperator); 76 } 77 else 78 { 79 while (stack.Count != 0) 80 { 81 var popOperator = stack.Pop(); 82 if (popOperator == "(") 83 { 84 stack.Push(popOperator); 85 break; 86 } 87 88 if (_operators[curOperator] <= _operators[popOperator]) 89 { 90 postfixTokens.Add(popOperator); 91 } 92 else 93 { 94 stack.Push(popOperator); 95 break; 96 } 97 } 98 99 stack.Push(curOperator); 100 } 101 } 102 else if (token == "(") 103 { 104 stack.Push(token); 105 } 106 else if (token == ")") 107 { 108 var popOperator = stack.Pop(); 109 while (popOperator != "(") 110 { 111 postfixTokens.Add(popOperator); 112 popOperator = stack.Pop(); 113 } 114 } 115 else 116 { 117 postfixTokens.Add(token); 118 } 119 } 120 121 while (stack.Count != 0) 122 { 123 postfixTokens.Add(stack.Pop()); 124 } 125 126 return postfixTokens; 127 } 128 129 private static IEnumerable<string> GetTokens(string expression) 130 { 131 var tokens = new List<string>(); 132 var sb = new StringBuilder(); 133 134 foreach (var item in expression) 135 { 136 if (IsOperator(item.ToString()) || item == '(' || item == ')') 137 { 138 if (sb.Length > 0) 139 { 140 tokens.Add(sb.ToString()); 141 sb.Clear(); 142 } 143 144 tokens.Add(item.ToString()); 145 } 146 else 147 { 148 sb.Append(item); 149 } 150 } 151 152 return tokens; 153 } 154 155 private static bool IsOperator(string token) 156 { 157 return _operators.ContainsKey(token); 158 } 159 } 160 }