棧(2)--棧的應用

fan_rockrock發表於2014-02-11

一:數制轉換

void Conversion ( )  {
// 對於輸入的任意一個非負十進位制整數,輸出等值的八進位制數
   InitStack(&S); // 構造空棧
   scanf ("%d",N);
   while (N) {
        Push(&S, N % 8);
        N = N/8;  }
   while (!StackEmpty(S)) {
       Pop(&S,&e);
       printf ( "%d", e );  }
 } // conversion

二.括號匹配

演算法思想:

1.凡是有左括號的就入棧;

2.凡是有右括號的,檢查棧是否為空

   (1)是:右括號是多餘的

   (2)否:出棧頂元素與之比較,若為左括號,則匹配成功

3.當檢查完畢時:

  (1)若棧空,則匹配成功;

  (2)棧不空,則有多餘的左括號

status matching(string &exp) 
{
// 檢驗表示式中所含括弧是否正確巢狀,
  int state = 1;
  while ( i <= length(exp) && state)  
  {
     swith of exp[i]  {
       case “(”: { Push(&S,exp[i]); i++; break; }
       case “)”: { if ( !StackEmpty(S) && GetTop(S) = = ‘(‘  ) 
                             {Pop(&S,&e);  i++;} 
                     else state = 0 ;   break; }
       ...... 
       } // swith
   } // while
  if ( state && StackEmpty(S) ) return OK
  else return ERROR;            
}
三.行編輯程式

我們假設使用者輸入文字時,用#表示退格,用@表示退行,

舉例:   whli##ilr#e(s#*s)
            outcha@putchar(*s=#++);

實際有效的是:
        while (*s)
        putchar(*s++);
演算法思想:

1.當使用者輸入字元非@,非#,非換行時就入棧;

2.輸入#時出棧頂元素;

3.輸入@時清空棧;

void LineEdit( ) 
{
    InitStack(s);  
    ch = getchar();
    while (ch != EOF) 
    {
        switch (ch) 
        {
            case '#' : Pop(S, c); break;
            case '@': ClearStack(S); break;// 重置S為空棧        

            case '\n': ClearStack(S); break;// 重置S為空棧

            default : Push(S, ch); break; 
        } 
       ch = getchar(); // 從終端接收下一個字元 } DestroyStack(S); }    

四.迷宮求解

演算法思路:

do

{
     if(當前位置可通)
   {

           將當前位置插入棧頂;
           if(該位置是出口位置)

                 演算法結束;            
           else{

                     切換當前位置的東鄰方塊為
                     新的當前位置;

                  }      

      }
   else

  {

      if(棧不空且棧頂位置尚有其他方向未被探索)
         {

            設定新的當前位置為: 沿順時針方向旋轉
            找到的棧頂位置的下一相鄰塊;

          }

       if(棧不空但棧頂位置的四周均不可通)
        {

             刪去棧頂位置; // 從路徑中刪去該通道塊
            若棧不空,則重新測試新的棧頂位置,
           直至找到一個有可通相鄰塊的位置
           或出棧至棧空;

         }
 }
}while (棧不空);若棧空,則表明迷宮沒有通路。


五.表示式求值

1.表示式的三種標識方法:

      例如:    Exp = a *b + (c -d / e) *f

      字首式:           + * a b *- c / d e f
      中綴式:           a* b + c - d / e * f
      字尾式:           a b * c d e / - f * +

      *結論:1)運算元之間的相對次序不變
                 2)運算子的相對次序不同
                 3)中綴式丟失了括弧資訊,致使運算的次序不確定;
                 4)字首式的運算規則為:連續出現的兩個運算元和在它們之前且緊靠它們的運算子構成一個最小表示式;
                 5)字尾式的運算規則為:運算子在式中出現的順序恰為 表示式的運算順序;每個運算子和在它之前出現且緊靠它的兩個運算元構成一個最小表示式

2.由字尾式求值

   (1)方法:先找運算子,再找運算元,運算規則為上面1(5)所示

  

演算法思想:

1)初始化運算元棧,若遇到運算元,則運算元入棧;

2)若遇到操作符,則出棧兩個運算元,運算之後再把結果入棧,直至字尾表示式依次掃描完

