程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> C# >> C#入門知識 >> 表達式求值,用棧實現表達式求值

表達式求值,用棧實現表達式求值

編輯:C#入門知識

表達式求值,用棧實現表達式求值


前兩天翻看《數據結構》,看到有個表達式求值的東西比較有意思。於是乎就用c#代碼實現了下。倒騰了半天 總算能工作了。 看到博客園的前輩們也寫過好多類似的例子 獻丑了。程序設計語言中都有計算表達式的問題,這是語言編譯中的典型問題。看到博客園的其他帖子好多都是說什麼後綴表達式 什麼的。我這個代碼比較短 但是基礎功能是完全實現了的。

《數據結構》第3章63 頁 是講堆棧。就是stack 這個鳥玩意兒 。以前存數據 都是用list 類似於鏈表 。誰用過這個啊 有什麼用。沒什麼用 就是一種數據結構。表達式求值這當中利用了一個重要特性 那就是堆棧的先進後出。 不論是我們的高級程序語言 還是表達式  ,他們都有一個重要的特性就是 大括號包小括號  括號當中包括號。並且有左括號就會有右括號 是相互對稱的 ,其實要說的話 這個是一種遞歸結構。 不管怎麼說  遇左括號入棧  遇右括號出棧  ,堆棧天生就有一種處理這種問題的能力,並且還讓條理更清晰。

我這段代碼的大概原理就是書上講的那樣:

先給個運算符優先級表

1 char[,] compareTable = new char[7, 7]{
2             {'>','>','<','<','<','>','>'},
3             {'>','>','<','<','<','>','>'},
4             {'>','>','>','>','<','>','>'},
5             {'>','>','>','>','<','>','>'},
6             {'<','<','<','<','<','=','x'},
7             {'>','>','>','>','x','>','>'},
8             {'<','<','<','<','<','x','='}
9             };

橫著豎著7行7列  依次對應+-*/()#   行數為第一個變量 列數為第二個變量 ,比如+與* 為 compare[0,2] 是小於符號 ,+號優先級小於*
然後是規則:
從左往右掃描,遇操作數進operator棧 遇操作符進行下面的邏輯
1若棧頂運算符優先級低於剛讀入的運算符 則讓剛讀入的運算符進入operator棧
2若棧頂運算符的優先級高於剛讀入的運算符則將棧頂運算符退棧 ,同時將操作數棧operand退棧兩次 讓他們進行運算 運算結果推入operator棧
3若優先級相同 說明左右括號相遇 只需將棧頂運算符退棧即可
當棧頂操作符和剛讀入操作符均為#時 說明表達式結束

