《資料結構和演算法》之符號匹配性檢測
一,問題描述:
在C語言中有一些符號是成對出現的,括號:(),【】,{},《》,<>;引號:“”,‘’;等都是成對出現,其在C語言中是無處不在的,幾乎所有的編譯器都具有語法檢查的能力,其中有一項就是括號的匹配性檢測,意思就是對應於左括號出現的時候就一定會有對應的右括號的匹配性檢測。如何實現編譯器中的符號成對檢測呢?
二,問題分析:
可能猛的看到這個題目都不知道要怎麼做,但仔細分析之後可以發現可以從以下這個思路來進行解答:
1,從第一個字元開始掃描,當遇見普通字元時忽略,當遇見左符號時壓入棧中;
2,當遇見右符號時就從棧中彈出棧頂符號進行匹配,如果匹配成功則繼續讀入下一個字元,如果匹配失敗,可以立即停止並且報錯;
3,成功時:這個時候所有字元掃描完畢,且棧為空。
失敗時:匹配失敗或者所有字元掃描完畢但棧非空。
舉例:
void f(int a[])
{
int (*p)[5];
p= NULL;
}
首先,從v開始掃描,屬於普通字元,一直掃描直到‘(’被掃描,此時將左符號壓入棧中,接著繼續掃描,又掃描到‘[’的時候遇到左符號,此時將該左符號壓入棧中,繼續掃描則遇到‘]’,此時‘[]’匹配成功,則這個兩個符號從棧中彈出,再繼續掃描,遇到‘)’,則剛好與之前的‘(’相匹配,此時“(”出棧,繼續掃描,遇到‘{’,入棧,再接著‘(’又入棧,繼續掃描直到‘)’此時匹配,出棧,繼續掃描遇到‘[’入棧,繼續遇到‘]’,又匹配成功,出棧;這樣一直匹配到最後遇到‘}’,出棧,匹配成功,此時棧為空,最後掃描結束。
三,演算法框架設計
scanner演算法的過程正如上述程式碼所示,首先要建立一個棧,按照上面二中的思路進行編寫。判斷左符號和右符號以及匹配函式均如下所示:int scanner(const char* code) { LinkStack* stack = LinkStack_Create();//建立棧S; int ret = 0; int i = 0; while( code[i] != '\0') { if(isLeft(code[i])) //code[i]為左括號 { LinkStack_Push(stack,(void*)(code + i)); //將code[i]出棧 } if(isRight(code[i])) //code[i]為右括號 { char* c = (char*)LinkStack_Pop(stack); //將code[i]入棧 if((c == NULL) || !match(*c,code[i])) //如果c與code[i]不匹配 { printf("%c does not match!\n",code[i]); //此時報錯 break; //停止迴圈 } } i++; } if((LinkStack_Size(stack)==0)&&(code[i]=='\0')) { printf("Succeed!\n"); //如果滿足if裡面的條件則匹配成功 ret = 1; } else { printf("Invalid code!\n"); //如果不滿足那些條件則匹配失敗,報錯 ret = 0; } LinkStack_Destroy(stack); //銷燬棧,釋放記憶體 return ret; }
左符號判斷函式:
int isLeft(char c)
{
int ret = 0;
switch(c)
{
case '<':
case '(':
case '[':
case '{':
case '\'':
case '\"':
ret = 1;
break;
default:
ret = 0;
break;
}
return ret;
}
右符號判斷函式:
int isRight(char c)
{
int ret = 0;
switch(c)
{
case '>':
case ')':
case ']':
case '}':
case '\'':
case '\"':
ret = 1;
break;
default:
ret = 0;
break;
}
return ret;
}
匹配函式:
int match(char left, char right)
{
int ret = 0;
switch(left)
{
case '<':
ret = (right == '>');
break;
case '(':
ret = (right == ')');
break;
case '[':
ret = (right == ']');
break;
case '{':
ret = (right == '}');
break;
case '\'':
ret = (right == '\'');
break;
case '\"':
ret = (right == '\"');
break;
default:
ret = 0;
break;
}
}
四,總的測試程式碼
#include <stdio.h>
#include <stdlib.h>
#include "LinkStack.h"
/* run this program using the console pauser or add your own getch, system("pause") or input loop */
int isLeft(char c)
{
int ret = 0;
switch(c)
{
case '<':
case '(':
case '[':
case '{':
case '\'':
case '\"':
ret = 1;
break;
default:
ret = 0;
break;
}
return ret;
}
int isRight(char c)
{
int ret = 0;
switch(c)
{
case '>':
case ')':
case ']':
case '}':
case '\'':
case '\"':
ret = 1;
break;
default:
ret = 0;
break;
}
return ret;
}
int match(char left, char right)
{
int ret = 0;
switch(left)
{
case '<':
ret = (right == '>');
break;
case '(':
ret = (right == ')');
break;
case '[':
ret = (right == ']');
break;
case '{':
ret = (right == '}');
break;
case '\'':
ret = (right == '\'');
break;
case '\"':
ret = (right == '\"');
break;
default:
ret = 0;
break;
}
}
int scanner(const char* code)
{
LinkStack* stack = LinkStack_Create();//建立棧S;
int ret = 0;
int i = 0;
while( code[i] != '\0')
{
if(isLeft(code[i])) //code[i]為左括號
{
LinkStack_Push(stack,(void*)(code + i)); //將code[i]出棧
}
if(isRight(code[i])) //code[i]為右括號
{
char* c = (char*)LinkStack_Pop(stack); //將code[i]入棧
if((c == NULL) || !match(*c,code[i])) //如果c與code[i]不匹配
{
printf("%c does not match!\n",code[i]); //此時報錯
break; //停止迴圈
}
}
i++;
}
if((LinkStack_Size(stack)==0)&&(code[i]=='\0'))
{
printf("Succeed!\n"); //如果滿足if裡面的條件則匹配成功
ret = 1;
}
else
{
printf("Invalid code!\n"); //如果不滿足那些條件則匹配失敗,報錯
ret = 0;
}
LinkStack_Destroy(stack); //銷燬棧,釋放記憶體
return ret;
}
int main(int argc, char *argv[])
{
const char* code = "void fint a[]) {int (*p)[5]; p = NULL;}";
scanner(code);
return 0;
}
在輸入"void fint a[]) {int (*p)[5]; p = NULL;}"字串的時候會出現圖1結果
圖1 結果不成功的現象截圖
在輸入"void f(int a[]) {int (*p)[5]; p = NULL;}"的時候會出現圖2結果:
圖2 結果成功的截圖