正在载入交互式动画窗口请稍等

B树 可视化交互式动画版

图码-数据结构可视化动画版

传统二叉搜索树的局限性可能令人沮丧。 B 树是一种多才多艺的数据结构,可以轻松处理大量数据。 当涉及到存储和搜索大量数据时,传统的二叉搜索树由于其性能差和内存使用率高而变得不切实际。 B 树,也称为 B 树或平衡树,是一种自平衡树,专门为克服这些限制而设计。

与传统的二叉搜索树不同,B 树的特点是可以在单个节点中存储大量键,这就是为什么它们也被称为“大键”树。 B 树中的每个节点可以包含多个键,这使得树具有更大的分支因子,从而具有更浅的高度。 这种浅高度会减少磁盘 I/O,从而加快搜索和插入操作的速度。 B 树特别适合具有缓慢、大量数据访问的存储系统,例如硬盘驱动器、闪存和 CD-ROM。

B 树通过确保每个节点具有最少数量的键来保持平衡,因此树始终是平衡的。 这种平衡保证了插入、删除和搜索等操作的时间复杂度始终为 O(log n),无论树的初始形状如何。

B树的时间复杂度:  
 

先生。 出色地。 算法 时间复杂度
1. 搜索 O(logn)
2. 插入 O(logn)
3. 删除 O(logn)

注: “n”是B树中元素的总数

B 树的性质:  

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

以下是最小阶数为 5 的 B 树的示例 
注意: 在实际的 B 树中,最小阶数的值远大于 5。 
 

从上图中我们可以看到,所有的叶子节点都处于同一级别,所有非叶子节点都没有空子树,并且键的值比其子节点的数量少一。

关于 B 树的有趣事实:  

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

B树中的遍历:  

遍历也类似于二叉树的中序遍历。 我们从最左边的孩子开始,递归地打印最左边的孩子,然后对其余的孩子和键重复相同的过程。 最后,递归打印最右边的孩子。 

B树中的搜索操作:  

搜索类似于二叉搜索树中的搜索。 设要搜索的键为k。 

  • 从根开始,递归向下遍历。 
  • 对于每个访问过的非叶节点, 
    • 如果节点有密钥,我们只需返回该节点即可。 
    • 否则,我们递归到该节点的适当子节点(位于第一个更大键之前的子节点)。 
  • 如果我们到达叶节点并且在叶节点中没有找到 k,则返回 NULL。

搜索 B 树类似于搜索二叉树。 算法类似,都是递归的。 在每个级别,搜索都会得到优化,就好像键值不存在于父级范围中,然后键存在于另一个分支中一样。 由于这些值限制了搜索,因此它们也称为限制值或分离值。 如果我们到达叶节点但没有找到所需的键,那么它将显示 NULL。

在 B 树中搜索元素的算法:-

C++

struct Node {
    int n;
    int key[MAX_KEYS];
    Node* child[MAX_CHILDREN];
    bool leaf;
};
 
Node* BtreeSearch(Node* x, int k) {
    int i = 0;
    while (i < x->n && k > x->key[i]) {
        i++;
    }
    if (i < x->n && k == x->key[i]) {
        return x;
    }
    if (x->leaf) {
        return nullptr;
    }
    return BtreeSearch(x->child[i], k);
}


            

C

BtreeSearch(x, k)
    i = 1
     
    // n[x] means number of keys in x node
    while i ≤ n[x] and k ≥ keyi[x]
        do i = i + 1
    if i  n[x] and k = keyi[x]
        then return (x, i)  
    if leaf [x]
        then return NIL
    else
        return BtreeSearch(ci[x], k)


            

Java

class Node {
    int n;
    int[] key = new int[MAX_KEYS];
    Node[] child = new Node[MAX_CHILDREN];
    boolean leaf;
}
 
Node BtreeSearch(Node x, int k) {
    int i = 0;
    while (i < x.n && k >= x.key[i]) {
        i++;
    }
    if (i < x.n && k == x.key[i]) {
        return x;
    }
    if (x.leaf) {
        return null;
    }
    return BtreeSearch(x.child[i], k);
}


            

Python3

