【數(shù)據(jù)結(jié)構(gòu)】棧

本文更新于個(gè)人博客Burnside Blog

總的來(lái)說(shuō),棧(Stack)是一種應(yīng)用十分廣泛的線(xiàn)性數(shù)據(jù)結(jié)構(gòu),我們大多數(shù)時(shí)候可以把它理解成一個(gè)杯子,杯子只有一個(gè)口,它既是進(jìn)入的入口,也是退出的出口。的確如此,棧是一種先入后出(LIFO)的數(shù)據(jù)結(jié)構(gòu),它支持插入與刪除兩種操作,且兩個(gè)操作僅可以在一端進(jìn)行。

為了方便起見(jiàn),我們不使用動(dòng)態(tài)方式生成一個(gè)棧,或銷(xiāo)毀一個(gè)棧,我們只考慮一個(gè)靜態(tài)的棧的功能實(shí)現(xiàn)。棧中的元素可以是任何的用戶(hù)自定義類(lèi)型,為了方便起見(jiàn),我們假設(shè)元素的類(lèi)型為int,如需要?jiǎng)e的類(lèi)型,只需要靈活處理即可。接下來(lái)我們申請(qǐng)一塊長(zhǎng)度為MaxSize的連續(xù)內(nèi)存來(lái)存儲(chǔ)這個(gè)棧,這時(shí)它又被稱(chēng)為順序棧。

int Stack[MaxSize];

這樣我們就成功獲得了一個(gè)自己的棧??紤]往棧中插入元素或刪除元素,所改變的只有最頂部的元素距棧底的距離,這里的距離表示的是元素個(gè)數(shù),我們把這個(gè)頂部稱(chēng)為棧頂,可以用一個(gè)變量top來(lái)維護(hù),最頂部的元素為棧頂元素,不難發(fā)現(xiàn),每一次的刪除操作,總是刪除的棧頂元素。

因此,我們會(huì)得到棧的幾個(gè)操作:

1、插入元素

int push(int x){

? ? Stack[++top]=x;

? ? return top;

}

插入一個(gè)元素很簡(jiǎn)單,只需要將棧頂指向數(shù)組內(nèi)的下一個(gè)位置,然后把該位置賦值為要插入的值即可,函數(shù)中的變量x即為需要插入的值,top為棧頂,此函數(shù)返回值為插入后的棧頂。注意,當(dāng)棧為空的時(shí)候,變量top應(yīng)當(dāng)?shù)扔?1。

2、刪除元素

int pop(){

? ? return --top;

}

刪除一個(gè)元素更簡(jiǎn)單,只需要將棧頂下移一個(gè)就可以。注意,原來(lái)的棧頂元素不需要做任何的改變,因?yàn)橹灰迦氲竭@個(gè)位置,這個(gè)位置就會(huì)立馬被賦值上被插入的新的元素,所以只需要讓棧頂下移即可,而并不需要改變棧頂元素的值。此函數(shù)返回的是刪除后的棧頂。要注意,這里有一個(gè)潛在的問(wèn)題,如果這個(gè)時(shí)候棧已空,但仍然調(diào)用了pop(),可能會(huì)使以后的操作訪(fǎng)問(wèn)到非法位置,因此,請(qǐng)務(wù)必確保棧是非空的,再使用pop(),為了方便確保棧是否為空,我們引入一個(gè)新的函數(shù)。

3、查詢(xún)棧是否為空

bool empty(){

? ? return top==-1?true:false;

}

很簡(jiǎn)單,棧為空的標(biāo)志為top等于-1,直接調(diào)用即可。

4、查詢(xún)?,F(xiàn)在的大?。╯ize)

int size(){

? ? return top+1;

}

也很簡(jiǎn)單,棧的大小為top+1。

5、查詢(xún)棧頂元素

int top(){

? ? return Stack[top];

}

請(qǐng)注意,請(qǐng)務(wù)必在棧非空的情況下使用該命令。

6、刪除棧內(nèi)的所有元素

void clear(){

? ? while(!empty()) pop();

}

很自然的實(shí)現(xiàn),當(dāng)棧為非空時(shí),一直刪除元素就可以了。

以上為棧的所有操作,部分書(shū)中還介紹了鏈?zhǔn)綏?,本文中不再涉及,具體的實(shí)現(xiàn)思想與上述六個(gè)函數(shù)一樣。

棧有很多實(shí)際的應(yīng)用,其中常見(jiàn)的有:把一個(gè)十進(jìn)制數(shù)拆分為二進(jìn)制,查詢(xún)一個(gè)括號(hào)序列是否能夠匹配,計(jì)算表達(dá)式的值等。我們主要來(lái)寫(xiě)查詢(xún)括號(hào)序列是否匹配,剩下兩個(gè)常見(jiàn)功能讀者可以自行完成。

括號(hào)序列,是僅由(與)構(gòu)成的序列,匹配的定義如下:

1. ()是一個(gè)合法匹配。

2. 如果A是一個(gè)合法匹配,則(A)是一個(gè)合法匹配。

3. 如果A和B都是合法匹配,則AB是一個(gè)合法匹配。

不難發(fā)現(xiàn),()()(())((())())是一個(gè)合法匹配,而(()不是一個(gè)合法匹配。

判斷的過(guò)程也很輕松,我們只需要模擬這個(gè)匹配的過(guò)程就可以了,具體操作步驟如下:

1. 如果當(dāng)前讀取到一個(gè)(,進(jìn)棧,讀取下一位。

2. 如果當(dāng)前讀取到一個(gè)),如果棧非空,取棧頂?shù)挠依ㄌ?hào)與之匹配,讀取下一位;如果???,則找不到括號(hào)與之匹配,證明其不合法。

3. 如果讀完了整個(gè)括號(hào)序列???,則整個(gè)括號(hào)序列合法,否則不合法。

正確性顯然,不過(guò)多贅述,代碼如下:

#include<iostream>

#include<cstdio>

const int MaxSize=1000;

char Stack[MaxSize];

int top=-1,flag=true;

int main(){

? ? char c;

? ? while((c=getchar())!=EOF){

? ? ? ? if(c=='(') Stack[++top]='(';

? ? ? ? else{

? ? ? ? ? ? if(top==-1){

? ? ? ? ? ? ? ? flag=false;

? ? ? ? ? ? ? ? break;

? ? ? ? ? ? }

? ? ? ? ? ? top--;

? ? ? ? }

? ? }

? ? if(top!=-1) flag=false;

? ? printf(flag?"legal":"illegal");

? ? return 0;

}

可能會(huì)有人表示輸出總是illegal,因?yàn)樵谝婚_(kāi)始讀的時(shí)候把回車(chē)也讀進(jìn)去了,可以使用文件輸入輸出,最后不換行就可以了,或者可以采用其他的輸入方式。

在某些特殊應(yīng)用中,還會(huì)使用到單調(diào)棧,因?yàn)閮H在競(jìng)賽中常用,因此不在本文中描述。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀(guān)點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容