資料結構學習(C++)——棧應用(表示式求值) (轉)
棧的應用很廣泛,原書只講解了求值,那我也就只寫這些。其實,棧的最大的用途是解決回溯問題,這也包含了消解遞迴;而當你用棧解決回溯問題成了習慣的時候,你就很少想到用遞迴了,比如迷宮求解。另外,人的習慣也是先入為主的,比如樹的遍歷,從學的那天開始,就是遞迴演算法,雖然書上也教了用棧實現的方法,但應用的時候,你首先想到的還是遞迴;當然了,如果語言本身不支援遞迴(如BASIC),那棧就是唯一的選擇了——好像現在的高階語言都是支援遞迴的。
如下是表示式類的定義和實現,表示式可以是中綴表示也可以是字尾表示,用頭節點資料域裡的type區分,這裡有一點說明的是,由於單連結串列的賦值,我原來寫的時候沒有複製頭節點的內容,所以,要是在兩個表示式之間賦值,頭節點裡存的資訊就丟了。你可以改寫單連結串列的賦值函式來解決這個隱患,或者你根本不不在兩個表示式之間賦值也行。
#ifndef Expression_H:namespace prefix = o ns = "urn:schemas--com::office" />
#define Expression_H
#include "List.h"
#include "Stack.h"
#define INFIX 0
#define POSTFIX 1
#define OPND 4
#define OPTR 8
template
{
public:
int type;
union { Type opnd; char optr;};
ExpNode() : type(INFIX), optr('=') {}
ExpNode(Type opnd) : type(OPND), opnd(opnd) {}
ExpNode(char optr) : type(OPTR), optr(optr) {}
};
template
{
public:
void Input()
{
MakeEmpty(); Get()->type =INFIX;
cout << endl << "輸入表示式,以=結束輸入" << endl;
Type opnd; char optr = ' ';
while (optr != '=')
{
cin >> opnd;
if (opnd != 0)
{
ExpNode
LastInsert(newopnd);
}
cin >> optr;
ExpNode
LastInsert(newoptr);
}
}
void Print()
{
First();
cout << endl;
for (ExpNode
{
switch (p->type)
{
case OPND:
cout << p->opnd; break;
case OPTR:
cout << p->optr; break;
default: break;
}
cout << ' ';
}
cout << endl;
}
Expression & Postfix() //將中綴表示式轉變為字尾表示式
{
First();
if (Get()->type == POSTFIX) return *this;
Stack
Expression temp;
ExpNode
while (p != NULL)
{
switch (p->type)
{
case OPND:
temp.LastInsert(*p); p = Next(); break;
case OPTR:
while (isp(s.GetTop()) > icp(p->optr) )
{
ExpNode
temp.LastInsert(newoptr);
}
if (isp(s.GetTop()) == icp(p->optr) )
{
s.Pop(); p =Next(); break;
}
s.Push(p->optr); p = Next(); break;
default: break;
}
}
*this = temp;
pGetFirst()->data.type = POSTFIX;
return *this;
}
Type Calculate()
{
Expression temp = *this;
if (pGetFirst()->data.type != POSTFIX) temp.Postfix();
Stack
for (ExpNode
{
switch (p->type)
{
case OPND:
s.Push(p->opnd); break;
case OPTR:
right = s.Pop(); left = s.Pop();
switch (p->optr)
{
case '+': s.Push(left + right); break;
case '-': s.Push(left - right); break;
case '*': s.Push(left * right); break;
case '/': if (right != 0) s.Push(left/right); else return 0; break;
// case '%': if (right != 0) s.Push(left%right); else return 0; break;
// case '^': s.Push(Power(left, right)); break;
default: break;
}
default: break;
}
}
return s.Pop();
}
private:
int isp(char optr)
{
switch (optr)
{
case '=': return 0;
case '(': return 1;
case '^': return 7;
case '*': return 5;
case '/': return 5;
case '%': return 5;
case '+': return 3;
case '-': return 3;
case ')': return 8;
default: return 0;
}
}
int icp(char optr)
{
switch (optr)
{
case '=': return 0;
case '(': return 8;
case '^': return 6;
case '*': return 4;
case '/': return 4;
case '%': return 4;
case '+': return 2;
case '-': return 2;
case ')': return 1;
default: return 0;
}
}
};
#endif
幾點說明
l 表示式用單連結串列儲存,你可以看到這個連結串列中既有運算元又有運算子,如果你看過我的《如何在一個連結串列中鏈入不同型別的》,這裡的方法也是對那篇文章的補充。
l 輸入表示式時,會將原來的內容清空,並且必須按照中綴表示輸入。如果你細看一下中綴表示式,你就會發現,除了括號,表示式的結構是“運算元”、“運算子”、“運算元”、……“運算子(=)”,為了統一這個規律,同時也為了使輸入函式簡單一點,規定括號必須這樣輸入“0(”、“)0”;這樣一來,“0”就不能作為運算元出現在表示式中了。因為我沒有在輸入函式中增加容錯的語句,所以一旦輸錯了,那就“死”了。
l 表示式求值的過程是,先變成字尾表示,然後用字尾表示求值。因為原書講解的是這兩個演算法,並且用這兩個演算法就能完成中綴表示式的求值,所以我就沒寫中綴表示式的直接求值演算法。具體演算法說明參見原書,我就不廢話了。
l Calculate()註釋掉的兩行,“%”是因為只對整型表示式合法,“^”的Power()函式沒有完成。
l isp(),icp()的返回值,原書說的不細,我來多說兩句。‘=’(表示式開始和結束標誌)的棧內棧外優先順序都是最低。‘(’棧外最高,棧內次最低。‘)’棧外次最低,不進棧。‘^’棧內次最高,棧外比棧內低。‘×÷%’棧內比‘^’棧外低,棧外比棧內低。‘+-’棧內比‘×’棧外低,棧外比棧內低。這樣,綜合起來,就有9個優先順序,於是就得出了書上的那個表。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10752043/viewspace-997979/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 【資料結構】棧的應用——中綴表示式求值(c++)資料結構C++
- 【資料結構】棧的應用---四則運算表示式求值(中綴表示式與字尾表示式轉換)資料結構
- 4、逆波蘭表示式求值——棧(java資料結構)Java資料結構
- 棧在表示式求值中的應用
- 【資料結構】棧的應用--數制轉換(c++)資料結構C++
- 使用棧實現表示式求值,運用棧計算
- 資料結構學習(C++)——單連結串列應用(一元多項式【1】) (轉)資料結構C++
- 資料結構學習(C++)——單連結串列應用(一元多項式【2】) (轉)資料結構C++
- 資料結構學習(C++)——序言 (轉)資料結構C++
- 資料結構與演算法——棧(五)中綴表示式轉字尾表示式資料結構演算法
- 資料結構學習(C++)——圖(總結) (轉)資料結構C++
- 資料結構學習(C++)——樹(總結) (轉)資料結構C++
- 【資料結構】棧的應用--括號的匹配(c++)資料結構C++
- 【資料結構】棧的應用--行編輯程式(c++)資料結構C++
- 資料結構學習(C++)——佇列應用(事件驅動模擬) (轉)資料結構C++佇列事件
- 資料結構學習(C++)——棧和佇列(定義和實現) (轉)資料結構C++佇列
- 逆波蘭表示式求值——棧與佇列佇列
- 資料結構學習筆記--棧資料結構筆記
- 資料結構學習(C++)——線性鏈式結構總結(代後記)【1】 (轉)資料結構C++
- 資料結構學習(C++)——線性鏈式結構總結(代後記)【2】 (轉)資料結構C++
- 資料結構學習(C++)——遞迴【1】 (轉)資料結構C++遞迴
- 資料結構 中綴表示式轉化資料結構
- 資料結構學習(C++)——迴圈連結串列 (轉)資料結構C++
- 資料結構學習(C++)——雙向連結串列 (轉)資料結構C++
- 資料結構筆記-棧的應用資料結構筆記
- 棧的應用——表示式求和
- 資料結構學習(c++)——二叉樹 (轉)資料結構C++二叉樹
- 資料結構學習(C++)——遞迴【2】(1) (轉)資料結構C++遞迴
- 資料結構學習(C++)——遞迴【2】(2) (轉)資料結構C++遞迴
- 資料結構學習(C++)——遞迴【2】(3) (轉)資料結構C++遞迴
- 資料結構學習(C++)——遞迴【2】(4) (轉)資料結構C++遞迴
- 資料結構學習(C++)——遞迴【3】(1) (轉)資料結構C++遞迴
- 資料結構學習(C++)——遞迴【3】(2) (轉)資料結構C++遞迴
- 前端資料結構(1)之棧及其應用前端資料結構
- 3.2.5 表示式求值
- 資料結構學習(C++)——二叉樹【2】 (轉)資料結構C++二叉樹
- 資料結構學習(C++)續——排序【3】交換排序 (轉)資料結構C++排序
- 資料結構學習(C++)——圖【4】(最短路徑) (轉)資料結構C++