📜  B树介绍

📅  最后修改于: 2021-09-09 11:14:47             🧑  作者: Mango

介绍:
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树的特性:

  1. 所有的叶子都在同一水平线上。
  2. B-Tree 由术语最小度数‘t’ 定义。 t 的值取决于磁盘块大小。
  3. 除根之外的每个节点必须至少包含 (ceiling)([t-1]/2) 个键。根可能包含最少 1 个密钥。
  4. 所有节点(包括根节点)最多可以包含 t – 1 个键。
  5. 节点的子节点数等于其中的键数加 1。
  6. 节点的所有键都按升序排序。两个键 k1 和 k2 之间的子键包含 k1 和 k2 范围内的所有键。
  7. B 树从根开始生长和收缩,这与二叉搜索树不同。二叉搜索树向下生长,也从向下收缩。
  8. 与其他平衡二叉搜索树一样,搜索、插入和删除的时间复杂度为 O(log n)。
  9. 在 B 树中插入节点只发生在叶节点。

下面是一个最小阶数为5的B-Tree的例子。注意,在实际的B-Trees中,最小阶数的值远远大于5。

我们可以在上图中看到,所有的叶子节点都在同一层,所有的非叶子节点都没有空的子树,并且键值比它们的子节点数少 1。
有趣的事实:

  1. 可以存在 n 个节点且 m 是节点的最大子节点数的 B 树的最小高度是: h_{min} =\lceil\log_m (n + 1)\rceil - 1
  2. 可以存在 n 个节点且 d 是非根节点可以拥有的最小子节点数的 B 树的最大高度是: h_{max} =\lfloor\log_t\frac {n + 1}{2}\rfloor             t = \lceil\frac {m}{2}\rceil

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 现场工作专业课程学生竞争性编程现场课程