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