因為之前就復習完數據結構了,所以為了保持記憶,整理了一份復習綱要,復習的時候可以看著綱要想具體內容。
樹
-
樹的基本概念
- 樹是遞歸的定義
- 有序樹(如二叉樹)
- 樹的高度(葉結點高度為1)
- 樹的性質(王道補充)
- 高度為h的m叉樹至多結點數: (m^h - 1)/(m-1),等比數列求和公式
- 具有n個結點的m叉樹的最小高度:↑logm(n(m-1)+1) ↑(↑↑為向上取整)
- 含有n個結點的m叉樹的最小高度和最大高度,通過不等式,等比數列求和公式,同時取對數方法計算(重點)
-
二叉樹
- 定義,有序樹,子樹次序不能顛倒,完全二叉樹,滿二叉樹
- 性質
- 第i層最多結點數
- 深度為k的二叉樹最少和最多結點數
- N = N0 + N1 + N2 && E = 2N2 + N1 = N - 1 —> N0 = N2 + 1
- 可適用于m叉樹 N = N0 + N1 + N2 +….+ Nm && N = mNm + (m-1)Nm-1 + …. + 2N2 + N1
- 注意n1奇偶不同的情況
- n個結點的完全二叉樹的深度
-
二叉樹的存儲表示
- 數組存儲
- 鏈表存儲
- n個結點的二叉鏈表中有n+1個空鏈指針域,N空 = 2N0 + N1 = 2(N2+1) + N1 = N + 1,多叉鏈表同理
- 靜態鏈表結構,數組元素四個區域:data、parent、leftchild、rightchild
- 廣義表表示建立二叉樹(P197),二叉樹高度與廣義表深度及括號嵌套數的關系
-
二叉樹遍歷及其應用
-
遍歷的遞歸算法(O(n))
- 前序
- 創建二叉樹
- 判斷兩棵樹是否相等
- 以廣義表輸出二叉樹
- 中序
- 后序(從『先計算左右子樹,再比較兩者大小』方面理解)
- 樹高度、深度
- 結點個數(左子樹的結點個數+右字數的結點個數+1)
- 前序
-
遍歷的非遞歸算法
- 前序、中序、后序(設置tag表示左右方向)、層次遍歷(隊列)
-
二叉樹的計數
- 前序(后序)+ 中序
- 層次 + 中序
- 前序1,2,3.....n,可以確定多少棵二叉樹,與進棧順序一定,出棧方式的數量相同
-
-
線索二叉樹
- 中序線索二叉樹
- 建立、遍歷
- 中序序列的First()、Next()、Last()、Prior()函數
- 實現前序、后序遍歷
- 插入與刪除
- 前序、后序線索化二叉樹
- 后序線索樹遍歷時仍然需要棧的支持
- 中序線索二叉樹
-
樹與森林
- 樹的存儲表示
- 廣義表、父指針、子女鏈表、子女-兄弟鏈表
- 森林、二叉樹的轉換
- 樹的存儲表示
-
樹與森林的遍歷及其應用
- 樹的深度優先遍歷
- 先跟、后跟
- 森林的深度優先遍歷
- 先跟(前序)、后跟(中序)
- 樹和森林的廣度優先遍歷
- 樹的深度優先遍歷
-
堆
- 最小堆、最大堆
- 堆的建立、插入、刪除
- siftDown()、siftUp()
-
Huffman樹
- 建立
- 帶權路徑長度
- 最優判定樹
- Huffman編碼
- 前綴編碼(無前綴)
-
綜合應用:(遞歸算法是重點,除非特殊說明否則都是二叉鏈表存儲結構)
- 遞歸
- 返回二叉樹中值為x的結點所在的層號
- 從二叉樹中查找值為x的結點,返回指向其父結點的指針
- 交換左右子樹,返回新的根結點
- 原來根的基礎上交換左右子樹(前序后序都可)
- 刪除二叉樹中值為x的結點(注意在遞歸狀態下刪除結點,無需手動改變指針鏈接)
- 將此題與鏈表遞歸刪除結點對比(王道P42),刪除結點無需手動指定鏈接,L=L->next 在遞歸中相當于L->next = L->next->next,就完成了刪除結點
- 計算二叉樹雙分支結點個數(注意遞歸模型的統一性)
- 計算二叉樹葉節點的帶權路徑長度之和(前序或層次)
- 非遞歸
- 求樹的高度
- 非遞歸后序遍歷
- 打印值為x的結點的所有祖先
- 找到p和q的最近公共祖先結點
- 遞歸
散列表
- 概念
- 沖突
- 散列函數可能會把兩個或兩個以上的不同關鍵字映射到同一地址的情況
- 沖突只是一種情況,并不代表結果沖突,沖突是無法避免的,所以需要設計好的散列函數
- 堆積、聚集、同義詞、關鍵碼、裝載因子,ASL(succ)、ASL(unsucc)
- 沖突
- 散列函數
- 除留余數法
- hash(key) = key % p(p<=m),p是不大于m的最大質數,m是散列表允許的地址數
- 數字分析法、平方取中法、折疊法
- 其他方法,注意返回值要一對一確定,否則無法查找,所以不能random
- 除留余數法
- 處理沖突方法
- 閉散列(開放定址)法(只能邏輯刪除元素)
- 線性探查法(線性探測再散列)
- 二次探查法
- 散列表大小必須是滿足4k+3的質數
- 至少能探測到一半單元,裝載因子α <= 0.5時,新表項一定能夠插入,且任意一個位置不會被探查兩次
- 雙散列法
- j = H0 = Hash(key),p = ReHash(key),j = (j+p) % m,其中p是小于且與m互質的正整數
- 開散列(閉合定址/拉鏈)法
- 計算ASL(succ)和ASL(unsucc)
- 注意計算ASL(unsucc)時,分母是可能取的散列地址數,如除留余數法%后面的數,跟表長無關(若表長是質數則與散列地址數相同)
- 閉散列(開放定址)法(只能邏輯刪除元素)
- 散列表分析
- 開散列優于閉散列,除留余數法優于其他散列函數
- 搜索性能直接依賴于裝載因子,不直接依賴于n或m
搜索結構
- 靜態搜索結構
- 順序搜索
- 監視哨
- 基于有序順序表的順序搜索和折半搜索
- 順序搜索
- ASLsucc = (n+1)/2
- ASLunsucc = (1+2+….+n+n)/(n+1) = n/2 + n/(n+1)
- 折半搜索
- 代碼及拓展代碼
- n個關鍵碼有序順序表,最多比較次數
- ASLsucc = O(log2n)
- 順序搜索
- 順序搜索
- 二叉搜索樹(二叉排序樹)
- 常用來表示字典結構,主要用于內存中目錄的編制,需要快速插入搜索刪除
- 搜索、插入、刪除,O(log2n)
- n個關鍵碼的集合,有n!種不同排序,可構成的二叉搜索樹有多少種
- ASLsucc、ASLunsucc(等概率和不等概率)
- AVL樹
- 平衡因子
- 平衡化旋轉(代碼)
- 插入、刪除
- 性能分析,斐波那契數
- 伸展樹
- 紅黑樹
圖
- 概念
- 圖不可以是空圖,至少有一個頂點
- 完全圖
- 無向圖,n(n+1)/2邊
- 有向圖,n(n+1)邊
- 路徑
- 一系列頂點序列來定義
- 簡單路徑
- 路徑上各頂點不互相重復
- 連通圖與連通分量
- 無向圖中,v1到v2有路徑,則v1與v2連通,圖中任意一對頂點連通,此圖為連通圖
- 非連通圖的極大連通子圖叫連通分量
- 強連通圖與強連通分量
- 有向圖中,每一對頂點vi到vj有路徑,vj到vi也有路徑,此圖是強連通圖
- 非強連通圖的極大強連通子圖叫強連通分量
- 設圖G的鄰接矩陣為A,An的元素An[i][j]等于由頂點i到頂點j長度為n的路徑的數目
- 存儲結構
- 鄰接矩陣
- 鄰接表
- 有向圖、無向圖的度和邊鏈表中邊結點數目的關系
- 遍歷
- DFS
- 深度優先生成樹
- 判斷有無回路
- BFS
- 廣度優先生成樹
- 先訪問,再如隊列,否則會出現重復入隊現象
- 主調用函數中對BFS/DFS的調用次數是該圖的連通分量的數目
- 基于鄰接矩陣遍歷的DFS/BFS序列唯一,鄰接表則不唯一
- 時間復雜度
- 鄰接表 O(n+e)
- 鄰接矩陣 O(n^2)
- 應用
- 找極大連通子圖
- 消除圖中回路
- 找出關節點等應用
- DFS
- 最小生成樹MST
- MST不一定唯一,MST權值一定唯一
- prime
- 時間復雜度
- 王道:O(n^2)
- 教材:O(elog2e),使用了最小堆
- 適用于邊稠密圖
- 時間復雜度
- kruscal
- 最小堆
- 并查集
- 時間復雜度:
- O(n)+O(建堆e)
- 建堆時間復雜度是O(n)還是O(nlog2n)?王道和教材不一致
- 適用于邊稀疏,頂點較多的圖
- 最短路徑
- Dijkstra
- 非負權值單源最短路徑,求某一點到其他點的最短路徑
- O(n2),若求所有源最短路徑,則O(n3)
- Floyd
- 所有頂點之間的最短路徑
- 允許有帶負權值的邊,但不許有包含負權值邊組成的回路
- O(n^3)
- Bellman-Ford
- 任意權值的單源最短路徑
- Bellman-Ford方程為距離向量路由選擇算法給出了基本思想
- BFS廣度優先搜索算法
- 非帶權圖單源最短路徑
- Dijkstra
- AOV網(activities on verticles)
- 拓撲排序
- 檢測有向環
- 拓撲排序算法,O(n+e)
- 用DFS實現拓撲排序,退出遞歸時訪問結點,得到逆拓撲有序序列。要求沒有有向回路
- 拓撲排序
- AOE網(activities on edges)
- 關鍵路徑
- 檢測是否有從開始頂點無法到達的頂點
- 關鍵路徑
- 綜合應用
- 將無環有向圖的頂點號重新安排使得該圖的鄰接矩陣中所有的1集中在對角線以上
- 拓撲排序
- 出度最大的編號為1
- Dijkstra和prime算法比較
- 判斷有向圖中是否存在回路
- 拓撲排序
- DFS
- 無向圖:遇到回邊
- 有向圖:DFS(v)結束之前出現一條u道v的回邊,且u在生成樹上是v的子孫
- 『破圈法』求解最小生成樹
- 判斷無向圖是否為一棵樹
- DFS非遞歸算法
- 分別采用DFS、BFS判斷有向圖鄰接表中是否存在vi到vj的路徑
- 鄰接表,輸出vi到vj的所有簡單路徑
- 計算圖中各頂點的度
- 計算某頂點的入度、出度
- 刪除有向圖中以某頂點為弧頭(尾)的有向邊
- 根據鄰接矩陣轉換鄰接表、根據鄰接表轉換為鄰接矩陣
- 根據鄰接表建立逆鄰接表(邊鏈表中是弧指向該頂點的頂點)
- 將無環有向圖的頂點號重新安排使得該圖的鄰接矩陣中所有的1集中在對角線以上
內部排序
- 排序碼、算法穩定性、內部排序外部排序
- 對任意n個關鍵字排序的比較次數至少為↑log2(n!)↑
- 插入排序(左邊是排好序的序列,右邊是未排序序列,右邊第一個拿出來插入到左邊)
- 初始排列基本有序的序列,效率很高
- 直接插入排序(從后向前比較再插入)
- 折半插入排序(注意是從high+1的位置(包括)往后移空出插入位置)
- 比較次數為O(nlog2n),但交換次數仍然是O(n2),所以時間復雜度仍然是O(n2)
- 希爾排序
- 增量gap = ↑n/3↑ + 1 (教材)
- 冒泡排序(從后往前冒泡)
- 快速排序(先移動high)
- 最通用,平均最快
- 分治思想
- 每一次選出一個基準值,小于基準的在左邊,大于基準的在右邊,基準在中間
- 每次的樞軸都把表分為長度相近的兩個子表時,速度最快
- 改進算法
- 序列長度M取值為5-25時,直接插入比快排快10%,因此小于M時直接用插入排序
- 劃分過程中對小規模子序列不排序,最后進行一遍直接插入排序
- 采用左端點,右端點,中間端點,三者取中間值作為基準,并交換到右端點
- 將2.3結合,可將遞歸實現的快排效率提高20%-25%
- 選擇排序
- 直接選擇排序
- 每趟從未排序序列中選擇一個最小的與未排序序列第一個位置進行交換
- 移動次數O(n),比較次數O(n2),時間復雜度O(n2)
- 錦標賽排序(勝者樹)
- 直接選擇排序
- 堆排序
- 每趟從小到大排序,建立最大堆,將最大的取出來交換到排序數組最后
- 計算插入、刪除元素的比較次數時,注意左右子樹可能會先比較
- 歸并排序
- 分治法
- 改進算法
- 歸并趟數 m = logkN 其中k為路數 k路歸并
- 分配排序
- 桶式排序
- 基數排序
- LSD 最低位優先
- MSD 最高位優先
- 空間O(n),時間O(d(n+r)) ,d為分配和收集的趟數,r為隊列數
- 算法分析
- 按時間復雜度:
- O(n^2):直接插入、冒泡、直接選擇、折半插入
- O(nlog2n):快排、堆排、歸并
- O(n^1.25):希爾
- 按內存(空間)復雜度:
- O(1):直接插入、冒泡、直接選擇、堆排、希爾
- O(log2n):快排
- O(n):歸并
- 按規模:
- 規模很小(n<=25):直接插入、簡單選擇排序(記錄本身信息量較大,移動要少)
- 中等規模(n<=1000): 希爾
- 規模不是很大(n<10k):直接插入、冒泡、直接選擇比較主要
- 規模很大:快排、堆排、歸并
- 規模很大,記錄關鍵字位數較少且可分解:基數排序
- 基本有序:插入、冒泡
- 記錄本身信息量較大時:用鏈表做存儲結構,避免耗費大量時間移動記錄
- 按穩定性:
- 穩定:直接插入、冒泡、歸并、折半插入、基數排序
- 不穩定:快排、堆排、希爾、簡單(直接)選擇
- 按最好最壞情況:
- 冒泡:改進算法最好只需要一趟起泡過程,n-1次比較操作
- 直接插入:最好只要n-1次比較操作O(n),平均和最差情況下,比較和交換都是O(n^2)
- 直接選擇:比較次數總是O(n^2),但移動次數最好情況一次也不移動
- 快排:
- 時間復雜度:元素有序時會退化,時間O(n^2),空間O(n),但改進算法可避免最壞情況發生
- 空間復雜度:最好為log2(n+1),最壞為O(n),平均O(log2n)
- 希爾:最壞O(n^2)
- 歸并:平均和最壞的空間O(n)
- 比較:
- 堆排不太可能提供比快排更好的平均性能
- 歸并排序跟堆排和快排相比,穩定
- 基數排序的線性時間開銷實際并不比快排小多少,應用不廣泛,主要適用于硬件環境,編程環境和輸入與元素序列滿足一定條件時,且不能處理float,double類實數
- 只需得到前k小個元素的順序排列可采用的排序算法有冒泡、堆排、簡單選擇,當k>=5時,堆排最優,4n+klog2n
- 按時間復雜度:
- 算法代碼應用
- 快排劃分的兩種算法
- 從第二個元素開始尋找小于基準的元素,找到后交換到前面 swap( A[++i] , A[j] ),重復
- 從后面開始找到<基準的元素j,覆蓋從前面找到>基準的元素i,i++,覆蓋j,j++,覆蓋i,重復
- 使用快排分治思想,在數組中找到第k小的元素
- 用k跟基準比,小的在左邊,大的在右邊,遞歸劃分繼續查找
- 荷蘭國旗問題,將僅有紅白藍三種顏色的序列,按紅白藍順序排好(將負數排在非負數前面同理,快排劃分思想)
- j為工作指針,i以前的元素為紅色,k以后的元素為藍色,i++,k—
- 鏈表的選擇排序算法,每次從first鏈上摘下最大的結點current鏈入head之后,算法結束前將head刪除
- 快排劃分的兩種算法
外部排序
- 基本過程
- 建立為外排序所用的內存緩沖區,根據大小將輸入文件劃分為若干段,對各段進行內排序(如堆排),經過排序的段叫初始歸并段,將他們寫入外存
- 把第一階段生成的初始歸并段加以歸并,一趟趟擴大歸并段和減少歸并段個數,直至最后歸并成一個大有序文件
- 輸入緩沖區、輸出緩沖區
- 總歸并趟數 == 歸并樹的高度減一 == ↑log2m↑ ,其中m為初始歸并段個數
- S=↑logkm↑ 增大歸并路數k,或減少初始歸并段個數m,都能減少歸并趟數s,以減少磁盤I/O數,提高排序速度
- 但是k增大時,相應需要增加輸入緩沖區個數,k值過大時,外存I/O仍會增加,需要綜合考慮
- k路平衡歸并
- k路平衡歸并時,m個初始歸并段,則歸并樹有 ↑logkm↑+1 層,需要歸并 ↑logkm↑ 趟
- 增大歸并路樹k,會是內部歸并的時間增大
- 敗者樹
- 『敗者樹』從k個歸并段中選最小者,排序碼比較次數與k無關,總的內部歸并時間不會隨k的增大而增大
- 完全二叉樹,葉節點存放各歸并段在歸并過程中當前參加比較的記錄,非葉結點記憶其子女中記錄排序碼小的結點(敗者),根結點記憶樹中當前的最小記錄
- 冠軍送入結果歸并段,冠軍所在歸并段的下一個記錄替補上來,與其父節點記憶的敗者進行比較,敗者進行記憶,勝者與更上次父節點的敗者繼續比較,直到比出冠軍
- 敗者樹高度↑log2k↑+1,包括冠軍結點
- 每次調整找下一個最小記錄時,最多做↑log2k↑次排序碼比較
- 初始歸并段的生成(選擇-置換)
- 使用敗者樹生成初始歸并段,同樣內存下,生成平均比原來等長情況下大一倍的初始歸并段,從而減少m,降低s
- 從敗者樹中選一個最小的,然后補上記錄,再輸出最小的,注意只有比當前歸并段最大值大的才能輸出到歸并段,否則放到下一個歸并段中
- n個記錄,生成初始歸并段的時間開銷O(nlog2k),每輸出一個記錄,對敗者樹進行調整需要O(log2k)
- 最佳歸并樹
- 只有度為0和度為k的結點的正則k叉樹
- 葉節點代表參加歸并的各初始歸并段,葉節點權值為該初始歸并段的記錄個數,葉節點到根結點的路徑長度表示在歸并過程中的歸并趟數,歸并樹的帶權路徑長度WPL(葉節點)即為歸并過程中總的讀記錄樹,總讀寫記錄次數為2*WPL
- Huffman樹思想
- 補空歸并段,計算補的度為0的結點個數,正則k叉樹 n0 = (k-1)nk + 1,其中n0就是記錄數n(Huffman樹的key都是葉節點)
- 若(n0-1)%(k-1) = 0,則說明這n0個葉節點(即初始歸并段)正好可構造k叉歸并樹,不需要空歸并段
- 若(n0-1)%(k-1) = m ≠ 0,則說明剩m個記錄加不到樹中。此時在記錄中增加k-m-1個空記錄(0)即可
- 計算應用
- 假設文件4500個記錄,磁盤上每個頁塊可放75個記錄,計算機中用于排序的內存區可容納450個記錄,(1)可建立多少歸并段?每個歸并段有多少記錄?存放于多少頁塊中?(2)應采用幾路歸并?寫出歸并過程及每趟需要讀寫磁盤的頁塊數
- (1)可建立初始歸并段有4500/450=10個。每個初始歸并段中有450個記錄,存于450/75=6個頁塊中
- (2)內存區可容納6個頁塊,可建立6個緩沖區,其中5個用于輸入,1個用于輸出,采用5路歸并。做了兩趟歸并,每趟需要讀60個磁盤頁塊,寫60個磁盤頁塊
- 假設文件4500個記錄,磁盤上每個頁塊可放75個記錄,計算機中用于排序的內存區可容納450個記錄,(1)可建立多少歸并段?每個歸并段有多少記錄?存放于多少頁塊中?(2)應采用幾路歸并?寫出歸并過程及每趟需要讀寫磁盤的頁塊數
多級索引結構
- 動態的m路搜索樹
- 每個結點最多m棵子樹,最多有m-1個關鍵碼
- 最少有0棵子樹,1個關鍵碼
- AVL樹是2路搜索樹
- m路搜索樹,高度h,最大結點數(m^h-1)/(m-1) ,注意是結點數,一個結點里有m-1個關鍵碼,所以相乘,最大關鍵碼數為(m^h-1)
- 最大結點數時的結點結構與滿m叉樹結構一樣,所以結點數都是上面的公式,相同
- m路搜索樹,高度h,最小結點數為h
- h <= 關鍵碼個數 <= (m^h-1) —> n個關鍵碼的m路搜索樹高度h: logm(n+1) <= h <= n
- 提高搜索樹的路數m,可以改善樹的搜索性能。對于給定的關鍵碼數n,如果搜索樹是平衡的,可以使m路搜索樹的性能接近最佳(B樹)
- B樹(繼承自m路搜索樹)
- B樹常存儲在磁盤上,在B樹種尋找結點是在磁盤上進行的,在結點內找關鍵字是在內存中進行的。找到目標結點后,先將結點中的信息讀入內存,再用順序或折半查找關鍵字
- B樹結構
n
P0
K1
P1
K2
P2
……
Kn
Pn
K為關鍵字n個,P為指向子樹根結點(也即磁盤地址)的指針n+1個(可出計算題) - m階B樹的性質(調整B樹時看的就是這三點性質!)
- 根結點至少2個子女
- 除根結點以外的所有結點(不包括失敗結點)至少有↑m/2↑個子女,即該結點至少有↑m/2↑-1個關鍵字
- 所有的失敗結點都位于同一層
- B樹的搜索過程是一個在結點內搜索和循某一條路徑向下一層搜索交替進行的過程,因此B樹的搜索時間與B樹的階數m和高度h直接相關,需加以權衡
- 搜索成功所需時間取決于關鍵碼所在層次,搜索不成功所需時間取決于樹的高度
- B樹高度時不包括失敗結點
- 第二層至少兩個結點,每個結點至少有↑m/2↑個子女,因此第三層至少2↑m/2↑個子女
- 第h層至少有2↑m/2↑^(h-2)
- 位于第h+1層的失敗結點至少有2↑m/2↑^(h-1)個結點 == 樹中所有關鍵碼的數量+1
- 樹中關鍵碼有N個,則失敗結點個數為N+1 >= 2↑m/2↑^(h-1) —> h <=↓ log↑m/2↑((N+1)/2) ↓+ 1,(h不包括失敗結點)
- B樹最高h =↓ log↑m/2↑((N+1)/2) ↓+ 1,最低h = ↑ logm(n+1)↑
- 由公式看到,增大m可以降低樹的高度,從而減少結點讀入結點的次數,減少磁盤I/O次數,但是當m超過可分配內存時,結點不能一次讀入內存,反而增加了讀盤次數
- B樹的插入
- 每個非失敗結點的關鍵碼個數在 ↑m/2↑-1 和 m-1 之間(這樣其子女就有↑m/2↑到m個,滿足B樹性質)
- 插入是在某個葉結點(第h層)開始,插入后關鍵碼個數超過m-1,則需要分裂,將中間結點K↑m/2↑插入父結點,繼續向上處理
- 高度為h的B樹,自頂向下搜索葉結點的過程需要h次讀盤,最壞結果需要自底向上分裂結點,分裂非根結點向磁盤寫出2個結點,分裂根結點寫出三個結點,完成一次插入需要讀寫磁盤次數為 h+2(h-1)+3 = 3h+1
- 當m較大時,訪問磁盤平均次數為h+1
- B樹的刪除
- 所刪除關鍵字k不在終端結點中時
- k的左子樹滿足條件,前驅值k’取代k,再遞歸刪除k’;若左子樹不滿足,右子樹滿足,則用右子樹后繼來取代
- 前后子樹均不滿足條件,合并兩個子結點,直接刪除k
- 所刪除關鍵字k在終端結點中時
- 直接刪
- 不能直接刪,兄弟夠借,父親下來,兄弟上位
- 兄弟不夠借,刪除k后,父親下來跟兄弟合并,再看父親
- 最壞情況,讀寫磁盤 3h-2次,釋放h個結點
- 所刪除關鍵字k不在終端結點中時
- B+樹
- 實現文件索引結構方面比B樹使用更普遍
- 所有關鍵碼都在葉結點中,上層非葉結點的關鍵碼是其字數中最小(大)關鍵碼的復寫
- 葉結點包含了全部關鍵碼及指向相應記錄地址的指針,且葉結點本身按關鍵碼從小到大順序連接
- 『最大關鍵碼復寫』原則定義B+樹
- 每個結點最多有m棵子樹
- 根結點至少有一個子樹,其他結點至少↑m/2↑個子樹
- 所有葉結點再同一層,按從小大順序存放全部關鍵碼,各個葉結點順序鏈接
- 有n個子樹的結點有n個關鍵碼
- 非葉結點可以看成葉結點的索引
- 葉結點中存放的是對實際數據記錄的索引,每個索引項給出數據記錄的關鍵碼及實際存儲地址
- B+樹有兩個頭指針,一個紙箱B+樹的根結點,一個指向關鍵碼最小的葉結點,因此可對B+樹進行兩種搜索:
- 循葉結點拉起的鏈表順序搜索
- 從根結點開始,自頂向下隨機搜索,每次搜索都是一條根到葉結點的路徑
- B+樹的插入
- 僅在葉結點上進行
- 插入后葉結點中的關鍵碼個數n>m時,將葉結點分為兩個分別包含↑(m+1)/2↑ 和 ↓(m+1)/2↓個關鍵碼的結點
- 他們的父結點應同時包含這兩個結點的最大關鍵碼和地址
- 非葉結點中關鍵碼的插入
- 葉結點分裂后,其父節點(非葉結點)被動插入,最終可能樹會增加一層
- 插入高度h的B+樹需要3h+1此磁盤訪問,平均大約h+1次磁盤訪問,與B樹類似
- 僅在葉結點上進行
- B+樹的刪除
- 僅在葉結點上進行
- 刪除后該結點關鍵碼個數不小于↑m/2↑-1(或者說子樹棵樹小于↑m/2↑時)時,無需調整上層索引(即使刪了某結點的最大關鍵碼,其在父結點的復寫也不用動,因為索引只起引導搜索的分界作用)
- 小于↑m/2↑時,需要調整合并
- 可從右兄弟結點拉一個,然后修改父結點索引
- 右兄弟子樹棵樹也達到下限時,將右兄弟合并至被刪關鍵碼所在結點,父結點再根據情況與其兄父調整合并,最終可能樹會減少一層
- 計算應用
- 利用B樹做文件索引時,若假設磁盤頁塊的大小是4000字節,指示磁盤地址的指針需要5個字節,現有20 000 000個記錄構成的文件,每個記錄200字節,其中包含關鍵字5個字節。(1)在此采用B樹做索引的文件中,B樹的階樹應為多少?(2)嘉定文件數據部分未按關鍵字有序排列,則索引部分需要占用多少磁盤頁塊?
- (1):根據B樹概念,一個索引結點應適應操作系統過一次讀寫的物理記錄大小,其大小應取不超過但最接近一個磁盤頁塊的大小。假設B樹為m階,一個B數結點最多存放m-1個關鍵字(5字節)和對應的記錄地址(5個字節)、m個子樹指針(5個字節)、1個指示結點關鍵字個數的整數(2字節),則有(2(m-1)+m)5+2<=4000,m<=267
- (2):一個索引結點最多存放266個索引項,最少133個,全部有20 000 000個記錄,每個記錄200字節,每個頁塊則20個記錄,全部記錄分布在1 000 000個頁塊中,則最多占用1 000 000/133 = 7519個磁盤頁塊(也就是7519個索引結點)作為B樹索引,最少3760個。
- 利用B樹做文件索引時,若假設磁盤頁塊的大小是4000字節,指示磁盤地址的指針需要5個字節,現有20 000 000個記錄構成的文件,每個記錄200字節,其中包含關鍵字5個字節。(1)在此采用B樹做索引的文件中,B樹的階樹應為多少?(2)嘉定文件數據部分未按關鍵字有序排列,則索引部分需要占用多少磁盤頁塊?