8.棧和隊列的應用

一、棧的應用

1.1 括號匹配問題

圖片

怎樣判斷是不是匹配序列呢?

算法思想:
1)初始一個空棧,順序讀入括號。
2)若是右括號,則與棧頂元素進行匹配
●若匹配,則彈出棧頂元素並進行下一個元素
●若不匹配,則該序列不合法
3)若是左括號,則壓入棧中
4)若全部元素遍歷完畢,棧中非空則序列不合法

代碼如下:

#include <malloc.h>
#include <stdio.h>
#include <stdlib.h>
#define MaxSize 50
#define ElemType char
typedef struct
{
    ElemType data[MaxSize];
    int top;
}SqStack;
void InitStack(SqStack *&s){
    s = (SqStack*)malloc(sizeof(SqStack));
    s->top=-1;
}
bool IsEmpty(SqStack *&s){
    return s->top == -1;
}
bool Push(SqStack *&s, ElemType e){
    //判斷棧有沒有滿
    if(s->top == MaxSize)
        return false;
    s->data[++s->top] = e;
    return true;
}
bool Pop(SqStack *&s, ElemType &e){
    //如果棧爲空,則返回false
    if(s->top == -1)
        return false;
    e = s->data[s->top--];
    return true;
}
bool GetTop(SqStack *&s, ElemType &e){
    if(s->top==-1)
        return false;
    e = s->data[s->top];
    return true;
}
void DestroyStack(SqStack *&s){
    free(s);
}

//括號匹配問題
bool Match(char exp[],int n)
{
    int i=0; char e;
    bool match=true;
    SqStack *st;
    InitStack(st);                      //初始化棧
    while (i<n && match)                //掃描exp中所有字符
    {
        if (exp[i]=='(')                //當前字符爲左括號,將其進棧
            Push(st,exp[i]);
        else if (exp[i]==')')           //當前字符爲右括號
        {
            if (GetTop(st,e)==true)
            {   
                if (e!='(')             //棧頂元素不爲'('時表示不匹配
                    match=false;
                else
                    Pop(st,e);          //將棧頂元素出棧
            }
            else  match=false;          //無法取棧頂元素時表示不匹配
        }
        i++;                            //繼續處理其他字符
    }
    if (!IsEmpty(st))               //棧不空時表示不匹配
        match=false;
    DestroyStack(st);                   //銷燬棧
    return match;
}

2.2 表達式求值問題

((2+3)*4)-(5-3)

  1. 先要中綴轉後綴:
  2. 計算後綴

