1. 程式人生 > >棧的應用:表示式括號匹配檢測(C)

棧的應用:表示式括號匹配檢測(C)

問題說明:

假設數學表示式中允許包含兩種括號:圓括號“()”和方括號“[]”,巢狀順序任意。

正確的巢狀模式:( [ ] ( ) )、[ ( [ ] [ ] ) ]

正確的表示式例:(a+b)[c*(d-e)]

錯誤的巢狀模式:[ ( ] )、( ( ) ]

 

比如,在處理表達式(A)時

(A)  4+(2+8)*[5/(9-7)]

有以下步驟:

(1)檢測到第一個括號“(”;

(2)檢測到第二個括號“)”,說明子表示式 “4+(2+8)” 已完成匹配;

(3)檢測到第三個括號“[”;

(4)檢測到第四個括號“(”,與(3)中的括號不匹配,但由於同是左括號,可以繼續匹配;

(5)檢測到第五個括號“)”,由括號的作用可知,後來的括號比先來的括號優先順序高,因此與(4)中括號匹配;

(6)檢測到第六個括號“]”,由於原來優先順序更高的括號已完成,因此與(3)中括號匹配。至此所有括號匹配完成。

 

解決方案:

可以看出,匹配成功的條件很簡單:每一個檢測到的括號與已檢測到的優先順序最高的括號都匹配。

匹配失敗的條件:

(1)檢測到與已檢測到的優先順序最高的括號不匹配的括號;

(2)掃描完整個表示式,還是有已檢測到的括號沒有完成匹配;

 

由於棧具有“先進後出”的特點,能很好地表現優先順序這個性質,因此可以用棧來儲存已經檢測到的括號。

以(A)為例:

有以下步驟:

(1)檢測到第一個括號“(”,進棧;

(2)檢測到第二個括號“)”,進棧。子表示式 “4+(2+8)” 完成匹配,匹配的括號都出棧;

(3)檢測到第三個括號“[”,進棧;

(4)檢測到第四個括號“(”,進棧。與(3)中的括號不匹配,但由於同是左括號,可以繼續匹配;

(5)檢測到第五個括號“)”,進棧。由括號的作用可知,後來的括號比先來的括號優先順序高,因此與(4)中括號匹配,匹配的括號都出棧;

(6)檢測到第六個括號“]”,進棧。由於原來優先順序更高的括號已完成,因此與(3)中括號匹配。匹配的括號都出棧,至此所有括號匹配完成。

 

需要注意的是,第一個括號進棧時,沒有比較物件,因此需要特別處理。

判斷函式 judge () 如下:

 1 Status judge(Stack *S)
 2 {
 3     //進行表示式的輸入和判斷 
 4     SElemType *p;
 5     char n;
 6     
 7     scanf("%c",&n);            //第一個括號的檢測
 8     while(n!='(' && n!='[')        //忽略數字等其他符號,直到輸入括號
 9     {
10         if(n==')' || n==']' || n=='#')    return FALSE;    //若為')'或']',則表明不匹配。'#'用於結束輸入
11         scanf("%c",&n);    
12     }
13     
14     if(n=='(' || n=='[')    Push(S,n);    //檢測到左括號,進棧
15     scanf("%c",&n);
16     while(n!='#')    //'#'用於結束輸入
17     {    
18         if(n=='(' || n==')' || n=='[' || n==']')
19         {
20             p=S->top;
21             Push(S,n);
22             if(*(p-1)=='(')        //與前一個括號比較
23             {
24                 if(*p==')')    
25                 {
26                     printf("%c\n",Pop(S));
27                     printf("%c\n",Pop(S));
28                 }
29                 else if(*p==']')    return FALSE;
30             }
31             else if(*(p-1)=='[')
32             {
33                 if(*p==']')    
34                 {
35                     printf("%c\n",Pop(S));
36                     printf("%c\n",Pop(S));
37                 }
38                 else if(*p==')')    return FALSE;
39             }
40         }
41         scanf("%c",&n);
42     }
43     if(S->top==S->base)    return TRUE; //棧內沒有元素時,說明匹配 
44     else return FALSE;
45 }

 

原始碼如下:

#include <stdio.h>
#include <stdlib.h>
#define INIT_SIZE 10
#define INCREMENT 5

#define OVERFLOW -2
#define FALSE 0 
#define OK 1
#define TRUE 1
#define ERROR 0

typedef char SElemType; 
typedef int Status;
typedef struct stack{
    SElemType *base;
    SElemType *top;
    int stacksize; 
}Stack;

Status InitStack(Stack *S)
{
    //初始化棧 
    S->base=(SElemType *)malloc(INIT_SIZE*sizeof(SElemType));
    if(!S->base) exit(OVERFLOW);
    S->top=S->base;
    S->stacksize=INIT_SIZE;
    return OK;
}

Status Push(Stack *S,char e)
{
    //入棧 
    if(S->top-S->base>=S->stacksize){    //棧滿,重新分配記憶體 
        S->base=(SElemType *)realloc(S->base,(INIT_SIZE+INCREMENT)*sizeof(SElemType));
        if(!S->base) exit(OVERFLOW);
        S->top=S->base+S->stacksize;
        S->stacksize+=INCREMENT;
    }
    *S->top++=e;
    return OK;
}

char Pop(Stack *S)
{
    //出棧 
    char e;
    
    if(S->top==S->base)    return ERROR;    //棧空,出錯 
    e=*(--S->top);
    return e;
}

Status judge(Stack *S)
{
    //進行表示式的輸入和判斷 
    SElemType *p;
    char n;
    
    scanf("%c",&n);            //第一個括號的檢測
    while(n!='(' && n!='[')        //忽略數字等其他符號,直到輸入括號
    {
        if(n==')' || n==']' || n=='#')    return FALSE;    //若為')'或']',則表明不匹配。'#'用於結束輸入
        scanf("%c",&n);    
    }
    
    if(n=='(' || n=='[')    Push(S,n);    //檢測到左括號,進棧
    scanf("%c",&n);
    while(n!='#')    //'#'用於結束輸入
    {    
        if(n=='(' || n==')' || n=='[' || n==']')
        {
            p=S->top;
            Push(S,n);
            if(*(p-1)=='(')        //與前一個括號比較
            {
                if(*p==')')    
                {
                    printf("%c\n",Pop(S));
                    printf("%c\n",Pop(S));
                }
                else if(*p==']')    return FALSE;
            }
            else if(*(p-1)=='[')
            {
                if(*p==']')    
                {
                    printf("%c\n",Pop(S));
                    printf("%c\n",Pop(S));
                }
                else if(*p==')')    return FALSE;
            }
        }
        scanf("%c",&n);
    }
    if(S->top==S->base)    return TRUE; //棧內沒有元素時,說明匹配 
    else return FALSE;
}

int main()
{
    Stack Sta;
    Stack *S=&Sta;
    
    printf("INITIALIZING...\n");
    if(InitStack(S)) printf("DONE!\n");

    printf("enter an expression(stop by '#'):\n");
    if(judge(S)==1)    printf("It's True!");
    else printf("It's False\n");
    
    return 0;
}
source