一、解決問題的前提是定義清楚問題
通過對一些模糊需求進行假設,來限定要解決問題的范圍
根據某個值查找數據,比如 select * from use where id=1234;
根據區間值來查詢某些數據比如 select * from use where id > 1234 and id < 2345
性能方面的需求,我們主要考察時間和空間兩方面,也就是執行效率和存儲空間
執行效率:我么你希望通過索引,查詢數據的效率盡可能的高;
存儲空間方面:我們希望索引不需要消耗太多的內存空間
二、嘗試用學過的數據結構解決這個問題
支持快速查詢、插入等操作的動態數據結構,我們已經學過散列表、平衡二叉樹、跳表
這樣看來,跳表是可以解決這個問題,實際上,數據庫索引所用到的數據結構跟跳表非常相似,叫做B+樹
它是通過跳表演化雇來的,而非跳表
三、改造二叉查找樹來解決這個問題
1、實現代碼
/** * 這是 B+ 樹非葉子節點的定義。 * * 假設 keywords=[3, 5, 8, 10] * 4 個鍵值將數據分為 5 個區間:(-INF,3), [3,5), [5,8), [8,10), [10,INF) * 5 個區間分別對應:children[0]...children[4] * * m 值是事先計算得到的,計算的依據是讓所有信息的大小正好等於頁的大小: * PAGE_SIZE = (m-1)*4[keywordss 大小]+m*8[children 大小] */ public class BPlusTreeNode { public static int m = 5; // 5 叉樹 public int[] keywords = new int[m-1]; // 鍵值,用來划分數據區間 public BPlusTreeNode[] children = new BPlusTreeNode[m];// 保存子節點指針 } /** * 這是 B+ 樹中葉子節點的定義。 * * B+ 樹中的葉子節點跟內部結點是不一樣的, * 葉子節點存儲的是值,而非區間。 * 這個定義里,每個葉子節點存儲 3 個數據行的鍵值及地址信息。 * * k 值是事先計算得到的,計算的依據是讓所有信息的大小正好等於頁的大小: * PAGE_SIZE = k*4[keyw.. 大小]+k*8[dataAd.. 大小]+8[prev 大小]+8[next 大小] */ public class BPlusTreeLeafNode { public static int k = 3; public int[] keywords = new int[k]; // 數據的鍵值 public long[] dataAddress = new long[k]; // 數據地址 public BPlusTreeLeafNode prev; // 這個結點在鏈表中的前驅結點 public BPlusTreeLeafNode next; // 這個結點在鏈表中的后繼結點 }
2、實現步驟
3、實現思路
分裂合並
4、刪除操作的例子
四、總結引申
1、每個節點中子節點的個數不能超過m,也不能小於m/2
2、根節點的子節點個數不可超過m/2,這是一個例外
3、M叉樹只存儲索引,並不真正存儲數據,這個有點類似跳表
4、通過鏈表將葉子階段串聯在一次,這樣可以方便區間查詢
5、一般情況下,根節點會被存儲在內存中,其他節點存儲在磁盤中