選擇棧作為資料結構,所以所有操作都要圍繞棧的特點來進行。因為先入棧而被壓在下面的意味著要後處理,
所以優先順序低的不能壓著優先順序高的而入棧。對於同級的操作符,因為要按照從左往右的運算規則,所以也不
能壓著同級的操作符而入棧。簡單來說,與棧頂的操作符比較,優先順序高的則入棧,否則操作符出棧作相應運
算。
本演算法使用兩個棧,一個用來存放操作符,一個用來存放運算元和運算的結果。
因為比較優先順序是必須做的事,所以這是一個核心問題,需要定一個規則(這個規則在相應的函數中體現)。
本演算法對算術運算式的書寫是很嚴格的,本演算法不對錶達式的合法性作檢查。
算術運算式格式例子如:#23+(5-2)*10/5-3#
我們所做的一切都是為了簡化問題的複雜度,特別是當你不知道怎麼編寫代碼或代碼寫的很亂的時候,你就應
該想方設法進行簡化,而編寫演算法是一個有效簡化方法(至少編寫演算法時會忽略不重要的細節)。
演算法思想:
1。初始化,運算元棧置空;操作符棧壓入'#'。
2。從左往右讀取算術運算式(從第二個字元開始),當讀到'#'且操作符棧棧頂也是'#'時則演算法結束。
3。如果讀到的是運算元則壓入運算元棧中,轉到步驟2。
4。如果讀到是操作符,則比較其與操作符棧棧頂操作符的優先順序。
5。如果棧頂操作符的優先順序高,則棧頂操作符出棧,並從運算元棧中彈出兩個運算元進行相應的運算,再把運
算結果壓入運算元棧中,轉至步驟4。
6。如果棧頂操作符的優先順序低,則把當前操作符壓入操作符棧,轉至步驟2。
7。如果棧頂操作符與當前操作符優先順序相同,則只可能是'('跟')',把操作符從棧中彈出即可,轉至步驟2。
演算法描述:
expression_compute( expresstion )
InitStack( optrStack );
Push( optrStack, '#' );
InitStack( opndStack );
w = Read( expresstion ); // 讀取一個原子字元
while w != '#' or peek(optrStack) != '#'
[
if IsOpnd( w ) // 如果是運算元
[
Push( opndStack, w );
w = Read( expresstion ); // 讀取下一個原子字元
]
else
[
b = Precede( Peek(optrStack), w );
if b == '<'
[
Push( optrStack, w );
w = Read( expresstion );
]
else if b == '='
[
Pop( optrStack ); // 只可能是'('
w = Read( expresstion );
]
else if b == '>'
[
optr = Pop( optrStack );
right = Pop( opndStack );
left = Pop( opndStack );
x = Operate( left, optr, right );
Push( opnd, x );
]
]
]
return Peek(opndStack);
{expression_compute end}
以下是實現代碼,棧("Stack.h")的定義在文章<<c++編程思想>>學習之"初始化與清除"中給出。
#include <iostream>
using namespace std;
#include <cstdlib>
#include <cassert>
#include "Stack.h"
using namespace _bs_stack;
/*
* #5+(7-8*12)/3+1#
*/
typedef Stack OPNDStack; // 運算元棧
typedef Stack OPTRStack; // 操作符棧
void destroy( void * pData )
{
if ( !pData )
return;
delete pData;
pData = 0;
}
OPNDStack opndStack( destroy );
OPTRStack optrStack( destroy );
// 讀取一個原子字元
void read( char *& expression, char ret_buf[] )
{
if ( expression == 0 )
return;
if ( isdigit(*expression) )
{
int nPos = 0;
while ( isdigit(*expression) )
{
ret_buf[ nPos ] = *expression;
nPos ++;
expression ++;
}
ret_buf[ nPos ] = '/0';
}
else
{
ret_buf[ 0 ] = *expression;
expression ++;
ret_buf[ 1 ] = '/0';
}
}
// 判斷是否是運算元
bool isOpnd( char * expression )
{
assert( expression );
if ( !expression )
return false;
return isdigit( *expression ) == 0 ? false : true; // 如果第一字元是數字則整個是數字
}
// 優先順序比較,制定規則
char precede( char leftOptr, char rightOptr )
{
if ( leftOptr == '+' )
{
if ( rightOptr == '+' || rightOptr == '-' || rightOptr == ')' || rightOptr == '#'
)
return '>';
else return '<';
}
if ( leftOptr == '-' )
{
if ( rightOptr == '+' || rightOptr == '-' || rightOptr == ')' || rightOptr == '#'
)
return '>';
else return '<';
}
if ( leftOptr == '*' )
{
if ( rightOptr == '(' )
return '<';
else return '>';
}
if ( leftOptr == '/' )
{
if ( rightOptr == '(' )
return '<';
else return '>';
}
if ( leftOptr == '(' )
{
if ( rightOptr == ')' )
return '=';
else return '<';
}
if ( leftOptr == ')' )
return '>';
if ( leftOptr == '#' )
{
if ( rightOptr == '#' )
return '=';
else return '<';
}
return 'E';
}
// 運算
int operate( int leftOpnd, char optr, int rightOpnd )
{
if ( optr == '+' )
return leftOpnd + rightOpnd;
else if ( optr == '-' )
return leftOpnd - rightOpnd;
else if ( optr == '*' )
return leftOpnd * rightOpnd;
else if ( optr == '/' )
{
if ( rightOpnd == 0 )
return -9999;
return leftOpnd / rightOpnd;
}
else return -999;
}
// 主函數
int expression_compute( char * expression )
{
char * pChar = new char('#');
optrStack.push( pChar );
expression ++; // begin from the second character
const int buf_len = 126;
char buf[ buf_len ] = {0};
read( expression, buf );
while ( strcmp( buf, "#" ) != 0 || *(char*)optrStack.peek() != '#' )
{
if ( isOpnd( buf ) )
{
int nTemp = atoi( buf );
int * pInt = new int( nTemp );
opndStack.push( pInt );
memset( buf, '/0', buf_len );
read( expression, buf );
}
else
{
char ret_char = precede( *(char*)optrStack.peek(), *buf );
if ( ret_char == '<' )
{
char * pChar = new char(*buf);
optrStack.push( pChar );
memset( buf, 0, buf_len );
read( expression, buf );
}
else if ( ret_char == '=' )
{
void * pChar = optrStack.pop( );
delete (char*)pChar;
memset( buf, 0, buf_len );
read( expression, buf );
}
else if ( ret_char == '>' )
{
int * pRightOpnd = (int*)opndStack.pop( );
int * pLeftOpnd = (int*)opndStack.pop( );
char * pOptr = (char*)optrStack.pop( );
int ret = operate( *pLeftOpnd, *pOptr, *pRightOpnd );
int * pRet = new int( ret );
opndStack.push( pRet );
delete pRightOpnd;
delete pLeftOpnd;
delete pOptr;
}
}
}
return *(int*)opndStack.peek( );
}
// 測試函數
int main( )
{
const int buf_len = 126;
char buf[ buf_len ] = {0};
//strcpy( buf, "#1+20*2#" );
cout << "enter expression: ";
cin >> buf;
int ret = expression_compute( buf );
cout << buf << " == " << ret << endl;
return 1;
}