1. 程式人生 > >資料結構 JAVA描述(十六) 動態查詢 B-樹 B+樹 紅黑樹

資料結構 JAVA描述(十六) 動態查詢 B-樹 B+樹 紅黑樹

B-樹

前面介紹的查詢演算法都在記憶體中進行的,它們適合用於較小的檔案,而對於較大的、存放在外存的檔案就不合適,對於此類較大規模的檔案,即使是採用了平衡二叉樹,在查詢效率上仍然較低。例如若將存放在外存的10億條記錄組織為平衡二叉樹,則每次訪問記錄需要進行約30次外存訪問;而若採用256階的B-樹資料結構,則每次訪問記錄需要進行的外存訪問次數為4到5次。

B-樹是一種平衡的多路查詢樹,在檔案系統中,B-樹已經成為索引檔案的有效結構,並得到了廣泛的應用研究。

一顆m階的(m≥3)的B-樹,或為空樹,或滿足以下特性:

  1. 樹中的每個結點至多有m棵子樹

  2. 若根結點不是葉子結點,則至少有兩棵子樹

  3. 所有非終端結點中包含下列資訊:(n, P0, K1, P1, K2……Kn, Pn)
    其中,Ki(1≤i≤n)為關鍵字,且K i < K i+1;Pj所指子樹中所有結點的關鍵字值均小於K j+1,大於K j。n([m/2] - 1 ≤ n ≤ m-1)為關鍵字個數,n+1為子樹個數

  4. 除根結點外的所有非終端結點至少有[m/2]棵子樹,也即至少應有[m/2]-1個關鍵字

  5. 所有的葉子結點出現在同一層次上,並且不帶資訊(可以看作是外部結點或查詢失敗的結點,實際上這些結點不存在,指向這些結點指標為空)

如下圖為8個非終端結點、14個葉子結點和13個關鍵字組成的4階的B-樹示意圖:

這裡寫圖片描述

在一棵4階的B-樹中,每個結點關鍵字個數最少為[m/2] - 1”=1,最多為m-1=3;每個結點的子樹數目最少為[m/2]=2,最多為m=4

B-樹又稱為多路查詢樹,在B-樹中查詢一個關鍵字值=給定值key的具體過程是
首先在根結點的關鍵字序列(key1,key2,key3……keyn)中查詢,由於這個關鍵字序列是有序的,因此既可採用順查詢,也可採用二分查詢;若無匹配,(假設key i < key < key i+1),此時應沿著pi指標所指的結點繼續在相應的子樹中查詢。

需要說明的是,B-樹經常用於外部檔案的查詢,某些子樹未常駐記憶體,因為查詢過程需要從外存中讀入記憶體,讀盤次數與待查詢的結點在樹中的層次有關,但最多不會超過樹的深度,而在記憶體查詢所需的時間與結點中關鍵字的個數密切相關。

因為在外存上讀取結點比在記憶體中進行關鍵字查詢耗時多,所以在外存上讀取結點的次數,即B-樹的層次樹是決定B-樹查詢效率的首要因素。

㏒m (n+1) ≤ h ≤ ㏒[m/2] (n+1)/2 + 1,若當n=10000,m=10時,B-樹的深度在5-6之間。