中綴轉後綴算法思想:
數字直接加入後綴表達式運算符時:
a.若爲’(’,入棧;
b.若爲")",則依次把棧中的運算符加入後綴表達式,直到出現’(’, 並從棧中刪除’(’;
C.若爲’+’, ‘’, ‘*’, ‘/’,
  ●棧空,入棧;
  ●棧頂元素爲’(’,入棧;
  ●高於棧頂元素優先級,入棧;
  ●否則,依次彈出棧頂運算符,直到-一個優先級比它低的運算符或(爲止; 
d.遍歷完成,若棧非空依次彈出所有元素。

void trans(char *exp,char postexp[])    //將算術表達式exp轉換成後綴表達式postexp
{
    char e;
    SqStack *Optr;                      //定義運算符棧
    InitStack(Optr);                    //初始化運算符棧
    int i=0;                            //i作爲postexp的下標
    while (*exp!='\0')                  //exp表達式未掃描完時循環
    {   switch(*exp)
        {
        case '(':                       //判定爲左括號
            Push(Optr,'(');             //左括號進棧
            exp++;                      //繼續掃描其他字符
            break;
        case ')':                       //判定爲右括號
            Pop(Optr,e);                //出棧元素e
            while (e!='(')              //不爲'('時循環
            {
                postexp[i++]=e;         //將e存放到postexp中
                Pop(Optr,e);            //繼續出棧元素e
            }
            exp++;                      //繼續掃描其他字符
            break;
        case '+':                       //判定爲加或減號
        case '-':
            while (!IsEmpty(Optr))   //棧不空循環
            {
                GetTop(Optr,e);         //取棧頂元素e
                if (e!='(')             //e不是'('
                {
                    postexp[i++]=e;     //將e存放到postexp中
                    Pop(Optr,e);        //出棧元素e
                }
                else                    //e是'(時退出循環
                    break;
            }
            Push(Optr,*exp);            //將'+'或'-'進棧
            exp++;                      //繼續掃描其他字符
            break;
        case '*':                       //判定爲'*'或'/'號
        case '/':
            while (!IsEmpty(Optr))   //棧不空循環
            {
                GetTop(Optr,e);         //取棧頂元素e
                if (e=='*' || e=='/')   //將棧頂'*'或'/'運算符出棧並存放到postexp中
                {
                    postexp[i++]=e;     //將e存放到postexp中
                    Pop(Optr,e);        //出棧元素e
                }
                else                    //e爲非'*'或'/'運算符時退出循環
                    break;
            }
            Push(Optr,*exp);            //將'*'或'/'進棧
            exp++;                      //繼續掃描其他字符
            break;
        default:                //處理數字字符
            while (*exp>='0' && *exp<='9') //判定爲數字
            {   postexp[i++]=*exp;
                exp++;
            }
            postexp[i++]='#';   //用#標識一個數值串結束
        }
    }
    while (!IsEmpty(Optr))   //此時exp掃描完畢,棧不空時循環
    {
        Pop(Optr,e);            //出棧元素e
        postexp[i++]=e;         //將e存放到postexp中
    }
    postexp[i]='\0';            //給postexp表達式添加結束標識
    DestroyStack(Optr);         //銷燬棧       
}

計算後綴算法思想

double compvalue(char *postexp) //計算後綴表達式的值
{
    double d,a,b,c,e;
    SqStack *Opnd;             //定義操作數棧
    InitStack(Opnd);           //初始化操作數棧
    while (*postexp!='\0')      //postexp字符串未掃描完時循環
    {   
        switch (*postexp)
        {
        case '+':               //判定爲'+'號
            Pop(Opnd,a);       //出棧元素a
            Pop(Opnd,b);       //出棧元素b
            c=b+a;              //計算c
            Push(Opnd,c);      //將計算結果c進棧
            break;
        case '-':               //判定爲'-'號
            Pop(Opnd,a);       //出棧元素a
            Pop(Opnd,b);       //出棧元素b
            c=b-a;              //計算c
            Push(Opnd,c);      //將計算結果c進棧
            break;
        case '*':               //判定爲'*'號
            Pop1(Opnd,a);       //出棧元素a
            Pop(Opnd,b);       //出棧元素b
            c=b*a;              //計算c
            Push(Opnd,c);      //將計算結果c進棧
            break;
        case '/':               //判定爲'/'號
            Pop(Opnd,a);       //出棧元素a
            Pop(Opnd,b);       //出棧元素b
            if (a!=0)
            {
                c=b/a;          //計算c
                Push(Opnd,c);  //將計算結果c進棧
                break;
            }
            else
            {   
                printf("\n\t除零錯誤!\n");
                exit(0);        //異常退出
            }
            break;
        default:                //處理數字字符
            d=0;                //將連續的數字字符轉換成對應的數值存放到d中
            while (*postexp>='0' && *postexp<='9')   //判定爲數字字符
            {   
                d=10*d+*postexp-'0';  
                postexp++;
            }
            Push(Opnd,d);      //將數值d進棧
            break;
        }
        postexp++;              //繼續處理其他字符
    }
    GetTop(Opnd,e);            //取棧頂元素e
    DestroyStack(Opnd);        //銷燬棧       
    return e;                   //返回e
}

2.3 遞歸

我們可以用棧來實現遞歸過程

斐波拉契數列:0,1,1,2,3,5,…

//遞歸做法
int Fib(int n) {
  if(n == 0)
    return 0;
  else if(n == 1)
    return 1 ;
  else
    return Fib(n-1) + Fib(n-2) ;
}

使用棧:

int Fib(int n){
    int ans;
  if(n == 0)
    return 0;
  else if(n == 1)
    return 1;
  else{
   SqStack *s;
   InitStack(s);
   Push(s,0);
   Push(s,1);
     while(n-- > 1){
       int a,b;
       Pop(s,a);
       Pop(s,b);
       Push(s,a);
       Push(s,a+b);
     }
     GetTop(s,ans);
   }
   return ans;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章