《数据结构》考研天勤和王道 第三章 栈、队列、数组和广义表
《數(shù)據(jù)結(jié)構(gòu)》天勤和王道 第三章 棧、隊(duì)列、數(shù)組和廣義表
- 天勤的內(nèi)容
- 1.用棧實(shí)現(xiàn)表達(dá)式的轉(zhuǎn)換
- 1.1中綴轉(zhuǎn)后綴
- 1.2中綴轉(zhuǎn)前綴
- 1.3后綴轉(zhuǎn)前綴
- 2.用棧實(shí)現(xiàn)表達(dá)式的計(jì)算
- 2.1用棧求中綴表達(dá)式的值(需要兩個(gè)棧)
- 2.2用棧求后綴表達(dá)式的值(只需一個(gè)棧)
- 2.3用棧求前綴表達(dá)式的值(只需一個(gè)棧)
- 3.循環(huán)隊(duì)列的配置問(wèn)題
- 3.1正常配置
- 3.2非正常配置
- 3.2.1第一種情況
- 3.2.2第二種情況
- 4.用棧模擬隊(duì)列
- 5.用棧解決括號(hào)匹配問(wèn)題
- 6.數(shù)組
- 7.廣義表
- 7.1邏輯結(jié)構(gòu)
- 7.2存儲(chǔ)結(jié)構(gòu)
- 7.2.1頭尾鏈表存儲(chǔ)結(jié)構(gòu)
- 7.2.2擴(kuò)展線性表存儲(chǔ)結(jié)構(gòu)
- 王道的內(nèi)容
- 1.棧
- 1.1順序棧
- 1.2鏈棧
- 2.隊(duì)列
- 2.1順序?qū)崿F(xiàn)隊(duì)列(循環(huán)隊(duì)列)
- 2.1.1入隊(duì)操作
- 2.1.2出隊(duì)操作
- 2.1.3方案一:循環(huán)隊(duì)列的判空、判滿條件
- 2.1.4方案二:循環(huán)隊(duì)列的判空、判滿條件
- 2.1.5方案三:循環(huán)隊(duì)列的判空、判滿條件
- 2.1.6其他出題方式
- 2.1.7小結(jié)
- 2.2鏈?zhǔn)綄?shí)現(xiàn)隊(duì)列
- 2.2.1入隊(duì)操作
- 2.2.2出隊(duì)操作
- 3.棧的應(yīng)用——表達(dá)式求值
- 3.1中綴式轉(zhuǎn)后綴式(手算 適合作選擇題)
- 3.2中綴式轉(zhuǎn)前綴式(手算 適合作選擇題)
- 3.3中綴式轉(zhuǎn)后綴式(機(jī)算)
- 3.4中綴表達(dá)式的計(jì)算
- 4.棧的應(yīng)用——遞歸
- 5.特殊矩陣壓縮存儲(chǔ)
- 5.1一維數(shù)組的存儲(chǔ)結(jié)構(gòu)
- 5.2二維數(shù)組的存儲(chǔ)結(jié)構(gòu)
- 5.2.1行優(yōu)先存儲(chǔ)
- 5.2.2列優(yōu)先存儲(chǔ)
- 5.3普通矩陣的存儲(chǔ)
- 5.4對(duì)稱矩陣的壓縮存儲(chǔ)
- 5.4.1行優(yōu)先原則
- 5.4.2列優(yōu)先原則
- 5.5三角矩陣的壓縮存儲(chǔ)
- 5.6三對(duì)角矩陣的壓縮存儲(chǔ)
- 5.7稀疏矩陣的壓縮存儲(chǔ)
- 5.7.1順序存儲(chǔ)
- 5.7.2十字鏈表法
天勤的內(nèi)容
1.用棧實(shí)現(xiàn)表達(dá)式的轉(zhuǎn)換
1.1中綴轉(zhuǎn)后綴
規(guī)則:從左到右掃描表達(dá)式,循環(huán)進(jìn)行以下步驟:如果遇到操作數(shù)就把它寫(xiě)出來(lái)。如果遇到運(yùn)算符就把它入棧,但在入棧之前需要拿當(dāng)前運(yùn)算符與棧頂運(yùn)算符進(jìn)行一下比較,比較它們的運(yùn)算優(yōu)先級(jí),如果當(dāng)前運(yùn)算符小于或等于棧頂運(yùn)算符,就把棧頂運(yùn)算符出棧,并將其寫(xiě)入到當(dāng)前得到的結(jié)果表達(dá)式中。然后繼續(xù)比較,如果優(yōu)先級(jí)還是小于或等于,就繼續(xù)把棧頂運(yùn)算符出棧,直到當(dāng)前的運(yùn)算符大于棧頂運(yùn)算符才將當(dāng)前運(yùn)算符入棧。棧空的情況下,直接入棧。當(dāng)遇到棧頂元素是左括號(hào)的情況下也是直接入棧,直到掃描到當(dāng)前運(yùn)算符是右括號(hào)時(shí)才依次將棧中元素出棧,直到左括號(hào),并把左括號(hào)出棧,不寫(xiě)會(huì)結(jié)果表達(dá)式中,直接把左括號(hào)扔掉。當(dāng)掃描完整個(gè)表達(dá)式后,若棧還不為空,則把棧中全部的運(yùn)算符出棧并寫(xiě)入結(jié)果表達(dá)式中。
代碼如下:
//判斷優(yōu)先級(jí)的函數(shù) int getPriority(char op){if(op=='+'||op=='-')return 0;elsereturn 1; } //判斷優(yōu)先級(jí)的函數(shù) int getPriority(char op){if(op=='+'||op=='-')return 0;elsereturn 1; } void infixToPostFix(char infix[],char s2[],int &top2){ //infix[]為中綴表達(dá)式,s2[]用來(lái)存放后綴表達(dá)式,注意這里棧頂是引用型 char s1[maxSize]; int top1=-1; //新建一個(gè)棧并設(shè)置棧頂 int i=0;while(infix[i]!='\0'){if('0'<=infix[i]&&infix[i]<='9'){ //默認(rèn)表達(dá)式中數(shù)字都為個(gè)位數(shù) s2[++top2]=infix[i];++i;}else if(infix[i]=='('){s1[++top1]='(';++i;}else if(infix[i]=='+'||infix[i]=='-'||infix[i]=='*'||infix[i]=='/'){if(top1==-1||s1[top1]=='('||getPriority(infix[i])>getPriority(s1[top1])){s1[++top1]=infix[i];i++;}else{s2[++top2]=s1[top1--];}}else if(infix[i]==')'){while(s1[top1]!='('){s2[++top2]=s1[top1--];}--top1; //將左括號(hào)出棧,并扔掉 ++i;}}while(top1!=-1){ //若棧不為空,則依次將棧中的運(yùn)算符出棧到結(jié)果表達(dá)式中 s2[++top2]=s1[top1--];} }1.2中綴轉(zhuǎn)前綴
規(guī)則:是一個(gè)跟中綴轉(zhuǎn)后綴一個(gè)相反的過(guò)程。從右往左掃描表達(dá)式,這里是遇到右括號(hào)入棧,直到遇到左括號(hào)全部出棧。如果遇到運(yùn)算符就把它入棧,但在入棧之前需要拿當(dāng)前運(yùn)算符與棧頂運(yùn)算符進(jìn)行一下比較,比較它們的運(yùn)算優(yōu)先級(jí),如果當(dāng)前運(yùn)算符小于棧頂運(yùn)算符,就把棧頂運(yùn)算符出棧,并將其寫(xiě)入到當(dāng)前得到的結(jié)果表達(dá)式中。然后繼續(xù)比較,如果優(yōu)先級(jí)還是小于,就繼續(xù)把棧頂運(yùn)算符出棧,直到當(dāng)前的運(yùn)算符大于或等于棧頂運(yùn)算符才將當(dāng)前運(yùn)算符入棧。
代碼如下:
//判斷優(yōu)先級(jí)的函數(shù) int getPriority(char op){if(op=='+'||op=='-')return 0;elsereturn 1; } void infixToPostFix(char infix[],int len,char s2[],int &top2){ //infix[]為中綴表達(dá)式,len為中綴表達(dá)式的長(zhǎng)度,s2[]用來(lái)存放前綴表達(dá)式,注意這里棧頂是引用型 char s1[maxSize]; int top1=-1; //新建一個(gè)棧并設(shè)置棧頂 int i=len-1; //與轉(zhuǎn)后綴的不同處 while(i>=0){if('0'<=infix[i]&&infix[i]<='9'){ //默認(rèn)表達(dá)式中數(shù)字都為個(gè)位數(shù) s2[++top2]=infix[i];--i; //與轉(zhuǎn)后綴的不同處}else if(infix[i]==')'){ //與轉(zhuǎn)后綴的不同處s1[++top1]=')';--i;}else if(infix[i]=='+'||infix[i]=='-'||infix[i]=='*'||infix[i]=='/'){if(top1==-1||s1[top1]==')'||getPriority(infix[i])>=getPriority(s1[top1])){ //與轉(zhuǎn)后綴的不同處,這里是大于等于 s1[++top1]=infix[i];--i;}else{s2[++top2]=s1[top1--];}}else if(infix[i]=='('){ //與轉(zhuǎn)后綴的不同處while(s1[top1]!=')'){s2[++top2]=s1[top1--];}--top1; //將左括號(hào)出棧,并扔掉 --i;}}while(top1!=-1){ //若棧不為空,則依次將棧中的運(yùn)算符出棧到結(jié)果表達(dá)式中 s2[++top2]=s1[top1--];} }1.3后綴轉(zhuǎn)前綴
規(guī)則:當(dāng)兩個(gè)子表達(dá)式遇到運(yùn)算符時(shí),出棧,并把第一個(gè)出棧的表達(dá)式放在右邊,第二個(gè)出棧的表達(dá)式放在左邊,運(yùn)算符放在最前面,然后再次入棧。循環(huán)進(jìn)行這個(gè)過(guò)程。
2.用棧實(shí)現(xiàn)表達(dá)式的計(jì)算
2.1用棧求中綴表達(dá)式的值(需要兩個(gè)棧)
規(guī)則:需要兩個(gè)棧(s1和s2),一個(gè)用來(lái)暫存操作數(shù),一個(gè)用來(lái)暫存運(yùn)算符。當(dāng)遇到操作數(shù)的時(shí)候就入s1棧;遇到左括號(hào)的時(shí)候,就入s2棧;當(dāng)遇到運(yùn)算符的時(shí)候就得進(jìn)行判斷,如果此時(shí)s2棧空或s2棧頂為左括號(hào)就直接入s2棧,如果此時(shí)掃描到的運(yùn)算符大于棧頂運(yùn)算符的優(yōu)先級(jí)則入s2棧,否則把s2棧頂?shù)倪\(yùn)算符出棧,同時(shí)從s1棧中出棧兩個(gè)操作數(shù)并進(jìn)行一次運(yùn)算,而第一次出棧的操作數(shù)在右邊,第二次出棧的操作數(shù)在左邊,并將運(yùn)算結(jié)果入s1棧,循環(huán)執(zhí)行這個(gè)過(guò)程,直到當(dāng)前掃描到的運(yùn)算符的優(yōu)先級(jí)小于或等于當(dāng)前棧頂運(yùn)算符的優(yōu)先級(jí),才把當(dāng)前掃描到的運(yùn)算符入棧;如果遇到的是右括號(hào),則連續(xù)出棧運(yùn)算符直到遇到左括號(hào),每次都執(zhí)行上述的運(yùn)算并把運(yùn)算結(jié)果入s1棧;最后,當(dāng)掃描完整個(gè)表達(dá)式時(shí),如果s2棧中還有運(yùn)算符,則依次出棧,進(jìn)行運(yùn)算并把運(yùn)算結(jié)果壓入s1棧中,當(dāng)s2棧空時(shí),s1棧頂元素就是最后的運(yùn)算結(jié)果。
舉個(gè)例子:
代碼如下:
2.2用棧求后綴表達(dá)式的值(只需一個(gè)棧)
規(guī)則:從左到右掃描整個(gè)表達(dá)式,當(dāng)遇到操作數(shù)的時(shí)候就入棧,當(dāng)遇到運(yùn)算符的時(shí)候,就從棧中彈出兩個(gè)操作數(shù)并計(jì)算結(jié)果后壓入棧中,當(dāng)要注意的是,第一個(gè)彈出的操作數(shù)在右邊,第二個(gè)彈出的操作數(shù)在左邊。當(dāng)整個(gè)掃描過(guò)程結(jié)束后,棧頂就是運(yùn)算結(jié)果。
舉個(gè)例子:
代碼如下:
2.3用棧求前綴表達(dá)式的值(只需一個(gè)棧)
規(guī)則:從右往左掃描整個(gè)表達(dá)式,遇到操作數(shù)就入棧,遇到運(yùn)算符就出棧兩個(gè)操作數(shù)。不過(guò)與后綴表達(dá)式不同的是,第一次出棧的數(shù)在左邊,第二次出棧的數(shù)在右邊。
舉個(gè)例子:
代碼如下:
3.循環(huán)隊(duì)列的配置問(wèn)題
往年真題中默認(rèn)循環(huán)隊(duì)列的性質(zhì),在這里我們稱為正常配置。
3.1正常配置
隊(duì)空時(shí),頭指針和尾指針指向同一個(gè)位置。
入隊(duì)時(shí),尾指針前移一位。先移動(dòng)指針再入隊(duì)元素。
出隊(duì)時(shí),頭指針也前移一位。
當(dāng)繼續(xù)出隊(duì)時(shí),就隊(duì)空了,即頭指針和尾指針指向同個(gè)位置。
我們應(yīng)該留出一個(gè)位置來(lái)區(qū)分隊(duì)空和隊(duì)滿。隊(duì)滿時(shí),頭指針和尾指針相差一個(gè)位置。
以上就是一般題目默認(rèn)的正常配置,但當(dāng)題目有給限定條件時(shí),就不要直接按照這個(gè)正常配置來(lái)。
3.2非正常配置
曾經(jīng)在考題中出現(xiàn)過(guò)的非正常配置,也就是沒(méi)有按照上面的正常配置的循環(huán)隊(duì)列。
3.2.1第一種情況
隊(duì)空的情況跟正常配置一樣。頭指針和尾指針指向同一個(gè)地方。
這里就有所不同了,是先入隊(duì)元素再移動(dòng)指針。入隊(duì)一個(gè)元素后,再把尾指針前移一位。
出隊(duì)也是先出頭指針指向的元素,再移動(dòng)頭指針。
隊(duì)滿的情況跟正常配置一樣。如果尾指針再前移一位后取余等于頭指針則隊(duì)滿。
小結(jié):跟正常配置不同的就是在入隊(duì)跟出隊(duì)這里,而這樣導(dǎo)致的結(jié)果就是,頭指針指向隊(duì)頭元素,而尾指針指向隊(duì)尾元素的后一位。正常配置是頭指針指向隊(duì)頭元素的前一個(gè),尾指針指向隊(duì)尾元素。
計(jì)算隊(duì)中元素的公式是跟正常配置一樣的。有可能中間推導(dǎo)過(guò)程有點(diǎn)不一樣。
3.2.2第二種情況
隊(duì)空的情況是頭指針和尾指針相差一個(gè)位置,判斷條件是正常配置的判空條件。
入隊(duì)時(shí)是先移動(dòng)尾指針,再入隊(duì)元素。
隊(duì)滿時(shí),頭指針和尾指針相隔一個(gè)位置,所以這里判斷隊(duì)滿是得+2。如果是不空一個(gè)位置,全部占滿,則頭指針和尾指針只相差一個(gè)位置,則判斷條件跟判空條件是一樣的,所以不行,得空一個(gè)位置。
總結(jié):只要題目設(shè)計(jì)符合隊(duì)列的情況,就都可以配置進(jìn)行變化,所以這里要多注意一下。
4.用棧模擬隊(duì)列
5.用棧解決括號(hào)匹配問(wèn)題
規(guī)則:從左到右掃描整個(gè)表達(dá)式,如果遇到左括號(hào)則入棧;如果遇到右括號(hào)就出棧,如果此時(shí)棧空則括號(hào)不匹配,如果可以出棧,則判斷左右括號(hào)是否匹配,如果匹配則繼續(xù)掃描,否則直接判斷不匹配。當(dāng)掃描完整個(gè)表達(dá)式后,棧中還有元素,則說(shuō)明不匹配。
舉個(gè)例子:
代碼如下:
6.數(shù)組
數(shù)組和矩陣部分可以直接看下面王道對(duì)應(yīng)的內(nèi)容,已經(jīng)有插圖和加以解釋了。
7.廣義表
7.1邏輯結(jié)構(gòu)
廣義表(Lists,又稱列表)是一種非連續(xù)性的數(shù)據(jù)結(jié)構(gòu),是線性表的一種推廣。即廣義表中放松對(duì)表元素的原子限制,容許它們具有其自身結(jié)構(gòu)。
廣義表中的每個(gè)元素即可以是原子,也可以是廣義表。突破了線性表帶表元素的限制,線性表中的每個(gè)元素都是不可再分的原子。
GetTail()是取表尾元素,所以也是一個(gè)廣義表,要加括號(hào)。
7.2存儲(chǔ)結(jié)構(gòu)
7.2.1頭尾鏈表存儲(chǔ)結(jié)構(gòu)
“1”代表是廣義表結(jié)點(diǎn),“0”代表原子結(jié)點(diǎn)。
7.2.2擴(kuò)展線性表存儲(chǔ)結(jié)構(gòu)
王道的內(nèi)容
1.棧
1.1順序棧
1.2鏈棧
鏈棧相當(dāng)于單鏈表,插入和刪除都在頭節(jié)點(diǎn)(開(kāi)始結(jié)點(diǎn))操作。
2.隊(duì)列
棧和隊(duì)列都屬于線性表,只不過(guò)操作所限。
2.1順序?qū)崿F(xiàn)隊(duì)列(循環(huán)隊(duì)列)
2.1.1入隊(duì)操作
把順序?qū)崿F(xiàn)的隊(duì)列,經(jīng)過(guò)取模變成邏輯是的“環(huán)”,也就是循環(huán)隊(duì)列。上面這種情況,隊(duì)滿是犧牲一個(gè)存儲(chǔ)單元的。
2.1.2出隊(duì)操作
2.1.3方案一:循環(huán)隊(duì)列的判空、判滿條件
2.1.4方案二:循環(huán)隊(duì)列的判空、判滿條件
2.1.5方案三:循環(huán)隊(duì)列的判空、判滿條件
2.1.6其他出題方式
第一種是隊(duì)尾指針指向隊(duì)尾元素的后一個(gè)位置。還有一種出題方式就是隊(duì)尾指針指向隊(duì)尾元素。
2.1.7小結(jié)
2.2鏈?zhǔn)綄?shí)現(xiàn)隊(duì)列
2.2.1入隊(duì)操作
2.2.2出隊(duì)操作
3.棧的應(yīng)用——表達(dá)式求值
3.1中綴式轉(zhuǎn)后綴式(手算 適合作選擇題)
3.2中綴式轉(zhuǎn)前綴式(手算 適合作選擇題)
3.3中綴式轉(zhuǎn)后綴式(機(jī)算)
這里可以看作是天勤的補(bǔ)充,有解釋這些運(yùn)算為什么要有這樣子的順序。
當(dāng)表達(dá)式中存在有括號(hào)的情況下:
當(dāng)遇到運(yùn)算符出現(xiàn)我們確定不了運(yùn)算順序的時(shí)候,我們都可以先壓入到棧里。
因?yàn)槔ㄌ?hào)內(nèi)的運(yùn)算,我們需要先運(yùn)算,所以就括號(hào)內(nèi)的運(yùn)算可以直接生效。
3.4中綴表達(dá)式的計(jì)算
4.棧的應(yīng)用——遞歸
在編程的過(guò)程中,可以自定義棧,將遞歸算法改造成非遞歸算法。
5.特殊矩陣壓縮存儲(chǔ)
5.1一維數(shù)組的存儲(chǔ)結(jié)構(gòu)
5.2二維數(shù)組的存儲(chǔ)結(jié)構(gòu)
5.2.1行優(yōu)先存儲(chǔ)
5.2.2列優(yōu)先存儲(chǔ)
5.3普通矩陣的存儲(chǔ)
5.4對(duì)稱矩陣的壓縮存儲(chǔ)
5.4.1行優(yōu)先原則
總結(jié)起來(lái)就是這樣:
5.4.2列優(yōu)先原則
5.5三角矩陣的壓縮存儲(chǔ)
5.6三對(duì)角矩陣的壓縮存儲(chǔ)
5.7稀疏矩陣的壓縮存儲(chǔ)
5.7.1順序存儲(chǔ)
5.7.2十字鏈表法
總結(jié)
以上是生活随笔為你收集整理的《数据结构》考研天勤和王道 第三章 栈、队列、数组和广义表的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 摩斯密码
- 下一篇: 基于蒙特卡洛模型的排队问题求解