寫代碼以前,再回顧一下B樹是什麼,知足什麼樣的規則html
用一張圖來幫助理解B樹(爲了方便理解,使用實際字母大小來排列)
數據庫
如上圖我要從上圖中找到E字母,查找流程以下函數
拿一個5階樹舉例指針
B樹相對於平衡二叉樹的不一樣是,每一個節點包含的關鍵字增多了,特別是在B樹應用到數據庫中的時候,數據庫充分利用了磁盤塊的原理(磁盤數據存儲是採用塊的形式存儲的,每一個塊的大小爲4K,每次IO進行數據讀取時,同一個磁盤塊的數據能夠一次性讀取出來)把節點大小限制和充分使用在磁盤快大小範圍;把樹的節點關鍵字增多後樹的層級比原來的二叉樹少了,減小數據查找的次數和複雜度code
講了許多,對於程序猿來講,仍是上代碼實際htm
public class BTree<K, V> where K : IComparable<K> { private class Node { public Node Parent { get; set; } public List<K> Keys { get; set; } public List<V> Values { get; set; } public List<Node> Children { get; set; } /// <summary> /// 向節點內部按照大小順序插入一個元素, /// </summary> /// <param name="key"></param> /// <param name="value"></param> public void Insert(K key, V value) { var result = false; for (var i = 0; i < Keys.Count; i++) { var compareValue = key.CompareTo(Keys[i]); if (compareValue < 0) { Keys.Insert(i, key); Values.Insert(i, value); result = true; break; } else if (compareValue == 0) { throw new Exception(); } } if (!result) { Keys.Add(key); Values.Add(value); } } public Node() { Keys = new List<K>(); Values = new List<V>(); Children = new List<Node>(); } } private int _level; //單個節點包含key值數量的最小值(除了根節點外) private int _minKeysCount; private Node _first; /// <summary> /// B樹初始化 /// </summary> /// <param name="level">表示單個節點包含的最大Key值數量</param> public BTree(int level) { _level = level; _minKeysCount = (int)(Math.Ceiling(_level / 2.0) - 1); } }
BTree中定義的_level表示樹的階數,_minKeysCount表示單個節點關鍵字最小數目
Node表示B樹中的一個節點,包含多個關鍵字和對應的Value值,還包含子節點的引用blog
public void Insert(K key, V value) { if (_first == null) { _first = new Node(); _first.Insert(key, value); } else { var current = _first; Insert(current, key, value); } } private void Insert(Node current, K key, V value) { //若是當前節點是葉子節點,則直接插入到葉子節點,再看是否葉子節點須要分裂 if (current.Children.Count == 0) { if (current.Keys.Count > _level) { return; } current.Insert(key, value); if (current.Keys.Count == _level) { Bubble(current); } } else { //若是當前節點不是葉子節點,找出大於當前Key值的最小key對應的索引,找到對應的子節點,進行遞歸,直到找到最終的葉子節點 int childIndex = current.Keys.Count; for (var i = 0; i < current.Keys.Count; i++) { var compareValue = key.CompareTo(current.Keys[i]); if (compareValue < 0) { childIndex = i; break; } else if (compareValue == 0) { throw new Exception(); } } current = current.Children[childIndex]; Insert(current, key, value); } } /// <summary> /// 冒泡 /// 噹噹前結點的個數等於階數的時候,就須要把當前結點的最中間的關鍵字放到父結點中去, /// 當前結點分裂成兩個結點,小於中間結點的是左結點,大於中間結點的右結點,都做爲子結點節點加到當前結點的父結點上面去, /// 由於默認左結點的parent是父結點,因此只須要加入右結點 /// 而後再判斷當前結點是否有子結點,若是有子結點 子結點個數一定超過了階數(由於子結點的個數老是比當前結點的關鍵字數大1) /// 如有子結點 則還須要把子結點分紅兩部分 一部分紅爲左結點的子結點 另外一部分紅爲右結點的子結點 分界點就是當前結點最中間關鍵字所在位置 /// 而後遞歸執行,把關鍵字放到父結點中後,判斷父結點是否也須要冒泡分裂 /// </summary> /// <param name="current"></param> private void Bubble(Node current) { var middleIndex = (current.Keys.Count - 1) / 2; var middleKey = current.Keys[middleIndex]; var middleValue = current.Values[middleIndex]; var newRightChild = new Node(); newRightChild.Parent = current.Parent; for (var i = middleIndex + 1; i < current.Keys.Count; i++) { newRightChild.Keys.Add(current.Keys[i]); newRightChild.Values.Add(current.Values[i]); } var newLeftChild = current; var count = newLeftChild.Keys.Count - middleIndex; newLeftChild.Keys.RemoveRange(middleIndex, count); newLeftChild.Values.RemoveRange(middleIndex, count); for (var i = middleIndex + 1; i < current.Children.Count;) { var temp = current.Children[i]; newRightChild.Children.Add(temp); temp.Parent = newRightChild; newLeftChild.Children.RemoveAt(i); } if (current.Parent == null) { current.Parent = new Node(); _first = current.Parent; _first.Children.Add(newLeftChild); _first.Children.Add(newRightChild); newLeftChild.Parent = _first; newRightChild.Parent = _first; } else { current.Parent.Children.Add(newRightChild); } current = current.Parent; current.Insert(middleKey, middleValue); if (current.Keys.Count >= _level) { Bubble(current); } }
private Node Find(K key, out int index) { index = -1; if (_first == null) { return null; } var current = _first; while (true) { var childIndex = current.Keys.Count; for (var i = 0; i < current.Keys.Count; i++) { var compareValue = key.CompareTo(current.Keys[i]); if (compareValue < 0) { childIndex = i; break; } else if (compareValue == 0) { index = i; return current; } } if (current.Children.Count > 0) { current = current.Children[childIndex]; } else { return null; } }; } public bool ContainsKey(K key) { return Find(key, out int index) != null; }
public void Remove(K key) { var current = Find(key, out int index); if (current == null) { return; } current.Keys.RemoveAt(index); current.Values.RemoveAt(index); BorrowFromChild(current, index); } /// <summary> /// 刪除節點後,若是當前節點key的數目少於_minKeysCount,須要向子節點借一個key (相似於算術減法,低位數不夠向高位借) /// </summary> /// <param name="current"></param> /// <param name="index"></param> private void BorrowFromChild(Node current, int index) { if (current.Children.Count == 0) { if (current.Keys.Count < _minKeysCount) { BorrowFromParent(current); } return; } var leftChild = current.Children[index]; var rightChild = current.Children[index + 1]; if (rightChild.Keys.Count > _minKeysCount) { var childIndex = 0; current.Keys.Insert(index, rightChild.Keys[childIndex]); current.Values.Insert(index, rightChild.Values[childIndex]); rightChild.Keys.RemoveAt(childIndex); rightChild.Values.RemoveAt(childIndex); } else { //remove var childIndex = leftChild.Keys.Count - 1; current.Keys.Insert(index, leftChild.Keys[childIndex]); current.Values.Insert(index, leftChild.Values[childIndex]); leftChild.Keys.RemoveAt(childIndex); leftChild.Values.RemoveAt(childIndex); if (leftChild.Keys.Count < _minKeysCount) { BorrowFromChild(leftChild, childIndex); } } } /// <summary> /// 葉子節點key的數目不夠時,須要向父節點借 /// </summary> /// <param name="current"></param> private void BorrowFromParent(Node current) { var parent = current.Parent; if (parent == null) { //當前結點爲根結點的話 不須要操做 return; } var index = parent.Children.IndexOf(current); if (index > 0) { //如有左邊兄弟結點 var leftSibling = parent.Children[index - 1]; var leftKeysIndex = leftSibling.Keys.Count - 1; if (leftKeysIndex >= _minKeysCount) { current.Keys.Insert(0, parent.Keys[index-1]); current.Values.Insert(0, parent.Values[index-1]); parent.Keys[index-1] = leftSibling.Keys[leftKeysIndex]; parent.Values[index-1] = leftSibling.Values[leftKeysIndex]; leftSibling.Keys.RemoveAt(leftKeysIndex); leftSibling.Values.RemoveAt(leftKeysIndex); return; } } if (index < parent.Children.Count - 1) { var rightSibling = parent.Children[index + 1]; if (rightSibling.Keys.Count > _minKeysCount) { current.Keys.Add(parent.Keys[index]); current.Values.Add(parent.Values[index]); parent.Keys[index] = rightSibling.Keys[0]; parent.Values[index] = rightSibling.Values[0]; rightSibling.Keys.RemoveAt(0); rightSibling.Values.RemoveAt(0); return; } } //若是左右兩邊兄弟結點都不知足條件 判斷是否有左邊兄弟結點,若是有則和左邊兄弟結點合併 沒有 和右邊兄弟結點融合 if (index > 0) { MergeToLeft(parent, parent.Children[index - 1], current); } else { MergeToLeft(parent, current, parent.Children[index + 1]); } if (parent.Keys.Count < _minKeysCount) { if(parent == _first) { //若是是根結點 if(parent.Keys.Count == 0) { _first = current; current.Parent = null; } } else { BorrowFromParent(parent); } } } private void MergeToLeft(Node parent, Node left, Node right) { var index = parent.Children.IndexOf(left); left.Keys.Add(parent.Keys[index]); left.Values.Add(parent.Values[index]); parent.Keys.RemoveAt(index); parent.Values.RemoveAt(index); left.Keys.AddRange(right.Keys); left.Values.AddRange(right.Values); left.Children.AddRange(right.Children); parent.Children.Remove(right); }
以上代碼均爲原創分享,若你們認爲有不妥的地方,煩請留言指出,在下感激涕零
也但願各位可以多多分享本身寫的東西,共同進步排序