B-樹
前面介紹的查找算法都在內存中進行的,它們適合用於較小的文件,而對於較大的、存放在外存的文件就不合適,對於此類較大規模的文件,即使是採用了平衡二叉樹,在查找效率上仍然較低。例如若將存放在外存的10億條記錄組織爲平衡二叉樹,則每次訪問記錄需要進行約30次外存訪問;而若採用256階的B-樹數據結構,則每次訪問記錄需要進行的外存訪問次數爲4到5次。
B-樹的定義
B-樹是一種平衡的多路查找樹,在文件系統中,B-樹已經成爲索引文件的有效結構,並得到了廣泛的應用研究。
一顆m階的(m≥3)的B-樹,或爲空樹,或滿足以下特性:
樹中的每個結點至多有m棵子樹
若根結點不是葉子結點,則至少有兩棵子樹
所有非終端結點中包含下列信息:(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爲子樹個數除根結點外的所有非終端結點至少有[m/2]棵子樹,也即至少應有[m/2]-1個關鍵字
所有的葉子結點出現在同一層次上,並且不帶信息(可以看作是外部結點或查找失敗的結點,實際上這些結點不存在,指向這些結點指針爲空)
如下圖爲8個非終端結點、14個葉子結點和13個關鍵字組成的4階的B-樹示意圖:
在一棵4階的B-樹中,每個結點關鍵字個數最少爲[m/2] - 1”=1,最多爲m-1=3;每個結點的子樹數目最少爲[m/2]=2,最多爲m=4
基於B-樹的查找算法
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;
}
}
基於B-樹的插入算法
首先在樹中查找key,若找到則直接返回,否則,查找操作必定失敗在某個葉子結點上,則插入。若此結點原來是滿的,插入後違反了規則,則以key[m/2]爲劃分點,分成兩個結點,然後把key[m/2]升到雙親結點中。於是雙親結點指向被插入結點的指針p就改成p1和p2兩部分。
基於B-樹的刪除算法
若刪除結點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+樹
B+樹和B-樹的區別
B-樹中,每一個結點含有n個關鍵字和n+1棵子樹;而在B+樹中,每一個結點含有n個關鍵字和n棵子樹,即每一個關鍵字對應一棵子樹
在B-樹中,每個結點(除根結點)中關鍵字取值範圍爲[m/2]-1 ≤ n ≤ m-1;而在B+樹中是[m/2] ≤ n ≤ m
B+樹中所有葉子結點包含了全部關鍵字及指向對應記錄的指針,且所有葉子結點按關鍵字從小到大的順序依次連接。
4.B+樹中所有葉子結點僅起到索引作用,即結點中的每一個索引項只含有對應子樹的最大關鍵字和指向該子樹的指針,不含有該關鍵字對應記錄的存儲地址。
紅黑樹
紅黑樹又稱“對稱二叉B樹“,是一種自平衡的二叉查找樹。除了具有二叉排序樹的性質外,還具有以下三點性質:
根結點和所有外部結點的顏色都是黑色的。
從根結點到外部結點的所有路徑上沒有兩個連續的紅色結點。
從根結點到外部結點的所有路徑上都包含相同數目的黑色結點。
紅黑樹的查找
同二叉排序樹的查找算法。
紅黑樹的插入
首先使用二叉排序樹的插入算法將一個結點插入到紅黑樹中,該結點作爲新的葉子結點插入到紅黑樹中某一外部結點位置。在插入過程中需要爲新結點設置顏色。
新插入的結點肯定爲紅色,此時與性質2發生衝突,紅黑樹不平衡。通過檢查新結點u、父結點pu、祖父結點gu,可對不平衡的總類進行分類(8種):
LLr型:pu是gu左孩子,u是pu左孩子,gu另一孩子爲紅色;
LRr型:pu是gu左孩子,u是pu右孩子,gu另一孩子爲紅色;
RRr型:pu是gu右孩子,u是pu右孩子,gu另一孩子爲紅色;
RLr型:pu是gu右孩子,u是pu左孩子,gu另一孩子爲紅色;
LLb型:pu是gu左孩子,u是pu左孩子,gu另一孩子爲黑色;
LRb型:pu是gu左孩子,u是pu右孩子,gu另一孩子爲黑色;
RRb型:pu是gu右孩子,u是pu右孩子,gu另一孩子爲黑色;
RLr型:pu是gu右孩子,u是pu左孩子,gu另一孩子爲黑色;
對於以上1-4種可以通過改變顏色來進行,5-8種需要進行一次旋轉處理。具體算法有待研究,這裏只作初步瞭解。