B樹和B樹的實現 B-Tree
阿新 • • 發佈:2018-12-25
根據演算法導論的描述。B樹是一種特殊的平衡樹和查詢樹。其主要用於磁碟內資料的儲存和查詢。因此,B樹一般每個結點會比較大,包含許多資料關鍵字,最好佔一個頁面(page),這樣存取的時候直接存取一個結點的資料。
B樹的基本性質(M階):
1、B樹的每個葉子節點的高度均一致。
2、對於非空B樹,普通非根非葉節點至少有M-1個關鍵字(M個子女),至多2M-1個關鍵字(2M個子女)。根節點至少包含2個子女(因為根節點只有1個關鍵字時,要有兩個對應的孩子指標)。
3、結點內部的資料關鍵字是按從小到大排序的。
B樹的結點的結構(M階):
typedef struct btree_node { int k[2*M-1]; //用於儲存資料關鍵字 btree_node *p[2*M]; //用於儲存指向孩子的指標 int num; // 當前結點內資料關鍵字的個數, <=2*M-1 bool is_leaf; // 當前結點是否是葉子結點 true/false }btree_node,*btree;
B樹操作上的特質:
1、插入新資料關鍵字總是要往葉子結點上插入。
2、插入操作所造成的B樹的擴張,使得樹的高度升高一定是在根節點增加高度的。(這是由插入操作的手段所決定。)
B樹結點的建立:
在寫如何插入新的資料關鍵字之前,先考慮一個結點如何分裂:btree init_btree_node() { btree_node *node = (btree_node*)malloc(sizeof(btree_node)); if(node ==NULL) return NULL; for(int i=0;i<2*M-1;i++) node->k[i] = 0; for(int i=0;i<2*M;i++) node->p[i] = NULL; node->num = 0; node->is_leaf = true; return node; }
//child結點滿了,一分為二: 0~M-2 M-1 M~2M-2 // 1 //M-1 M-1 int split_child(btree parent, int pos, btree child) { //create a new child node for the other M-1 keys btree_node *new_child = init_btree_node(); if(new_child == NULL) return -1; new_child->is_leaf = child->is_leaf; new_child->num = M-1; for(int i=0;i<M-1;i++) new_child->k[i] = child->k[i+M]; if(new_child->is_leaf == false) for(int i=0;i<M;i++) new_child->p[i] = child->p[i+M]; //adjust the former child node child->num = M-1; //adjust parent node for(int i=parent->num; i>pos;i--) parent->p[i+1] = parent->p[i]; parent->p[pos+1] = new_child; for(int i=parent->num-1;i>=pos;i--) parent->k[i+1] = parent->k[i]; parent->k[pos] = child->k[M-1]; parent->num ++; return 1; }
對B樹新關鍵字插入的實現是個特別的過程,從根結點向下追溯到葉子結點,途中遇到滿的結點需要分裂:
--對根節點執行btree_insert();
--如果根節點滿了,B樹需要升高一層;
--向其孩子結點插入,遇到滿結點需要分裂,逐步遞迴到葉子結點。
btree btree_insert(btree root, int target)
{
if(root == NULL)
return NULL;
if(root->num == 2*M-1)
{
//create new root
//the only way to add the height of btree
btree_node *node = init_btree_node();
if(node == NULL)
return NULL;
node->is_leaf = false;
node->p[0] = root;
split_child(node, 0, root);
btree_insert_nonfull(node, target);
return node;
}
else
{
btree_insert_nonfull(root, target);
return root;
}
}
void btree_insert_nonfull(btree node, int target)
{
if(node->is_leaf == true)
{
int pos = node->num;
while(pos>=1 && target < node->k[pos-1])
{
node->k[pos] = node->k[pos-1];
pos--;
}
node->k[pos] = target;
node->num ++;
}
else
{
int pos = node->num;
while(pos>0 && target < node->k[pos-1])
pos--;
if(node->p[pos]->num == 2*M-1)
{
split_child(node, pos, node->p[pos]);
if(target > node->k[pos])
pos++;
}
btree_insert_nonfull(node->p[pos], target);
}
}
B樹的刪除操作:
未完成,有待學習。