class Node:
    def __init__(self):
        self.n = 0
        self.key = [0] * MAX_KEYS
        self.child = [None] * MAX_CHILDREN
        self.leaf = True
 
def BtreeSearch(x, k):
    i = 0
    while i < x.n and k >= x.key[i]:
        i += 1
    if i < x.n and k == x.key[i]:
        return x
    if x.leaf:
        return None
    return BtreeSearch(x.child[i], k)


            

C#

class Node {
    public int n;
    public int[] key = new int[MAX_KEYS];
    public Node[] child = new Node[MAX_CHILDREN];
    public bool leaf;
}
 
Node BtreeSearch(Node x, int k) {
    int i = 0;
    while (i < x.n && k >= x.key[i]) {
        i++;
    }
    if (i < x.n && k == x.key[i]) {
        return x;
    }
    if (x.leaf) {
        return null;
    }
    return BtreeSearch(x.child[i], k);
}


            

JavaScript

// Define a Node class with properties n, key, child, and leaf
class Node {
    constructor() {
        this.n = 0;
        this.key = new Array(MAX_KEYS);
        this.child = new Array(MAX_CHILDREN);
        this.leaf = false;
    }
}
 
// Define a function BtreeSearch that takes in a Node object x and an integer k
function BtreeSearch(x, k) {
    let i = 0;
    while (i < x.n && k >= x.key[i]) {
        i++;
    }
    if (i < x.n && k == x.key[i]) {
        return x;
    }
    if (x.leaf) {
        return null;
    }
    return BtreeSearch(x.child[i], k);
}


            

例子: 

输入: 在给定的 B 树中搜索 120。 
 

 
解决方案:  
 

 

 

在这个例子中,我们可以看到,通过限制包含值的键出现的机会,我们的搜索量就减少了。 类似地,如果在上面的示例中我们要查找 180,那么控制将在步骤 2 处停止,因为程序会发现键 180 存在于当前节点中。 同样,如果要查找 90,则 90 < 100,因此它将自动转到左子树,因此控制流程将与上面示例中所示的类似。

下面是上述方法的实现:

C++

// C++ implementation of search() and traverse() methods
#include <iostream>
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, traverse 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, traverse
        // 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);
    }
}


          

Python3

# Create a node
class BTreeNode:
  def __init__(self, leaf=False):
    self.leaf = leaf
    self.keys = []
    self.child = []
 
 
# Tree
class BTree:
  def __init__(self, t):
    self.root = BTreeNode(True)
    self.t = t
 
    # Insert node
  def insert(self, k):
    root = self.root
    if len(root.keys) == (2 * self.t) - 1:
      temp = BTreeNode()
      self.root = temp
      temp.child.insert(0, root)
      self.split_child(temp, 0)
      self.insert_non_full(temp, k)
    else:
      self.insert_non_full(root, k)
 
    # Insert nonfull
  def insert_non_full(self, x, k):
    i = len(x.keys) - 1
    if x.leaf:
      x.keys.append((None, None))
      while i >= 0 and k[0] < x.keys[i][0]:
        x.keys[i + 1] = x.keys[i]
        i -= 1
      x.keys[i + 1] = k
    else:
      while i >= 0 and k[0] < x.keys[i][0]:
        i -= 1
      i += 1
      if len(x.child[i].keys) == (2 * self.t) - 1:
        self.split_child(x, i)
        if k[0] > x.keys[i][0]:
          i += 1
      self.insert_non_full(x.child[i], k)
 
    # Split the child
  def split_child(self, x, i):
    t = self.t
    y = x.child[i]
    z = BTreeNode(y.leaf)
    x.child.insert(i + 1, z)
    x.keys.insert(i, y.keys[t - 1])
    z.keys = y.keys[t: (2 * t) - 1]
    y.keys = y.keys[0: t - 1]
    if not y.leaf:
      z.child = y.child[t: 2 * t]
      y.child = y.child[0: t - 1]
 
  # Print the tree
  def print_tree(self, x, l=0):
    print("Level ", l, " ", len(x.keys), end=":")
    for i in x.keys:
      print(i, end=" ")
    print()
    l += 1
    if len(x.child) > 0:
      for i in x.child:
        self.print_tree(i, l)
 
  # Search key in the tree
  def search_key(self, k, x=None):
    if x is not None:
      i = 0
      while i < len(x.keys) and k > x.keys[i][0]:
        i += 1
      if i < len(x.keys) and k == x.keys[i][0]:
        return (x, i)
      elif x.leaf:
        return None
      else:
        return self.search_key(k, x.child[i])
       
    else:
      return self.search_key(k, self.root)
 
 
