數據結構之棧的應用----C程序的括號配對檢查

這周學完了嚴老師的棧及其應用。

已經對棧的應用有了一定的瞭解了,並且感覺到數據結構實在是很強大,它幾乎可以解決我們生活中的大部分問題。

關於棧的基本常識,這裏不做過多的解釋,總之,其核心就是先進後出(FILO)

聯想到這種模式我們就可以很容易的知道,棧可以有如下幾種應用:

1、進制之間的轉換

2、C程序的括號配對檢查

3、迷宮求解問題

4、算術表達式求值

5、遞歸函數

......


這裏,我將以一個括號配對檢查的程序爲例,講述棧的應用。。。(之一)

起初看到這個題目是在K&R的書上看見的,當時看這個題時,簡直是找不到東南西北,就算看了答案也是模棱兩可的,

現在時隔半年,當我學到棧的時候,我纔對這個程序有了一個新的角度去理解,感覺着用棧去解決這個程序在思想上

很容易理解,但是效率上還不清楚,畢竟能力還沒達到可以提高程序運行效率的地步。


首先,我們得了解實現這個程序的基本思想

1、我們從一個C程序文本中查找括號(包括{},(),[],<>),當我們檢測到其中之一時,就將它push到棧中,如果棧裏的

top元素和它配對了(如:"{和}","(和)","[和]","<和>"。"}和{"不能算),就把它和top元素依次pop出來,當文本檢查完

,到了EOF時,如果棧爲空,則說明括號配對了,反之,則說明此C程序括號的配對有問題

2、然後,我們還需要解決一個問題,要是有雙引號和註釋符怎麼辦?很簡單,我們在檢查文本時,把它們當作特殊情

況處理,如果遇到了雙引號和註釋符,並且它們都配對了,則把它們之間的所有內容忽略掉就OK了

有了上述思想,我想這個程序應該就很容易實現了,我把它分爲了如下幾個步驟:

1、實現一個C程序文本的獲取功能,可以通過實現獲取一行字符的功能來實現獲取一段文本的功能

(1)我們可以寫一個名叫getline的函數,它的功能是從用戶的輸入中提取一行存入到一個字符串(char *line)中,並

以'\n'+'\0'爲每行結尾,返回這一行的字符數,不能將'\n'+'\0'計入其中;

(2)有了getline這個函數,我們對實現一段文本的提取就有了基礎了,我們寫這麼一個名叫gettext的函數,只需每獲取

一行之後就將這一行的首地址存入到一個字符串指針的形參中就可以了,形參爲:char **text,int i一開始我的想法很簡單,

在gettext函數裏定義一個line的數組(char line[MAXLINE]),然後直接getline,然後text[i++] = line;就OK了,但是問題就

在這裏產生了,如果每一次的line都通過這個賦值語句傳給*text的每一個元素*text[0],*text[1]...*text[n],那麼text的每一行

都將與最新的line相關聯,畢竟這是指針賦值給指針啊!!!而且,當這個gettext函數銷燬時,line數組也隨之銷燬,text

裏的每一行將會成爲野指針所隨機指向的一塊內存,這是一個相當大的問題啊!!!解決這個問題的辦法就是爲每一line

申請一塊動態內存空間,當然,必須得把line定義爲指針了。

這個功能實現的關鍵幾步:

/** 爲line指針申請動態內存,防止被銷燬**/

char *line = (char *)malloc(sizeof(char)*MAXLINE);

/** 一個獲取text的循環**/

//malloc a string line
while(1)
{
	lineLen = getline(line,MAXLINE);
	text[i] = line;
	++i;

	if(YES == hasEOF(line))
		break;

	line = (char *)malloc(sizeof(char)*MAXLINE);
}

2、實現棧的基本功能,init,push,pop,gettop等


(1)初始化(init)一個stack s,將創建一個s.top和一個s.base指針,top指向棧頂,移動用於彈出元素,base指向棧底,

不能移動,用以判斷stack是否爲空,有下面一條語句來判斷一個空stack:

if(s.top == s.base)
printf("Stack is NULL");
(2)壓入(push)和彈出(pop)一個元素,我們利用這兩個函數將滿足條件的元素push到stack中,它會將top加1,

pop一個元素將會把指針top減1,以保證top始終指向棧頂

(3)獲取top元素,這個函數將不會pop棧頂元素,但是可以獲取棧頂元素,這大大地提高了對棧的利用

3、最後是判斷括號配對的功能

(1)我們要有一個判斷字符是否是我們所認定的括號的函數IsBracket,傳入一個字符參數進行判斷,返回YES或者NO

(2)然後我們需要一個判斷括號是否匹配的小函數IsMatch,傳入需要比較的兩個字符,返回YES或者NO

(3)這樣我們就可以開始判斷整個text了,我將這個函數命名爲TextMatch,將文本text的首地址以及text的行數傳入即可,

沒有返回值,直接輸出是否完全配對的信息,這也是一個缺陷(無法準確找出不配對的位置),前面已經提過了,我們需

要把雙引號和註釋符當作特殊情況來處理,我們將一個一個字符進行判斷,雙引號和註釋符中的內容需要被忽視,當我們

讀取到第一個雙引號時,我們將它push到stack中,然後只需從這個雙引號開始進入循環,尋找下一個雙引號,如果直到

文件末尾都沒有雙引號的出現,則就表明text未完全配對,如果找到了下一個雙引號,那麼就在下一個雙引號的位置跳出

這個循環,進入到最初文本單個字符遍歷的主循環中,這樣雙引號的情況就可以完美解決了,註釋符同上。

(還有一種情況是雙斜槓,這個的忽略方法與/*差不多,只不過與//匹配的應該是'\n')

(單引號的情況要用轉義字符'\'',因爲單引號在C程序有着特殊的含義)

至於主文本中的括號匹配已經在開始的時候說過來,這裏略過。

/************************所有函數的源代碼**************************/

上述所有函數在我的代碼共享裏面均有完整源代碼,如下標題:

gettext,stack和bracket_matck三個

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章