void value(char suffix[ ],int &e)//suffix為字尾式,以"#"結尾
{ char *pch;
   InitStack(S); pch=suffix; //pch指向suffix字尾式的第一個
   while(*pch!=‘#’)
   {
       if(!IN(ch, OP)) 
          push(S,ch);
       else 
         {
          pop(S,a);pop(S,b);push(S,operate(a,ch,b));
         }
        pch++;
   }
    pop(S,e);
}
3.由原表示式求字尾式:

           原表示式:  a + b *c - d / e *f
           字尾式:  a b c * + d e / f * -
          *  結論: 中綴式中每個運算子的運算次序要由它之後的一個運算子來定;

                        字尾式中,優先數高的運算子領先於優先數低的運算子

演算法思想:

        1).建立運算子棧並初始化使其棧底為"#",也使表示式最後一個字元為"#";

        2).掃描原表示式,若遇到運算元,則把它加到字尾式;

        3).若遇到運算子,則與棧頂的元素比較,若優先順序大於棧頂元素,則入棧;

                                                                               若優先順序小於等於棧頂元素,則出棧頂元素並加入到字尾式;

       4).若遇到左括號,則進棧;遇到右括號,則棧中元素依次出棧並加入到字尾式中,直至遇到左括號(左括號也出棧但不加到字尾式中)

     

void transform(char suffix[ ], char exp[ ] ) {
  InitStack(S);  Push(S, '#');//給棧底賦值'#'
  p = exp;  ch = *p;
  while (!StackEmpty(S)) {
      if (!IN(ch, OP)) Pass( Suffix, ch); //如果ch不是操作符,則加到字尾
      else 
          {     
             switch (ch) 
              {
                case '(' :  Push(S, ch); break;
                case ')' :  Pop(S, c);
                            while (c!= '(' )
                              { Pass( Suffix, c);  Pop(S, c) }; break; //如果ch是右括號,則依次出棧並加到字尾,直至遇到左括號
                defult  : //遇到操作符
                while(Gettop(S, c)&&precede(c)>=precede(ch))//若優先順序小於等於棧頂元素,則出棧頂元素並加入到字尾式;
                { Pass( Suffix, c);  Pop(S, c); }
                if  ( ch!= '#' )  Push( S, ch); //若優先順序大於棧頂元素,則入棧;
                 break;  
              } // switch  
          }
      if ( ch!= '#' ) { p++;  ch = *p; }//掃描表示式的下一個字元
      else { Pop(S, ch);  Pass(Suffix, ch); }//若表示式取得的字元為'#',則符號棧依次出棧
  } // while
} // transform
4.直接從原表示式求值

     舉例算exp=a*b+(c-d/e)*f(用以下演算法思想模擬整個流程,並嘗試把整個程式碼編寫出來)

演算法思想:

1).建立兩個棧,一個操作符棧operator(OPTR),一個運算元棧operand(OPND),初始化operator棧底為'#'(表示式的最後也加上'#');

2).掃描表示式exp,

    若為運算元,則進棧operand;

    否則為操作符ch:

                         *若ch的優先順序大於棧頂元素,則入棧;

                         *若ch的優先順序小於等於棧頂元素,則彈出棧頂元素,並從operand棧中彈出兩個元素,生成運算指令,把結果入棧到operand,繼續處理剛掃描到的ch的操作;

                         @若ch='('左括號,則入棧;

                         @若ch=')'右括號,則看棧頂元素,

                                       若棧頂為'(',則出棧頂元素,繼續掃描下個exp字元;

                                       否則出棧一個符號,並從operator中彈出兩個運算元生成運算指令,把結果入棧到operand,繼續處理當前讀入符號;

   若當前讀入的ch='#',並且operator棧中也只有'#',則從operand中彈出最後的運算結果,整個流程結束.

OperandType  EvaluateExpression() 
{
  InitStack(OPTR); Push(OPTR,'#'); 
  InitStack(OPND);   c=getchar();
  while(c!=‘#’||GetTop(OPTR)!=‘#’)
  {
    if(!In(c,OP)) {Push((OPND,c); c=getchar();}//運算元
    else
      switch(Precede(GetTop(OPTR),c){
         case ‘<‘: //棧頂元素優先權低
               Push(OPTR,c); c=getchar(); break;
         case ‘=‘: //脫括號並接收下一字元(只有左括號和右括號優先順序相等)
               Pop(OPTR,x); c=getchar(); break;
         case ‘>‘: //退棧並將運算結果入棧
               Pop(OPTR, theta); Pop(OPND, b); Pop(OPND, a); 
               Push(OPND, Operate(a, theta, b)); break;
      }//switch
  }//while
  c=Gettop(OPND); //若當前讀入的ch='#',並且operator棧中也只有'#',則從operand中彈出最後的運算結果,整個流程結束.
  DestroyStack(OPTR); 
  DestroyStack(OPND); 
  return c;
 }

運算子優先順序表如下:θ1在前,θ2在後

    


相關文章