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

C++數據結構學習之棧的應用

編輯:C++入門知識

C++數據結構中,的應用很廣泛,棧的最大的用途是解決回溯問題,這也包含了消解遞歸;而當你用棧解決回溯問題成了習慣的時候,你就很少想到用遞歸了,比如迷宮求解。另外,人的習慣也是先入為主的,比如樹的遍歷,從學的那天開始,就是遞歸算法,雖然書上也教了用棧實現的方法,但應用的時候,你首先想到的還是遞歸;當然了,如果語言本身不支持遞歸(如BASIC),那棧就是唯一的選擇了——好像現在的高級語言都是支持遞歸的。

如下是表達式類的定義和實現,表達式可以是中綴表示也可以是後綴表示,用頭節點數據域裡的type區分,這裡有一點說明的是,由於單鏈表的賦值函數,我原來寫的時候沒有復制頭節點的內容,所以,要是在兩個表達式之間賦值,頭節點裡存的信息就丟了。你可以改寫單鏈表的賦值函數來解決這個隱患,或者你根本不不在兩個表達式之間賦值也行。

  1. #ifndef Expression_H  
  2. #define Expression_H  
  3. #include "List.h"  
  4. #include "Stack.h"  
  5. #define INFIX 0  
  6. #define POSTFIX 1  
  7. #define OPND 4  
  8. #define OPTR 8  
  9.  
  10. template <class Type> class ExpNode  
  11. {  
  12.  public:  
  13. int type;  
  14. union { Type opnd; char optr;};  
  15. ExpNode() : type(INFIX), optr('=') {}  
  16. ExpNode(Type opnd) : type(OPND), opnd(opnd) {}  
  17. ExpNode(char optr) : type(OPTR), optr(optr) {}  
  18. };  
  19.  
  20. template <class Type> class Expression : List >  
  21. {  
  22.  public:  
  23. void Input()  
  24. {  
  25.  MakeEmpty(); Get()->type =INFIX;  
  26.  cout << endl << "輸入表達式,以=結束輸入" << endl;  
  27.  Type opnd; char optr = ' ';  
  28.  while (optr != '=')  
  29.  {  
  30. cin >> opnd;   
  31. if (opnd != 0)  
  32. {  
  33.  ExpNode newopnd(opnd);  
  34.  LastInsert(newopnd);  
  35. }  
  36. cin >> optr;  
  37. ExpNode newoptr(optr);  
  38. LastInsert(newoptr);  
  39.  }  
  40. }  
  41. void Print()  
  42. {  
  43.  First();  
  44.  cout << endl;  
  45.  for (ExpNode *p = Next(); p != NULL; p = Next() )  
  46.  {  
  47. switch (p->type)  
  48. {  
  49.  case OPND:  
  50. cout << p->opnd; break;  
  51.  case OPTR:  
  52. cout << p->optr; break;  
  53.  default: break;  
  54. }  
  55. cout << ' ';  
  56.  }  
  57.  cout << endl;  
  58. }  
  59. Expression & Postfix() //將中綴表達式轉變為後綴表達式  
  60. {  
  61.  First();  
  62.  if (Get()->type == POSTFIX) return *this;  
  63.  Stack<char> s; s.Push('=');  
  64.  Expression temp;  
  65.  ExpNode *p = Next();  
  66.  while (p != NULL)  
  67.  {  
  68. switch (p->type)  
  69. {  
  70.  case OPND:  
  71.  temp.LastInsert(*p); p = Next(); break;  
  72.  case OPTR:  
  73.  while (isp(s.GetTop()) > icp(p->optr) )  
  74.  {  
  75. ExpNode newoptr(s.Pop());  
  76. temp.LastInsert(newoptr);  
  77.  }  
  78.  if (isp(s.GetTop()) == icp(p->optr) )  
  79.  {  
  80. s.Pop(); p =Next(); break;  
  81.  }  
  82.  s.Push(p->optr); p = Next(); break;  
  83.  default: break;  
  84. }  
  85.  }  
  86.  *this = temp;  
  87.  pGetFirst()->data.type = POSTFIX;  
  88.  return *this;  
  89. }  
  90.  
  91. Type Calculate()  
  92. {  
  93.  Expression temp = *this;  
  94.  if (pGetFirst()->data.type != POSTFIX) temp.Postfix();  
  95.  Stack s; Type left, right;  
  96.  for (ExpNode *p = temp.Next(); p != NULL; p = temp.Next())  
  97.  {  
  98. switch (p->type)  
  99. {  
  100.  case OPND:  
  101. s.Push(p->opnd); break;  
  102.  case OPTR:  
  103. right = s.Pop(); left = s.Pop();  
  104. switch (p->optr)  
  105. {  
  106.  case '+': s.Push(left + right); break;  
  107.  case '-': s.Push(left - right); break;  
  108.  case '*': s.Push(left * right); break;  
  109.  case '/': if (right != 0) s.Push(left/right); else return 0; break;  
  110. // case '%': if (right != 0) s.Push(left%right); else return 0; break;  
  111. // case '^': s.Push(Power(left, right)); break;  
  112.  default: break;  
  113. }  
  114. default: break;  
  115.  }  
  116. }  
  117. return s.Pop();  
  118. }  
  119.  
  120. private:  
  121.  int isp(char optr)  
  122.  {  
  123. switch (optr)  
  124. {  
  125.  case '=': return 0;  
  126.  case '(': return 1;  
  127.  case '^': return 7;  
  128.  case '*': return 5;  
  129.  case '/': return 5;  
  130.  case '%': return 5;  
  131.  case '+': return 3;  
  132.  case '-': return 3;  
  133.  case ')': return 8;  
  134.  default: return 0;  
  135. }  
  136.  }  
  137.  
  138.  int icp(char optr)  
  139.  {  
  140. switch (optr)  
  141. {  
  142.  case '=': return 0;  
  143.  case '(': return 8;  
  144.  case '^': return 6;  
  145.  case '*': return 4;  
  146.  case '/': return 4;  
  147.  case '%': return 4;  
  148.  case '+': return 2;  
  149.  case '-': return 2;  
  150.  case ')': return 1;  
  151.  default: return 0;  
  152. }  
  153.  }  
  154. };  
  155.  
  156. #endif 

