使用栈Stack对整数数值的运算表达式字符串进行运算C#

Posted 代小代

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了使用栈Stack对整数数值的运算表达式字符串进行运算C#相关的知识,希望对你有一定的参考价值。

     这里如果对于形如字符串“((6+((7+8)-9)*9+8/2)-3)/2”的运算表达式进行运算。接触过此类的同学知道这种存在着运算符优先级的表达式,不能直接从左到右进行运算,我们使用OperandStack操作数栈和OperatorStack操作符栈,对操作符进行比较,确定优先级后,取出操作数进行运算。

    算法思想如下:

1.首先确定操作的符的优先级,*、/大于+、-,(大于*、/,*、/或者+、-一起时,排在前面的运算符优先,)的优先级最小,且)与(相遇时抵消

2.从左到右遍历字符串,每次遍历一个字符,设置数字临时存储变量OperandTemp

①当遇到操作符时, 如果OperandTemp有数值,把数字压入到OperandStack中

②循环OperatorStack,直到OperatorStack没值为止,然后比较这个操作符和OperatorStack顶部的运算符进行比较,如果此操作符运算优先级高,将此运算符压入栈,退出循环;如果此操作符运算优先级低,则将OperatorStack栈顶的运算符取出ope1,从OperandStack中取出顶部的两个数值a1(先出栈)和a2,注意首先出栈的做第二个操作数,则进行

 a2 ope1 a1;求得结果压人OperandStack中;如果此操作符是)遇到(时,将OperatorStack栈中的(消除

③循环到最后会剩余2中情况,即OperatorStack中剩1个运算符,剩余两个运算符,且最后一个运算符优先级高,则读取最后一个数字和OperandStack顶的数字进行操作运算,求得结果,再运算。

以字符串“((6+((7+8)-9)*9+8/2)-3)/2”为例,算法的运算过程是,先将((压入OperatorStack变为【((】,将6压入OperandStack【6】,到+,由于(不参与运算,则将+压入

OperatorStack【((+】,下一个字符(的优先级大于OperatorStack顶的+,则将(压入OperatorStack【((+(】,下一个(压入OperatorStack【((+((】,7压入OperandStack【6,7】,下一个+同理压入

OperatorStack【((+((+】,8压入OperandStack【6,7,8】,下一个)优先级小于OperatorStack顶部的+,则取出OperandStack顶部的8和7和OperatorStack顶部的+,运算得15压入OperandStack,继续比较)和OperatorStack顶的(,优先级相同,同时消去(,此时OperatorStack为【((+(】,OperandStack位【6,15】,下一个字符-小于(,入栈【((+(—】,9入栈OperandStack为【6,15,9】;下一个),取出-和15,9进行运算得6,入栈OperandStack【6,6】;)消去栈顶(OperatorStack为【((+】;下一个*同理,OperandStack【6,6】,OperatorStack为【((+*】;下一个9入栈OperandStack【6,6,9】;下一个+,优先级小于*,则6*9=54入栈,OperandStack【6,54】,OperatorStack为【((+】;下一个+,优先级小,则取出栈顶+6+54=60入栈OperandStack【60】,压入此运算符+OperatorStack为【((+】;下一个8入栈OperandStack【60,8】;下一个/,优先级大入栈,2入栈,则OperatorStack为【((+/】,OperandStack【60,8,2】;下一个)优先级小,则

OperatorStack为【((+】,OperandStack【60,4】=》OperatorStack为【(】,OperandStack【64】;下一个-入栈,3入栈OperatorStack为【(-】,OperandStack【64,3】;下一个),则64-3=61入栈,OperatorStack为【空】,OperandStack【61】;下一个/入栈,2入栈,OperatorStack为【/】,OperandStack【61,2】;此为剩下一操作符的情况,最后运算得到结果:61/2=30.5

 

实现代码如下:

  1 static char[] Operators = new char[] { \'+\', \'-\', \'*\', \'/\', \'(\', \')\' };
  2         static void Main(string[] args)
  3         {
  4            float a = EvaluateExpression("10+(80*3+(6+7))*2");
  5            Console.WriteLine(a);
  6            Console.ReadKey();
  7 
  8         }
  9         /// <summary>
 10         /// 初始化运算符优先级
 11         /// </summary>
 12         /// <param name="a"></param>
 13         /// <param name="b"></param>
 14         /// <returns></returns>
 15         static char InitPriorities(char a, char b)
 16         {
 17             int aIndex = -1;
 18             int bIndex = -1;
 19             for (int i = 0; i < Operators.Length; i++)
 20             {
 21                 if (Operators[i] == a)
 22                     aIndex = i;
 23                 if (Operators[i] == b)
 24                     bIndex = i;
 25 
 26             }
 27             char[,] Priorities = new char[6, 6] {{\'>\',\'>\',\'<\',\'<\',\'<\',\'>\'},
 28                                                  {\'>\',\'>\',\'<\',\'<\',\'<\',\'>\'},
 29                                                  {\'>\',\'>\',\'>\',\'>\',\'<\',\'>\'},
 30                                                  {\'>\',\'>\',\'>\',\'>\',\'<\',\'>\'},
 31                                                  {\'<\',\'<\',\'<\',\'<\',\'<\',\'=\'},
 32                                                  {\'?\',\'?\',\'?\',\'?\',\'?\',\'?\'}};
 33             return Priorities[aIndex, bIndex];
 34         }
 35         static float Calculate(float Operand1, float Operand2, char Operator)
 36         {
 37             float Ret = 0;
 38             if (Operator == \'+\')
 39             {
 40                 Ret = Operand1 + Operand2;
 41             }
 42             else if (Operator == \'-\')
 43             {
 44                 Ret = Operand1 - Operand2;
 45             }
 46             else if (Operator == \'*\')
 47             {
 48                 Ret = Operand1 * Operand2;
 49             }
 50             else if (Operator == \'/\')
 51             {
 52                 Ret = Operand1 / Operand2;
 53             }
 54 
 55             return Ret;
 56         }
 57         static float EvaluateExpression(string str)
 58         {
 59             Stack<float> OperandStack = new Stack<float>(); // 操作数栈, 
 60             Stack<char> OperatorStack = new Stack<char>(); // 操作符栈  
 61             float OperandTemp = 0;
 62 
 63             char LastOperator = \'0\';  // 记录最后遇到的操作符  
 64 
 65             for (int i = 0, size = str.Length; i < size; ++i)
 66             {
 67                 char ch = str[i];
 68 
 69                 if (\'0\' <= ch && ch <= \'9\')
 70                 {   // 读取一个操作数  
 71                     OperandTemp = OperandTemp * 10 + ch - \'0\';
 72                 }
 73                 else if (ch == \'+\' || ch == \'-\' || ch == \'*\' || ch == \'/\' ||
 74                     ch == \'(\' || ch == \')\')
 75                 {
 76                     // 有2种情况 是没有操作数需要入栈保存的。  
 77                     // 1 当前操作符是 “(”。(的左边的操作符已经负责操作数入栈了。  
 78                     // 2 上一次遇到的操作符是“)”。)本身会负责操作数入栈,)后面紧跟的操作符不需要再负责操作数入栈。  
 79                     if (ch != \'(\' && LastOperator != \')\')
 80                     {
 81                         // 遇到一个操作符后,意味着之前读取的操作数已经结束。保存操作数。  
 82                         OperandStack.Push(OperandTemp);
 83                         // 清空,为读取下一个操作符做准备。  
 84                         OperandTemp = 0;
 85                     }
 86 
 87                     // 当前遇到的操作符作为操作符2,将和之前遇到的操作符(作为操作符1)进行优先级比较  
 88                     char Opt2 = ch;
 89 
 90                     for (; OperatorStack.Count > 0; )
 91                     {
 92                         // 比较当前遇到的操作符和上一次遇到的操作符(顶部的操作符)的优先级  
 93                         char Opt1 = OperatorStack.Peek();
 94                         char CompareRet = InitPriorities(Opt1, Opt2);
 95                         if (CompareRet == \'>\')
 96                         {   // 如果操作符1 大于 操作符2 那么,操作符1应该先计算  
 97 
 98                             // 取出之前保存的操作数2  
 99                             float Operand2 = OperandStack.Pop();
100 
101                             // 取出之前保存的操作数1  
102                             float Operand1 = OperandStack.Pop();
103 
104                             // 取出之前保存的操作符。当前计算这个操作符,计算完成后,消除该操作符,就没必要保存了。  
105                             OperatorStack.Pop();
106 
107                             // 二元操作符计算。并把计算结果保存。  
108                             float Ret = Calculate(Operand1, Operand2, Opt1);
109                             OperandStack.Push(Ret);
110                         }
111                         else if (CompareRet == \'<\')
112                         {   // 如果操作符1 小于 操作符2,说明 操作符1 和 操作符2 当前都不能进行计算,  
113                             // 退出循环,记录操作符。  
114                             break;
115                         }
116                         else if (CompareRet == \'=\')
117                         {
118                             // 操作符相等的情况,只有操作符2是“)”,操作数1是“(”的情况,  
119                             // 弹出原先保存的操作符“(”,意味着“(”,“)”已经互相消掉,括号内容已经计算完毕  
120                             OperatorStack.Pop();
121                             break;
122                         }
123 
124                     } // end for  
125 
126                     // 保存当前遇到操作符,当前操作符还缺少右操作数,要读完右操作数才能计算。  
127                     if (Opt2 != \')\')
128                     {
129                         OperatorStack.Push(Opt2);
130                     }
131 
132                     LastOperator = Opt2;
133                 }
134 
135             } // end for  
136 
137 
138             /* 
139             上面的 for 会一面遍历表达式一面计算,如果可以计算的话。 
140             当遍历完成后,并不代表整个表达式计算完成了。而会有2种情况: 
141             1.剩余1个运算符。 
142             2.剩余2个运算符,且运算符1 小于 运算符2。这种情况,在上面的遍历过程中是不能进行计算的,所以才会被遗留下来。 
143             到这里,已经不需要进行优先级比较了。情况1和情况2,都是循环取出最后读入的操作符进行运算。 
144             */
145             if (LastOperator != \')\')
146             {
147                 OperandStack.Push(OperandTemp);
148             }
149             for (; OperatorStack.Count > 0; )
150             {
151                 // 取出之前保存的操作数2  
152                 float Operand2 = OperandStack.Pop();
153 
154                 // 取出之前保存的操作数1  
155                 float Operand1 = OperandStack.Pop();
156 
157                 // 取出末端一个操作符  
158                 char Opt = OperatorStack.Pop();
159 
160                 // 二元操作符计算。  
161                 float Ret = Calculate(Operand1, Operand2, Opt);
162                 OperandStack.Push(Ret);
163             }
164 
165             return OperandStack.Peek();
166         }
View Code

 

以上是关于使用栈Stack对整数数值的运算表达式字符串进行运算C#的主要内容,如果未能解决你的问题,请参考以下文章

栈实现表达式求值

Stack实现表达式的求值

表达式求值

四则运算林正扬

怎样用C语言写出对栈进行的五种运算:push()、pop()、top()、empty()、makempty()

leetcode-简单-栈-逆波兰表达式