def main():
  B = BTree(3)
 
  for i in range(10):
    B.insert((i, 2 * i))
 
  B.print_tree(B.root)
 
  if B.search_key(8) is not None:
    print("\nFound")
  else:
    print("\nNot Found")
 
 
if __name__ == '__main__':
  main()


          

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, traverse
        // 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


          

JavaScript

// Javascript program to illustrate the sum of two numbers
 
// A BTree
class Btree
{
 
    // Constructor (Initializes tree as empty)
    constructor(t)
    {
        this.root = null;
        this.t = t;
    }
     
    // function to traverse the tree
    traverse()
    {
        if (this.root != null)
            this.root.traverse();
        document.write("<br>");
    }
     
    // function to search a key in this tree
    search(k)
    {
        if (this.root == null)
            return null;
        else
            return this.root.search(k);
    }
     
}
 
// A BTree node
class BTreeNode
{
     // Constructor
    constructor(t,leaf)
    {
        this.t = t;
        this.leaf = leaf;
        this.keys = new Array(2 * t - 1);
        this.C = new Array(2 * t);
        this.n = 0;
    }
    // A function to traverse all nodes in a subtree rooted with this node
    traverse()
    {
        // There are n keys and n+1 children, traverse through n keys
        // and first n children
        let 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();
            }
            document.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.
    search(k)    // returns NULL if k is not present.
    {
     
        // Find the first key greater than or equal to k
        let 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 patel2127


          

注意: 以上代码不包含驱动程序。 我们将在下一篇关于B 树插入的 文章中介绍完整的程序

定义B-Tree有两种约定,一是按最小度定义,二是按顺序定义。 我们遵循了最小度数约定,并且在接下来的 B-Tree 帖子中也将遵循相同的约定。 上面程序中使用的变量名也保持不变

B树的应用:

  • 它在大型数据库中用于访问存储在磁盘上的数据
  • 使用 B 树可以在更短的时间内搜索数据集中的数据
  • 通过索引功能,可以实现多级索引。
  • 大多数服务器也使用B树方法。
  • B 树在 CAD 系统中用于组织和搜索几何数据。
  • B 树还用于其他领域,例如自然语言处理、计算机网络和密码学。

B 树的优点:

  •  对于插入、删除和搜索等基本操作,B 树的时间复杂度保证为 O(log n),这使得它们适合大型数据集和实时应用。
  •  B 树是自平衡的。
  • 高并发、高吞吐量。
  • 高效的存储利用率。

B 树的缺点:

  • B 树基于基于磁盘的数据结构,并且可能具有较高的磁盘使用率。
  • 并非对所有情况都是最好的。
  • 与其他数据结构相比速度较慢。

插入和删除:
B 树插入 B 树删除  

如果您发现任何不正确的内容,或者您​​想分享有关上述主题的更多信息,请发表评论。


无论你的目标是考试成功、职业发展,还是纯粹的兴趣,这个数据结构和算法可视化的网站都会是一个无价的资源。

前往这个网站,开始你的学习之旅吧!

这些是常见的:【C语言描述】《数据结构和算法》数据结构JAVA实现 数据结构与算法基础(青岛大学-王卓)数据结构与算法王道数据结构c语言实现 速成数据结构期末考前救急 数据结构视频C语言版教程 数据结构严蔚敏 数据结构郝斌 数据结构考研 JAVA数据结构算法与基础 数据结构王道 2022数据结构学习 数据结构小甲鱼 王卓 学习数据结构 数据结构浙江大学 数据结构复习 数据结构马士兵 数据结构零基础教程 数据结构和算法 数据结构入门 考研数据结构习题讲解 数据结构期末复习 计算机二级