王道408数据结构——第二章 线性表
文章目錄
- 一、線性表的定義和基本操作
- 線性表
- 順序表
- 1.插入操作
- 2.刪除操作
- 3.按值查找(順序查找)
- 二、單鏈表
- 1. 頭插法
- 2. 尾插法
- 3. 按序號查找
- 4. 按值查找
- 5. 插入結點
- 6. 刪除結點
- 7. 求表長
- 三、 雙鏈表
- 1. 插入
- 2. 刪除
- 四、循環鏈表
- 五、靜態鏈表
- 六、順序表和鏈表的比較
- 七、特殊矩陣的壓縮儲存
- 數組的定義
- 數組的存儲結構
- 矩陣的壓縮存儲
- 1. 對稱矩陣
- 2. 三角矩陣
- 3. 三對稱矩陣(帶狀矩陣)
- 4. 稀疏矩陣
- 八、廣義表
- 廣義表的定義
- 廣義表的操作
一、線性表的定義和基本操作
線性表
線性表是具有相同數據類型的n個數據元素的有限序列,其中n為表長,n=0是為一個空表。除第一個元素外,每一個元素有且僅有一個直接前驅,除最后一個元素外,每一個元素有且僅有一個直接后驅。
順序表
線性表的順序存儲稱為順序表,是用一組地址連續的存儲單元一次存儲線性表中的數據結構,從而使得邏輯上相鄰的兩個元素在物理位置上也相鄰。
線性表的位序是從1開始的,而數組元素的下標從0開始。
1.插入操作
最好情況:表尾插入,時間復雜度O(1)
最壞情況:表頭插入,時間復雜度O(n)
平均情況:n/2
平均時間復雜度:O(n)
2.刪除操作
最好情況:刪除表尾元素,時間復雜度O(1)
最壞情況:刪除表頭元素,時間復雜度O(n)
平均情況:(n-1)/2
平均時間復雜度:O(n)
順序表插入和刪除的時間主要耗費在移動元素上,而移動元素的個數取決于插入刪除元素的位置。
3.按值查找(順序查找)
最好情況:查找的元素在表頭,時間復雜度O(1)
最壞情況:查找的元素在表尾或不存在,時間復雜度O(n)
平均情況:(n+1)/2
平均時間復雜度:O(n)
二、單鏈表
線性表的鏈式存儲又稱單鏈表,指通過一組任意的存儲單元來存儲線性表中的數據元素。對每個鏈表結點,除存放元素自身信息外,還需要存放一個指向其后繼節點的指針。
利用單鏈表可以解決順序表需要大量連續存儲單元的缺點,但單鏈表附加指針域,存在浪費空間的缺點。由于單鏈表的元素離散地分布在存儲空間中,所以單鏈表是非隨機存取的存儲結構。
如果要訪問某個結點的前去前驅結點,只能從頭開始遍歷。
頭節點:在單鏈表的第一個結點前附加一個結點。頭結點可以不設任何信息,也可以記錄表長等信息。引入頭結點可以帶來兩個優點:
1. 頭插法
將新結點插入當前鏈表的表頭,即頭結點之后。
讀入數據的順序和生成鏈表中的元素順序是相反的,總時間復雜度為O(n)
2. 尾插法
增加一個尾指針,使其始終指向當前鏈表的尾結點。可使導入數據和鏈表元素的順序一致,總時間復雜度為O(n)。
3. 按序號查找
時間復雜度O(n)
4. 按值查找
時間復雜度O(n)
5. 插入結點
插入結點的代碼片段如下
p = getElem(L, i-1); // 移動到插入位置前一個結點 s->next = p->next; p->next = s;算法時間開銷主要在于查找第i-1個元素,時間復雜度為O(n);如果在給定結點后插入,時間復雜度僅為O(1)。
6. 刪除結點
代碼片段如下
p = getElem(L, i-1); q = p->next; p->next = q->next; free(q); // 第二、三步順序不能顛倒該算法的時間復雜度也耗費找查找操作上,時間復雜度為O(n)。
7. 求表長
時間復雜度O(n)
三、 雙鏈表
雙鏈表結點有兩個指針,分別指向其前驅結點和后繼結點。
1. 插入
在p所指結點之后插入*s
s->next = p->next; p->next->prior = s; s->prior = p; p->next = s; /// 第一、二步必須在第四步之前2. 刪除
在p后刪除q
p->next = q->next; q->next->prior = p; free(q);四、循環鏈表
將單鏈表最后一個結點的指針改為指向頭結點,形成循環單鏈表。判空條件是頭結點的指針是否指向自身。
循環單鏈表可以從表中任意一個結點開始遍歷整個鏈表。
有時單鏈表常用操作是在表頭和表尾進行的,此時不設頭指針而僅設尾指針。
五、靜態鏈表
借助數組來描述線性表的鏈式結構,結點也有數據域和指針域。與鏈表的指針不同,靜態鏈表的指針是結點的相對地址(數組下標),又稱游標。
靜態鏈表需要預先分配一塊連續的內存空間。
六、順序表和鏈表的比較
| 存取(讀寫)方式 | 既可以順序存取,也可以隨機存取 | 只能從表頭順序存取元素 |
| 邏輯結構與物理結構 | 邏輯上相鄰的元素,對應的物理存儲位置也相鄰 | 邏輯上相鄰的元素,物理存儲位置不一定相鄰,其對應的邏輯關系通過指針鏈接來表示 |
| 按值查找 | 順序表有序時,可采用折半查找,時間復雜度為O(log2n)O(log_2n)O(log2?n),若無序,時間復雜度為O(n) | 時間復雜度為O(n) |
| 按序號查找 | 順序表支持隨機訪問,時間復雜度僅為O(1) | 時間復雜度為O(n) |
| 插入、刪除 | 平均需要移動半個表長的元素 | 只需修改相關結點的指針域 |
| 空間分配 | 在靜態存儲分配情形,一旦存儲空間裝滿就不能擴充,加入新元素會導致內存溢出,因此需要預先分配足夠大的空間。但預先分配過大,會導致后部空間大量閑置;動態存儲分配雖然存儲空間可以擴充,但需要移動大量元素,導致操作效率降低,若內存沒有更大塊的連續存儲空間,則會導致分配失敗。 | 鏈式存儲的結點空間只需在需要是申請,只要內存有空間就可以分配,操作靈活、高效。 |
如何選取存儲結構:
- 基于存儲考慮:難以估計線性表的長度或存儲規模時,不宜采用順序表;鏈表實現不用估計存儲規模,但鏈表的存儲密度較低。
- 基于運算考慮:如經常做的運算時按序號訪問元素,則順序表優于鏈表;如經常進行插入、刪除操作,鏈表較優。
- 基于環境考慮:任何高級語言都有數組類型,順序表較容易實現;鏈表的操作是基于指針的。
通常,較穩定的線性表選擇順序存儲,而頻繁進行插入、刪除操作的線性表(動態性強)宜選擇鏈式存儲。
七、特殊矩陣的壓縮儲存
數組的定義
數組是由n(n ≥\ge≥ 1)個相同類型的數據元素構成的有序序列。
每個元素在線性關系中的序號稱為該元素的下標,下標的取值范圍稱為數組的維界。
數組是線性表的推廣:一維數組可視為一個線性表,二維數組可視為其元素也是定長線性表的線性表。
數組一旦被定義。其維數和維界就不再改變,因此除初始化和銷毀外,數組只有存取元素和修改元素的操作。
數組的存儲結構
對于多維數組,有按行優先和按列優先兩種映射方法。
設二維數組Ah1×h2A_{h_1\times h_2}Ah1?×h2??的行下標和列下標范圍分別為[l1,h1],[l2,h2][l_1,h_1],[l_2, h_2][l1?,h1?],[l2?,h2?]。
其按行優先存儲時,LOC(ai,j)=LOC(al1,l2)+[(i?l1)×(h2?l2+1)+(j?l2)]×LLOC(a_{i,j})=LOC(a_{l_1,l_2})+[(i-l_1)\times (h_2-l_2+ 1)+(j-l_2)]\times LLOC(ai,j?)=LOC(al1?,l2??)+[(i?l1?)×(h2??l2?+1)+(j?l2?)]×L其按列優先存儲時,LOC(ai,j)=LOC(al1,l2)+[(j?l2)×(h1?l1+1)+(i?l1)]×LLOC(a_{i,j})=LOC(a_{l_1,l_2})+[(j-l_2)\times (h_1-l_1+1)+(i-l_1)]\times LLOC(ai,j?)=LOC(al1?,l2??)+[(j?l2?)×(h1??l1?+1)+(i?l1?)]×L
矩陣的壓縮存儲
為多個值相同的元素只分配一個存儲空間,對零元素不分配存儲空間,目的是節省空間。
1. 對稱矩陣
將對稱矩陣A[1…n][1…n]存放在一維數組B[n(n+1/2)]中,只存放下三角部分的元素。
2. 三角矩陣
下三角矩陣中,上三角區的所有元素均為同一常量,其儲存思想與對稱矩陣類似,不同之處在于儲存完下三角區和主對角線上的元素后,在儲存上三角取的常量一次。
943 2019年選擇第9題默認矩陣下標從0開始
3. 三對稱矩陣(帶狀矩陣)
三對角線上的元素ai,ja_{i,j}ai,j?在一維數組中的下標為k=2+3(i-1)+(j-i+1)-1=2i+j-1(數組和元素下標均從0開始)。
4. 稀疏矩陣
矩陣中非零元素個數遠小于矩陣元素的矩陣。
通常將非零元素及其相應的行和列構成一個三元組,然后按照一定規則儲存這些三元組。
稀疏矩陣壓縮存儲后便失去了隨機存儲的特性。
八、廣義表
c++中union關鍵字詳見
廣義表的定義
廣義表的操作
getHead():獲得廣義表的第一個元素;
getTail():獲得以廣義表出第一個元素外的其余元素構成的廣義表。
如:A=(a), B=(b,c,d),C=(()),那么
getHead(A)=a, getHead(B)=b, getHead(C)=()
getTail(B)=(), getTail(B)=(c,d), getTail(C)=()
總結
以上是生活随笔為你收集整理的王道408数据结构——第二章 线性表的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 王道408数据结构——第一章 绪论
- 下一篇: 王道408数据结构——第三章 栈和队列