利用堆疊實現符號匹配(c語言)
請編寫程式檢查C語言源程式中下列符號是否配對:/*
與*/
、(
與)
、[
與]
、{
與}
。
輸入格式:
輸入為一個C語言源程式。當讀到某一行中只有一個句點.
和一個回車的時候,標誌著輸入結束。程式中需要檢查配對的符號不超過100個。
輸出格式:
首先,如果所有符號配對正確,則在第一行中輸出YES
,否則輸出NO
。然後在第二行中指出第一個不配對的符號:如果缺少左符號,則輸出?-右符號
;如果缺少右符號,則輸出左符號-?
。
輸入樣例1:
void test() { int i, A[10]; for (i=0; i<10; i++) { /*/ A[i] = i; } .
輸出樣例1:
NO
/*-?
輸入樣例2:
void test()
{
int i, A[10];
for (i=0; i<10; i++) /**/
A[i] = i;
}]
.
輸出樣例2:
NO
?-]
輸入樣例3:
void test()
{
int i
double A[10];
for (i=0; i<10; i++) /**/
A[i] = 0.1*i;
}
.
輸出樣例3:
YES
本程式碼取自陳越《資料結構學習與實驗指導》第二版,作者在上面標註註釋供自己學習,僅參考
程式碼
#include <stdio.h>
#include <stdlib.h>
#define MAXN 100 //最大的容量
typedef enum{false,true}bool;
typedef enum{ret,lc,lbrc,lbrkt,lpr,rc,rbrc,rbrkt,rpr,others}Token;
//用代號對各個符號命名,l開頭的是左型別({,/*,[,(),r開頭的是右(},*/,],))。ret回車,others其它字元,如數字等
typedef Token ElementType;
typedef int Position;
typedef struct SNode* PtrToSNode;
struct SNode{ //堆疊的定義
ElementType *Data;
Position Top;
int MaxSize;
};
typedef PtrToSNode Stack;
//堆疊相關操作
Stack CreateStack(int MaxSize);
bool IsEmpty(Stack S); //判斷棧空
void Push(Stack S,ElementType X); //入棧
ElementType Peek(Stack S); //取出棧頂元素
void Pop(Stack S); //出棧
//讀取和輸出
bool IsEnd(int newline,char *c); //判斷是否到行尾
Token GetToken(char c); //
bool IsPaired(Token t1,Token t2); //
void PrintS(Token t); //輸出對應的符號,部分符號用了2個位元組,專門寫一個函式去輸出它
int Check(Token* T1,Token* T2); //如果最後棧中不為空,則剩下的是未匹配的
int main(){
Token T1,T2;
int error=Check(&T1,&T2);
if(!error)
printf("YES\n");
else{
printf("NO\n");
switch(error){
case 1:printf("?-");PrintS(T1);break;
case 2:PrintS(T2);printf("-?");break;
default:break;
}
printf("\n");
}
return 0;
}
Stack CreateStack(int MaxSize){
Stack S=(Stack)malloc(sizeof(struct SNode));
S->Data=(ElementType*)malloc(MaxSize* sizeof(ElementType));
S->Top=-1;
S->MaxSize=MaxSize;
return S;
}
bool IsEmpty(Stack S){
return (S->Top==-1);
}
void Push(Stack S,ElementType X){
S->Data[++(S->Top)]=X;
}
ElementType Peek(Stack S){
return (S->Data[S->Top]);
}
void Pop(Stack S){
(S->Top)--;
}
int Check (Token *T1,Token* T2){
Stack S; //檢測用的堆疊
char c; //存讀入字元
Token t; //存字元轉化後的型別
int newline,error; //因為我們題目是有多行的,newline用來標記是否為新行,error標記錯誤;
S=CreateStack(MAXN);
newline =1;error=0; //無錯誤,新行
while(1){ //讀入所有字元
scanf("%c",&c);
if(IsEnd(newline,&c)) break; //如果到文章尾跳出迴圈
else{
switch(t=GetToken(c)){
case lc: //如果是左型別
case lbrc:
case lbrkt:
case lpr:
Push(S,t); newline = 0;break; //不是新行,入檢測棧
case rc: //如果是右型別
case rbrc:
case rbrkt:
case rpr:
if(IsEmpty(S)) error=1; //棧空了,error為1,即為入棧失敗
else if(!IsPaired(t,Peek(S))) error=2; //錯誤2
else Pop(S); //一切正常消去一對符號
newline=0; //不再是新行;
break;
case ret: newline =1;break; //遇見回車
default: newline =0;break; //其它字元跳過不處理
}
if(error) break; //有錯誤跳出迴圈
}
}
if(!error&&!IsEmpty(S)) error=2; //讀到結尾棧沒空,左半符號有多
(*T1)=t;
(*T2)=Peek(S);
return error;
}
bool IsEnd(int newline,char *c)
{/*判斷是否讀到結尾*/
if(newline && (*c)=='.'){
scanf("%c",c);
if((*c)=='\n') return true;
else return false;
}
else return false;
}
Token GetToken(char c)
{/*返回字元的型別*/
switch (c) {
case '\n': return ret;
case '{' : return lbrc;
case '[' : return lbrkt;
case '(' : return lpr;
case '/' :
scanf("%c",&c);
if(c=='*') return lc;
else return GetToken(c);
/*如果不是左註釋符,還要檢查c的型別*/
case '}' : return rbrc;
case ']' : return rbrkt;
case ')' : return rpr;
case '*' :
scanf("%c",&c);
if(c=='/') return rc;
else return GetToken(c);
/*如果不是右註釋符,還要檢查c的型別*/
default: return others;
}
}
bool IsPaired(Token t1,Token t2)
{
return (t1-t2)==4;
/*t1是右半符,t2是左半符*/
/*如果它們的enum值差4,說明是匹配的*/
}
void PrintS(Token t)
{
switch (t) {
case lc:printf("/*");break;
case lbrc:printf("{");break;
case lbrkt:printf("[");break;
case lpr:printf("(");break;
case rc:printf("*/");break;
case rbrc:printf("}");break;
case rbrkt:printf("]");break;
case rpr:printf(")");break;
default: break;
}
}