树是一种数据结构。树用多个节点储存元素。某些节点存在一定的关系,用连线表示。二叉树是一种特殊的树,每个节点最多有两个子树。二叉树常用于实现二叉搜索树和二叉堆。 而 AVL 树 是特殊的二叉树,是最早被发明的自平衡二叉查找树。B 树保留了自平衡的特点,但 B 树的每个节点可以拥有两个以上的子节点,因此 B 树是一种多路搜索树。
性质
首先介绍一下一棵 阶的 B 树的特性。 表示这个树的每一个节点最多可以拥有的子节点个数。一棵 阶的 B 树满足的性质如下:
B 树中的节点包含有多个键。假设需要查找的是 ,那么从根节点开始,从上到下递归的遍历树。在每一层上,搜索的范围被减小到包含了搜索值的子树中。 子树值的范围被它的父节点的键确定。因为是从根节点开始的二分法查找,所以查找一个键的代码如下:
实现
1 2 3 4 5 6 7 8 91011121314
BTreeNode*BTreeNode::search(intk){// 找到第一个大于等于待查找键 k 的键inti=0;while(i<n&&k>keys[i])i++;// 如果找到的第一个键等于 k , 返回节点指针if(keys[i]==k)returnthis;// 如果没有找到键 k 且当前节点为叶子节点则返回NULLif(leaf==true)returnNULL;// 递归returnC[i]->search(k);}
遍历
B 树的中序遍历与二叉搜索树的中序遍历也很相似,从最左边的孩子节点开始,递归地打印最左边的孩子节点,然后对剩余的孩子和键重复相同的过程。 最后,递归打印最右边的孩子节点。
遍历的代码如下:
实现
1 2 3 4 5 6 7 8 91011121314
voidBTreeNode::traverse(){// 有 n 个键和 n+1 个孩子// 遍历 n 个键和前 n 个孩子inti;for(i=0;i<n;i++){// 如果当前节点不是叶子节点, 在打印 key[i] 之前,// 先遍历以 C[i] 为根的子树.if(leaf==false)C[i]->traverse();cout<<" "<<keys[i];}// 打印以最后一个孩子为根的子树if(leaf==false)C[i]->traverse();}
B-Tree-Delete-Key(x, k)
if not leaf[x] then
y ← Preceding-Child(x)
z ← Successor-Child(x)
if n[[y] > t − 1 then
k' ← Find-Predecessor-Key(k, x)]()
Move-Key(k', y, x)
Move-Key(k, x, z)
B-Tree-Delete-Key(k, z)
else if n[z] > t − 1 then
k' ← Find-Successor-Key(k, x)
Move-Key(k', z, x)
Move-Key(k, x, y)
B-Tree-Delete-Key(k, y)
else
Move-Key(k, x, y)
Merge-Nodes(y, z)
B-Tree-Delete-Key(k, y)
else (leaf node)
y ← Preceding-Child(x)
z ← Successor-Child(x)
w ← root(x)
v ← RootKey(x)
if n[x] > t − 1 then Remove-Key(k, x)
else if n[y] > t − 1 then
k' ← Find-Predecessor-Key(w, v)
Move-Key(k', y,w)
k' ← Find-Successor-Key(w, v)
Move-Key(k',w, x)
B-Tree-Delete-Key(k, x)
else if n[w] > t − 1 then
k' ← Find-Successor-Key(w, v)
Move-Key(k', z,w)
k' ← Find-Predecessor-Key(w, v)
Move-Key(k',w, x)
B-Tree-Delete-Key(k, x)
else
s ← Find-Sibling(w)
w' ← root(w)
if n[w'] = t − 1 then
Merge-Nodes(w',w)
Merge-Nodes(w, s)
B-Tree-Delete-Key(k, x)
else
Move-Key(v,w, x)
B-Tree-Delete-Key(k, x)