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