[BTree_1

package Search;

class Node<T> {
    private
int keyNum; // 關鍵字個數域 private boolean isLeaf; // 是否為樹葉 private T[] key; // 關鍵字陣列 private Node[] child; // 子樹指標陣列 private Node parent; // 雙親結點指標 Node(int m){ keyNum = 0; isLeaf = true; key = (T[])(new Object[2 * m - 1]); '2509child = new Node[2 * m]; parent = null; } public int getKeyNum() { return keyNum; } public void setKeyNum(int keyNum) { this.keyNum = keyNum; } public boolean isLeaf() { return isLeaf; } public void setLeaf(boolean isLeaf) { this.isLeaf = isLeaf; } public T[] getKey() { return key; } public void setKey(T[] key) { this.key = key; } public Node[] getChild() { return child; } public void setChild(Node'5B] child) { this.child = child; } public Node getParent() { return parent; } public void setParent(Node parent) { this.parent = parent; } } class Result{ private Node resultNode; //B-樹查詢結果型別 private int i; //指向找到的結點 private boolean found; //true找到 false未找到 public Node getResultNode() { return resultNode; } public void setResultNode(Node resultNode) { this.resultNode = resultNode; } public int getI() { return i; } public void setI(int i) { this.i = i; } public boolean isFound() { return found; } public void setFound(boolean found) { this.found = found; } } public class BTree<T> { private Node<T> root = null; private int"degree; public BTree(int t){ degree = t; } /** * @description B-樹查詢演算法 * @param root * @param key * @return * @time 2016年1月13日 下午11:54:57 */ public Result searchBTree(Node<T> root, T key){ int"i = 0; Node<T> p = root, q = null; //p指向待查詢的結點,q指向p的雙親結點 boolean found = false; Result rs = new Result(); //存放查詢結果 Comparable<T> k = (Comparable<T>) key; while(p != null && !found){ i = 0; while(i < p.getKeyNum() && k.compareTo(p.getKey()[i])>0) i++; //找到 if(i < p.getKeyNum() && k.compareTo(p.getKey()[i]) == 0) found = true; else{ q = p; //儲存雙親結點 p = p.ggtChild()[i]; //在子樹中查詢 } } if(found == false) p = q; rs.setResultNode(p); rs.setI(i); rs.setFound(found); return rs; } }

首先在樹中查詢key,若找到則直接返回,否則,查詢操作必定失敗在某個葉子結點上,則插入。若此結點原來是滿的,插入後違反了規則,則以key[m/2]為劃分點,分成兩個結點,然後把key[m/2]升到雙親結點中。於是雙親結點指向被插入結點的指標p就改成p1和p2兩部分。

這裡寫圖片描述

這裡寫圖片描述

這裡寫圖片描述

  1. 若刪除結點Ki是最下層的非終端結點(即葉子結點的上一層),則應刪除Ki及它右邊的指標;刪除後若結點中關鍵字個數不少於[m/2]-1,則刪除完成;否則要進行合併結點操作。

    • 被刪關鍵字所在結點的關鍵字個數不小於[m/2],則只需從該結點刪除關鍵字Ki和相應的指標Pi,樹的其他部分保持不變。
      這裡寫圖片描述

    • 被刪除關鍵字所在結點的關鍵字個數等於[m/2]-1,而與該結點相鄰的有兄弟(或左兄弟)結點的關鍵字>[m/2]-1,則需將其右兄弟(或左兄弟)的最小關鍵字上移到雙親結點中,而將其雙親結點中<(或>)該上移關鍵字的關鍵字下移到被刪關鍵字所在的結點中。
      這裡寫圖片描述

    • 被刪關鍵字所在的結點的關鍵字個數和其相鄰的兄弟結點中的關鍵字個數均等於[m/2]-1,此時需將被刪除關鍵字的所有結點與其左或右兄弟合併。
      這裡寫圖片描述

2.若刪除結點是最下層的非終端結點以上某個層次的結點,根據B-樹的特性可知,可用Ki右邊指標Pi所指子樹中最小關鍵字Y代替Ki,然後在相應的結點中刪除Y。

這裡寫圖片描述

這裡寫圖片描述

B+樹

  1. B-樹中,每一個結點含有n個關鍵字和n+1棵子樹;而在B+樹中,每一個結點含有n個關鍵字和n棵子樹,即每一個關鍵字對應一棵子樹

  2. 在B-樹中,每個結點(除根結點)中關鍵字取值範圍為[m/2]-1 ≤ n ≤ m-1;而在B+樹中是[m/2] ≤ n ≤ m

  3. B+樹中所有葉子結點包含了全部關鍵字及指向對應記錄的指標,且所有葉子結點按關鍵字從小到大的順序依次連線。

4.B+樹中所有葉子結點僅起到索引作用,即結點中的每一個索引項只含有對應子樹的最大關鍵字和指向該子樹的指標,不含有該關鍵字對應記錄的儲存地址。

這裡寫圖片描述

紅黑樹

紅黑樹又稱“對稱二叉B樹“,是一種自平衡的二叉查詢樹。除了具有二叉排序樹的性質外,還具有以下三點性質:

  1. 根結點和所有外部結點的顏色都是黑色的。

  2. 從根結點到外部結點的所有路徑上沒有兩個連續的紅色結點。

  3. 從根結點到外部結點的所有路徑上都包含相同數目的黑色結點。

這裡寫圖片描述

同二叉排序樹的查詢演算法。

首先使用二叉排序樹的插入演算法將一個結點插入到紅黑樹中,該結點作為新的葉子結點插入到紅黑樹中某一外部結點位置。在插入過程中需要為新結點設定顏色。

新插入的結點肯定為紅色,此時與性質2發生衝突,紅黑樹不平衡。通過檢查新結點u、父結點pu、祖父結點gu,可對不平衡的總類進行分類(8種):

  1. LLr型:pu是gu左孩子,u是pu左孩子,gu另一孩子為紅色;

  2. LRr型:pu是gu左孩子,u是pu右孩子,gu另一孩子為紅色;

  3. RRr型:pu是gu右孩子,u是pu右孩子,gu另一孩子為紅色;

  4. RLr型:pu是gu右孩子,u是pu左孩子,gu另一孩子為紅色;

  5. LLb型:pu是gu左孩子,u是pu左孩子,gu另一孩子為黑色;

  6. LRb型:pu是gu左孩子,u是pu右孩子,gu另一孩子為黑色;

  7. RRb型:pu是gu右孩子,u是pu右孩子,gu另一孩子為黑色;

  8. RLr型:pu是gu右孩子,u是pu左孩子,gu另一孩子為黑色;

對於以上1-4種可以通過改變顏色來進行,5-8種需要進行一次旋轉處理。具體演算法有待研究,這裡只作初步瞭解。