介绍:
B-Tree 是一种自平衡搜索树。在大多数其他自平衡搜索树(如 AVL 和红黑树)中,假设所有内容都在主内存中。要理解 B-Trees 的使用,我们必须考虑无法容纳在主内存中的大量数据。当key个数较多时,数据以块的形式从磁盘读取。与主存储器访问时间相比,磁盘访问时间非常长。使用 B 树的主要思想是减少磁盘访问次数。大多数树操作(搜索、插入、删除、最大值、最小值、..等)需要 O(h) 次磁盘访问,其中 h 是树的高度。 B树是一棵胖树。通过在 B-Tree 节点中放置最大可能的键来保持 B-Tree 的高度较低。通常,B-Tree 节点大小保持等于磁盘块大小。由于 B 树的高度较低,因此与平衡二叉搜索树(如 AVL 树、红黑树等)相比,大多数操作的总磁盘访问量显着减少。
B-Tree的时间复杂度:
Sr. No. | Algorithm | Time Complexity |
---|---|---|
1. | Search | O(log n) |
2. | Insert | O(log n) |
3. | Delete | O(log n) |
“n”是 B 树中元素的总数。
B树的特性:
- 所有的叶子都在同一水平线上。
- B-Tree 由术语最小度数‘t’ 定义。 t 的值取决于磁盘块大小。
- 除根之外的每个节点必须至少包含 (ceiling)([t-1]/2) 个键。根可能包含最少 1 个密钥。
- 所有节点(包括根节点)最多可以包含 t – 1 个键。
- 节点的子节点数等于其中的键数加 1。
- 节点的所有键都按升序排序。两个键 k1 和 k2 之间的子键包含 k1 和 k2 范围内的所有键。
- B 树从根开始生长和收缩,这与二叉搜索树不同。二叉搜索树向下生长,也从向下收缩。
- 与其他平衡二叉搜索树一样,搜索、插入和删除的时间复杂度为 O(log n)。
- 在 B 树中插入节点只发生在叶节点。
下面是一个最小阶数为5的B-Tree的例子。注意,在实际的B-Trees中,最小阶数的值远远大于5。
我们可以在上图中看到,所有的叶子节点都在同一层,所有的非叶子节点都没有空的子树,并且键值比它们的子节点数少 1。
有趣的事实:
- 可以存在 n 个节点且 m 是节点的最大子节点数的 B 树的最小高度是:
- 可以存在 n 个节点且 d 是非根节点可以拥有的最小子节点数的 B 树的最大高度是: 和
B树中的遍历:
遍历也类似于二叉树的中序遍历。我们从最左边的孩子开始,递归打印最左边的孩子,然后对剩余的孩子和键重复相同的过程。最后,递归打印最右边的孩子。
B-Tree中的搜索操作:
搜索类似于二叉搜索树中的搜索。设要搜索的关键字为 k。我们从根开始向下递归遍历。对于每个访问过的非叶子节点,如果该节点有键,我们只需返回该节点。否则,我们向下递归到节点的适当子节点(就在第一个较大键之前的子节点)。如果我们到达一个叶节点并且在叶节点中没有找到 k,我们将返回 NULL。
逻辑:
搜索 B 树类似于搜索二叉树。该算法与递归相似。在每个级别,搜索都被优化,就好像键值不存在于父范围中,然后键存在于另一个分支中。由于这些值限制了搜索,因此它们也称为限制值或分离值。如果我们到达叶节点并且没有找到所需的键,那么它将显示 NULL。
示例:在给定的 B 树中搜索 120。
解决方案:
在这个例子中,我们可以看到我们的搜索减少了,因为只限制了包含该值的键可能出现的机会。类似地,如果在上面的示例中我们必须查找 180,那么控制将在第 2 步停止,因为程序将发现键 180 存在于当前节点中。同样,如果要查找 90,那么 90 < 100 将自动转到左子树,因此控制流将与上述示例中所示类似。
C++
// C++ implementation of search() and traverse() methods
#include
using namespace std;
// A BTree node
class BTreeNode
{
int *keys; // An array of keys
int t; // Minimum degree (defines the range for number of keys)
BTreeNode **C; // An array of child pointers
int n; // Current number of keys
bool leaf; // Is true when node is leaf. Otherwise false
public:
BTreeNode(int _t, bool _leaf); // Constructor
// A function to traverse all nodes in a subtree rooted with this node
void traverse();
// A function to search a key in the subtree rooted with this node.
BTreeNode *search(int k); // returns NULL if k is not present.
// Make the BTree friend of this so that we can access private members of this
// class in BTree functions
friend class BTree;
};
// A BTree
class BTree
{
BTreeNode *root; // Pointer to root node
int t; // Minimum degree
public:
// Constructor (Initializes tree as empty)
BTree(int _t)
{ root = NULL; t = _t; }
// function to traverse the tree
void traverse()
{ if (root != NULL) root->traverse(); }
// function to search a key in this tree
BTreeNode* search(int k)
{ return (root == NULL)? NULL : root->search(k); }
};
// Constructor for BTreeNode class
BTreeNode::BTreeNode(int _t, bool _leaf)
{
// Copy the given minimum degree and leaf property
t = _t;
leaf = _leaf;
// Allocate memory for maximum number of possible keys
// and child pointers
keys = new int[2*t-1];
C = new BTreeNode *[2*t];
// Initialize the number of keys as 0
n = 0;
}
// Function to traverse all nodes in a subtree rooted with this node
void BTreeNode::traverse()
{
// There are n keys and n+1 children, travers through n keys
// and first n children
int i;
for (i = 0; i < n; i++)
{
// If this is not leaf, then before printing key[i],
// traverse the subtree rooted with child C[i].
if (leaf == false)
C[i]->traverse();
cout << " " << keys[i];
}
// Print the subtree rooted with last child
if (leaf == false)
C[i]->traverse();
}
// Function to search key k in subtree rooted with this node
BTreeNode *BTreeNode::search(int k)
{
// Find the first key greater than or equal to k
int i = 0;
while (i < n && k > keys[i])
i++;
// If the found key is equal to k, return this node
if (keys[i] == k)
return this;
// If the key is not found here and this is a leaf node
if (leaf == true)
return NULL;
// Go to the appropriate child
return C[i]->search(k);
}
Java
// Java program to illustrate the sum of two numbers
// A BTree
class Btree {
public BTreeNode root; // Pointer to root node
public int t; // Minimum degree
// Constructor (Initializes tree as empty)
Btree(int t) {
this.root = null;
this.t = t;
}
// function to traverse the tree
public void traverse() {
if (this.root != null)
this.root.traverse();
System.out.println();
}
// function to search a key in this tree
public BTreeNode search(int k) {
if (this.root == null)
return null;
else
return this.root.search(k);
}
}
// A BTree node
class BTreeNode {
int[] keys; // An array of keys
int t; // Minimum degree (defines the range for number of keys)
BTreeNode[] C; // An array of child pointers
int n; // Current number of keys
boolean leaf; // Is true when node is leaf. Otherwise false
// Constructor
BTreeNode(int t, boolean leaf) {
this.t = t;
this.leaf = leaf;
this.keys = new int[2 * t - 1];
this.C = new BTreeNode[2 * t];
this.n = 0;
}
// A function to traverse all nodes in a subtree rooted with this node
public void traverse() {
// There are n keys and n+1 children, travers through n keys
// and first n children
int i = 0;
for (i = 0; i < this.n; i++) {
// If this is not leaf, then before printing key[i],
// traverse the subtree rooted with child C[i].
if (this.leaf == false) {
C[i].traverse();
}
System.out.print(keys[i] + " ");
}
// Print the subtree rooted with last child
if (leaf == false)
C[i].traverse();
}
// A function to search a key in the subtree rooted with this node.
BTreeNode search(int k) { // returns NULL if k is not present.
// Find the first key greater than or equal to k
int i = 0;
while (i < n && k > keys[i])
i++;
// If the found key is equal to k, return this node
if (keys[i] == k)
return this;
// If the key is not found here and this is a leaf node
if (leaf == true)
return null;
// Go to the appropriate child
return C[i].search(k);
}
}
C#
// C# program to illustrate the sum of two numbers
using System;
// A BTree
class Btree
{
public BTreeNode root; // Pointer to root node
public int t; // Minimum degree
// Constructor (Initializes tree as empty)
Btree(int t)
{
this.root = null;
this.t = t;
}
// function to traverse the tree
public void traverse()
{
if (this.root != null)
this.root.traverse();
Console.WriteLine();
}
// function to search a key in this tree
public BTreeNode search(int k)
{
if (this.root == null)
return null;
else
return this.root.search(k);
}
}
// A BTree node
class BTreeNode
{
int[] keys; // An array of keys
int t; // Minimum degree (defines the range for number of keys)
BTreeNode[] C; // An array of child pointers
int n; // Current number of keys
bool leaf; // Is true when node is leaf. Otherwise false
// Constructor
BTreeNode(int t, bool leaf) {
this.t = t;
this.leaf = leaf;
this.keys = new int[2 * t - 1];
this.C = new BTreeNode[2 * t];
this.n = 0;
}
// A function to traverse all nodes in a subtree rooted with this node
public void traverse() {
// There are n keys and n+1 children, travers through n keys
// and first n children
int i = 0;
for (i = 0; i < this.n; i++) {
// If this is not leaf, then before printing key[i],
// traverse the subtree rooted with child C[i].
if (this.leaf == false) {
C[i].traverse();
}
Console.Write(keys[i] + " ");
}
// Print the subtree rooted with last child
if (leaf == false)
C[i].traverse();
}
// A function to search a key in the subtree rooted with this node.
public BTreeNode search(int k) { // returns NULL if k is not present.
// Find the first key greater than or equal to k
int i = 0;
while (i < n && k > keys[i])
i++;
// If the found key is equal to k, return this node
if (keys[i] == k)
return this;
// If the key is not found here and this is a leaf node
if (leaf == true)
return null;
// Go to the appropriate child
return C[i].search(k);
}
}
// This code is contributed by Rajput-Ji
如果您希望与专家一起参加现场课程,请参阅DSA 现场工作专业课程和学生竞争性编程现场课程。