資料結構—棧的應用
接著上次的棧的應用一,我們接著說說棧在計算機中的一些具體應用。我們知道計算機的最初的本質工作就是做數學運算,那麼計算機是如何讀入字串“9+(3-1)*5+8/2”並計算值的呢?
在此我們就引入了字尾表示式這個新有概念:
字尾表示式更符合計算機運算規則。
那麼字尾表示式又是怎樣的呢?又如何在c語言中將中綴表示式轉換成字尾表示式了?
解決方案:
遍歷中綴表示式中的數字和符號
對於數字:直接輸出
對於符號:
左括號:進棧
符號:與棧頂符號進行優先順序比較
若棧頂符號優先順序低:進棧
若棧頂符號優先順序不低:將棧頂符號彈出並輸出,之後進棧
右括號:將棧頂符號彈出並輸出,直到匹配到做括號
遍歷結束:將棧中的所有符號彈出並輸出
上面給出的解決方案就是中綴表示式轉字尾表示式的具體方法.
下面用幾個例子來對此作以說明:
例項: 5 + 3 => 5 3 +
1+2*3=>123*+
9+(3-1)5 =>931-5
那麼,在C語言中實現的演算法又是怎樣的呢?
當然,演算法是建立在棧完成的基礎上,棧又是基於線性表的。在之前也有貼出過棧與線性表的程式碼,有興趣也可以在我的程式碼片裡面檢視。
下面就是具體的中綴轉字尾的程式碼
#include <stdio.h>
#include "LinkStack.h"
int isNumber(char c)
{
return ('0' <= c) && (c <= '9');
}
int isOperator(char c)
{
return (c == '+') || (c == '-') || (c == '*' ) || (c == '/');
}
int isLeft(char c)
{
return (c == '(');
}
int isRight(char c)
{
return (c == ')');
}
int priority(char c)
{
int ret = 0;
if( (c == '+') || (c == '-') )
{
ret = 1;
}
if( (c == '*') || (c == '/') )
{
ret = 2;
}
return ret;
}
void output(char c)
{
if( c != '\0' )
{
printf("%c", c);
}
}
void transform(const char* exp)
{
LinkStack* stack = LinkStack_Create();
int i = 0;
while( exp[i] != '\0' )
{
if( isNumber(exp[i]) )
{
output(exp[i]);
}
else if( isOperator(exp[i]) )
{
while( priority(exp[i]) <= priority((char)(int)LinkStack_Top(stack)) )
{
output((char)(int)LinkStack_Pop(stack));
}
LinkStack_Push(stack, (void*)(int)exp[i]);
}
else if( isLeft(exp[i]) )
{
LinkStack_Push(stack, (void*)(int)exp[i]);
}
else if( isRight(exp[i]) )
{
char c = '\0';
while( !isLeft((char)(int)LinkStack_Top(stack)) )
{
output((char)(int)LinkStack_Pop(stack));
}
LinkStack_Pop(stack);
}
else
{
printf("Invalid expression!");
break;
}
i++;
}
while( (LinkStack_Size(stack) > 0) && (exp[i] == '\0') )
{
output((char)(int)LinkStack_Pop(stack));
}
LinkStack_Destroy(stack);
}
int main()
{
transform("9+(3-1)*5+8/2");
printf("\n");
return 0;
}
下來我們接著說字尾是如何在計算機中進行計算的?
計算機對字尾表示式的運算時基於棧的,那麼問題來了,在計算機中他是如何基於字尾表示式計算的呢?
圍繞這個問題,我們提出解決方案。
解決方案:
遍歷字尾表示式中的數字和符號
對於數字:進棧
對於符號:
從棧中彈出右運算元
從棧中彈出左運算元
根據符號進行運算
將運算結果壓入棧中
遍歷結束:棧中的唯一數字即為運算結果
到這字尾表示式轉換為計算機中的計算方式我想大家對此都有所瞭解了。
下面來給出大家字尾運算的C語言演算法框架。
具體實現程式碼如下:
#include <stdio.h>
#include "LinkStack.h"
int isNumber(char c)
{
return ('0' <= c) && (c <= '9');
}
int isOperator(char c)
{
return (c == '+') || (c == '-') || (c == '*') || (c == '/');
}
int value(char c)
{
return (c - '0');
}
int express(int left, int right, char op)
{
int ret = 0;
switch(op)
{
case '+':
ret = left + right;
break;
case '-':
ret = left - right;
break;
case '*':
ret = left * right;
break;
case '/':
ret = left / right;
break;
default:
break;
}
return ret;
}
int compute(const char* exp)
{
LinkStack* stack = LinkStack_Create();
int ret = 0;
int i = 0;
while( exp[i] != '\0' )
{
if( isNumber(exp[i]) )
{
LinkStack_Push(stack, (void*)value(exp[i]));
}
else if( isOperator(exp[i]) )
{
int right = (int)LinkStack_Pop(stack);
int left = (int)LinkStack_Pop(stack);
int result = express(left, right, exp[i]);
LinkStack_Push(stack, (void*)result);
}
else
{
printf("Invalid expression!");
break;
}
i++;
}
if( (LinkStack_Size(stack) == 1) && (exp[i] == '\0') )
{
ret = (int)LinkStack_Pop(stack);
}
else
{
printf("Invalid expression!");
}
LinkStack_Destroy(stack);
return ret;
}
int main()
{
printf("9 + (3 - 1) * 5 + 8 / 2 = %d\n", compute("931-5*+82/+"));
return 0;
}
小結:中綴表示式符合人類的閱讀習慣
字尾表示式是計算機喜歡的表示式
通過棧可以方便的將中綴表示式變換為字尾表示式
中綴表示式的計算過程類似程式編譯執行的過程
這篇部落格是就到這了,需要強調的是,這篇是補充昨天的部落格,今天的晚上會更新今天的部落格。