就這樣如此往復 遇到一個小的計算單位就會自動求值並消除操作數和操作符  然後又讓求出的值和其他值進行運算 如此往復以小到大都求出整個表達式的值。

  1 public char compareOper(char opr1, char opr2)
  2         {
  3             char[,] compareTable = new char[7, 7]{
  4             {'>','>','<','<','<','>','>'},
  5             {'>','>','<','<','<','>','>'},
  6             {'>','>','>','>','<','>','>'},
  7             {'>','>','>','>','<','>','>'},
  8             {'<','<','<','<','<','=','x'},
  9             {'>','>','>','>','x','>','>'},
 10             {'<','<','<','<','<','x','='}
 11             };
 12 
 13             int opr1Indx = 0;
 14             switch (opr1)
 15             {
 16                 case '+':
 17                     opr1Indx = 0;
 18                     break;
 19                 case '-':
 20                     opr1Indx = 1;
 21                     break;
 22                 case '*':
 23                     opr1Indx = 2;
 24                     break;
 25                 case '/':
 26                     opr1Indx = 3;
 27                     break;
 28                 case '(':
 29                     opr1Indx = 4;
 30                     break;
 31                 case ')':
 32                     opr1Indx = 5;
 33                     break;
 34                 case '#':
 35                     opr1Indx = 6;
 36                     break;
 37                 default:
 38                     break;
 39             }
 40             int opr2Indx = 0;
 41             switch (opr2)
 42             {
 43                 case '+':
 44                     opr2Indx = 0;
 45                     break;
 46                 case '-':
 47                     opr2Indx = 1;
 48                     break;
 49                 case '*':
 50                     opr2Indx = 2;
 51                     break;
 52                 case '/':
 53                     opr2Indx = 3;
 54                     break;
 55                 case '(':
 56                     opr2Indx = 4;
 57                     break;
 58                 case ')':
 59                     opr2Indx = 5;
 60                     break;
 61                 case '#':
 62                     opr2Indx = 6;
 63                     break;
 64                 default:
 65                     break;
 66             }
 67 
 68             return compareTable[opr1Indx, opr2Indx];
 69         }
 70         public int calc(int num1, int num2, char opr)
 71         {
 72             switch (opr)
 73             {
 74                 case '+':
 75                     return num1 + num2;
 76                     break;
 77                 case '-':
 78                     return num1 - num2;
 79                     break;
 80                 case '*':
 81                     return num1 * num2;
 82                     break;
 83                 case '/':
 84                     return num1 / num2;
 85                     break;
 86 
 87                 default:
 88                     break;
 89             }
 90             return 0;
 91         }
 92         private void button1_Click(object sender, EventArgs e)
 93         {
 94             Stack<int> operand = new Stack<int>();
 95             Stack<char> opera = new Stack<char>();
 96             opera.Push('#');
 97 
 98             string exp = textBox1.Text;
 99 
100             Regex numVali = new Regex(@"\d");
101 
102             //MessageBox.Show(numVali.IsMatch("6").ToString());
103 
104             for (int i = 0; i < exp.Length; i++)
105             {
106                 if (numVali.IsMatch(exp[i] + "") == true || exp[i] == ' ')//數字
107                 {
108                     string numTmp = exp[i] + "";
109                     int nextNumIndx = 1;
110                     char nextNum = exp[i + (nextNumIndx)];
111                     nextNumIndx++;
112                     while (numVali.IsMatch(nextNum + "") == true || nextNum == ' ')
113                     {
114                         numTmp += nextNum;
115                         if (i + (nextNumIndx) < exp.Length)
116                         {
117                             nextNum = exp[i + (nextNumIndx)];
118                             nextNumIndx++;
119                         }
120                         else
121                             break;
122                     }
123                     operand.Push(int.Parse(numTmp.Replace(" ", "")));
124                     i = i + nextNumIndx - 1 - 1;
125 
126                 }
127                 else//操作符
128                 {
129 
132                     switch (compareOper(opera.Peek(), exp[i]))
133                     {
134                         case '<':
135                             opera.Push(exp[i]);
136                             break;
137                         case '=':
138                             opera.Pop();
139                             break;
140                         case '>':
141 
142                             int b = operand.Pop();
143                             int a = operand.Pop();
144                             operand.Push(calc(a, b, opera.Pop()));
145 
146  
147                             if (compareOper(opera.Peek(), exp[i]) == '=')
148                             {
149                                 opera.Pop();
150                             }
151                             else if (compareOper(opera.Peek(), exp[i]) == '>')
152                             {
153                                  b = operand.Pop();
154                                  a = operand.Pop();
155                                 operand.Push(calc(a, b, opera.Pop()));
156                                 //opera.Push(exp[i]);
157 
158                                 if (compareOper(opera.Peek(), exp[i]) == '=')
159                                 {
160                                     opera.Pop();
161                                 }
162                                 else if (compareOper(opera.Peek(), exp[i]) == '>')
163                                 {
164                                     b = operand.Pop();
165                                     a = operand.Pop();
166                                     operand.Push(calc(a, b, opera.Pop()));
167                                     opera.Push(exp[i]);
168                                 }
169                                 else if (compareOper(opera.Peek(), exp[i]) == '<')
170                                     opera.Push(exp[i]);
171                             }
172                             else if (compareOper(opera.Peek(), exp[i]) == '<')
173                                 opera.Push(exp[i]);
174                             break;
175                         default:
176                             break;
177                     }
178                     if (exp[i] == '#')
179                         break;
180                 }
181             }
182             MessageBox.Show(string.Format("結果是{0}", operand.Peek()));
183         }


就這樣了 ,親測 可用。暫時只能計算整數哈,一個正確的輸入 應該像這樣:(3+2)*4#   。以井號結尾

 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved