使用棧Stack對整數數值的運算表達式字符串進行運算C#

     這裏若是對於形如字符串「((6+((7+8)-9)*9+8/2)-3)/2」的運算表達式進行運算。接觸過此類的同窗知道這種存在着運算符優先級的表達式,不能直接從左到右進行運算,咱們使用OperandStack操做數棧和OperatorStack操做符棧,對操做符進行比較,肯定優先級後,取出操做數進行運算。算法

    算法思想以下:ide

1.首先肯定操做的符的優先級,*、/大於+、-,(大於*、/,*、/或者+、-一塊兒時,排在前面的運算符優先,)的優先級最小,且)與(相遇時抵消lua

2.從左到右遍歷字符串,每次遍歷一個字符,設置數字臨時存儲變量OperandTempspa

①當遇到操做符時, 若是OperandTemp有數值,把數字壓入到OperandStack中code

②循環OperatorStack,直到OperatorStack沒值爲止,而後比較這個操做符和OperatorStack頂部的運算符進行比較,若是此操做符運算優先級高,將此運算符壓入棧,退出循環;若是此操做符運算優先級低,則將OperatorStack棧頂的運算符取出ope1,從OperandStack中取出頂部的兩個數值a1(先出棧)和a2,注意首先出棧的作第二個操做數,則進行blog

 a2 ope1 a1;求得結果壓人OperandStack中;若是此操做符是)遇到(時,將OperatorStack棧中的(消除字符串

③循環到最後會剩餘2中狀況,即OperatorStack中剩1個運算符,剩餘兩個運算符,且最後一個運算符優先級高,則讀取最後一個數字和OperandStack頂的數字進行操做運算,求得結果,再運算。string

以字符串「((6+((7+8)-9)*9+8/2)-3)/2」爲例,算法的運算過程是,先將((壓入OperatorStack變爲【((】,將6壓入OperandStack【6】,到+,因爲(不參與運算,則將+壓入it

OperatorStack【((+】,下一個字符(的優先級大於OperatorStack頂的+,則將(壓入OperatorStack【((+(】,下一個(壓入OperatorStack【((+((】,7壓入OperandStack【6,7】,下一個+同理壓入io

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
相關文章
相關標籤/搜索