棧的應用–算術運算式求值

來源:互聯網
上載者:User

選擇棧作為資料結構,所以所有操作都要圍繞棧的特點來進行。因為先入棧而被壓在下面的意味著要後處理,

所以優先順序低的不能壓著優先順序高的而入棧。對於同級的操作符,因為要按照從左往右的運算規則,所以也不

能壓著同級的操作符而入棧。簡單來說,與棧頂的操作符比較,優先順序高的則入棧,否則操作符出棧作相應運

算。
本演算法使用兩個棧,一個用來存放操作符,一個用來存放運算元和運算的結果。
因為比較優先順序是必須做的事,所以這是一個核心問題,需要定一個規則(這個規則在相應的函數中體現)。
本演算法對算術運算式的書寫是很嚴格的,本演算法不對錶達式的合法性作檢查。
算術運算式格式例子如:#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;
}

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.