幾點說明

1、表達式用單鏈表儲存,你可以看到這個鏈表中既有操作數又有操作符,如果你看過我的另一篇文章如何在C++鏈表中鏈入不同類型對象,這裡的方法也是對那篇文章的補充。

2、輸入表達式時,會將原來的內容清空,並且必須按照中綴表示輸入。如果你細看一下中綴表達式,你就會發現,除了括號,表達式的結構是“操作數”、“操作符”、“操作數”、……“操作符(=)”,為了統一這個規律,同時也為了使輸入函數簡單一點,規定括號必須這樣輸入“0(”、“)0”;這樣一來,“0”就不能作為操作數出現在表達式中了。因為我沒有在輸入函數中增加容錯的語句,所以一旦輸錯了,那程序就“死”了。

3、表達式求值的過程是,先變成後綴表示,然後用後綴表示求值。因為原書講解的是這兩個算法,並且用這兩個算法就能完成中綴表達式的求值,所以我就沒寫中綴表達式的直接求值算法。

4、Calculate()注釋掉的兩行,“%”是因為只對整型表達式合法,“^”的Power()函數沒有完成。

5、isp(),icp()的返回值,我來多說兩句。‘=’(表達式開始和結束標志)的棧內棧外優先級都是最低。‘(’棧外最高,棧內次最低。‘)’棧外次最低,不進棧。‘^’棧內次最高,棧外比棧內低。‘×÷%’棧內比‘^’棧外低,棧外比棧內低。‘+-’棧內比‘×’棧外低,棧外比棧內低。這樣,綜合起來,就有9個優先級。

  1. 淺析C++棧使用方法
  2. 數據庫使用C++數據結構
  3. 程序員必看 c++筆試題匯總
  4. c++編程常用工具
  5. C++數據結構學習之棧和隊列

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