了解B树的搜索

    在本教程中,您将学习什么是B树。此外,您还找到C语言中的示例。
    B-树是一种特殊类型的自平衡搜索树,其中每个节点可以包含多个键,并且可以有两个以上的子节点。它是二叉搜索树的一种推广形式。
    它也被称为高度平衡的m-way树。
在这里插入图片描述

1. 为什么选择B树?

    随着访问物理存储介质(如硬盘)所需时间的减少,对B-tree的需求也随之增加。辅助存储设备速度较慢,容量较大,有必要采用这种类型的数据结构,以尽量减少对磁盘的访问。
    其他数据结构如二叉搜索树、avl树、红黑树等只能在一个节点中存储一个key。如果您必须存储大量的key,那么这些树的高度会变得非常大,访问时间也会增加。
    然而,B-树可以在单个节点中存储多个key,并且可以有多个子节点。这大大降低了高度,从而可以更快地访问磁盘。

2. B树属性
  1. 对于每个节点x,key按递增顺序存储。
  2. 在每个节点中,都有一个布尔值x.leaf,如果x是叶子,则该值为真。
  3. 如果n是树的顺序,则每个内部节点最多可以包含n-1个键以及指向每个子节点的指针。
  4. 除根节点外,每个节点最多可以有n个子节点,至少可以有n/2个子节点。
  5. 所有的叶子都有相同的深度(即树的高度h)。
  6. 根至少有2个子级,并且至少包含1个键。
  7. 如果n≥1,则对于任意n键B树,假设高度为h且最小级 t≥2,则 h ≥ log ⁡ t ( n + 1 ) / 2 h ≥ \log_t (n+1)/2 hlogt(n+1)/2
3. 操作
3.1 搜索

    在B-树中搜索元素是在二叉搜索树中搜索元素的一般形式,遵循以下步骤。

  1. 从根节点开始,将k与节点的第一个键进行比较。如果 k = 节点的第一个键,返回节点和相应索引。
  2. 如果k.leaf=true,则返回NULL(即未找到)。
  3. 如果 k < 根节点第一个键,递归搜索此键的左子级。
  4. 如果当前节点中有多个键且k>第一个键,请将k与节点中的下一个键进行比较。
    如果k<下一个键,则搜索该键的左子项(即k位于第一个键和第二个键之间)。
    否则,搜索键的右子级。
  5. 重复步骤1到4,直到到达叶。
3.2 搜索示例
  1. 让我们在3级以下的树中搜索关键字 k = 17。
    在这里插入图片描述
  2. 在根中找不到k,因此请将其与根键进行比较。
    在这里插入图片描述
  3. 因为k>11,所以转到根节点的右子节点。
    在这里插入图片描述
  4. 把k和16比较一下。由于k>16,将k与下一个键18进行比较。
    在这里插入图片描述
  5. 由于k<18,k介于16和18之间。搜索16的右子级或18的左子级。
    在这里插入图片描述
  6. 找到k。
    在这里插入图片描述
4. 搜索元素的算法
BtreeSearch(x, k)
 i = 1
 while i ≤ n[x] and k ≥ keyi[x]        // n[x] means number of keys in x node
    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)
5. C示例
// Searching a key on a B-tree in C

#include <stdio.h>
#include <stdlib.h>

#define MAX 3
#define MIN 2

struct BTreeNode {
  int val[MAX + 1], count;
  struct BTreeNode *link[MAX + 1];
};

struct BTreeNode *root;

// Create a node
struct BTreeNode *createNode(int val, struct BTreeNode *child) {
  struct BTreeNode *newNode;
  newNode = (struct BTreeNode *)malloc(sizeof(struct BTreeNode));
  newNode->val[1] = val;
  newNode->count = 1;
  newNode->link[0] = root;
  newNode->link[1] = child;
  return newNode;
}

// Insert node
void insertNode(int val, int pos, struct BTreeNode *node,
        struct BTreeNode *child) {
  int j = node->count;
  while (j > pos) {
    node->val[j + 1] = node->val[j];
    node->link[j + 1] = node->link[j];
    j--;
  }
  node->val[j + 1] = val;
  node->link[j + 1] = child;
  node->count++;
}

// Split node
void splitNode(int val, int *pval, int pos, struct BTreeNode *node,
         struct BTreeNode *child, struct BTreeNode **newNode) {
  int median, j;

  if (pos > MIN)
    median = MIN + 1;
  else
    median = MIN;

  *newNode = (struct BTreeNode *)malloc(sizeof(struct BTreeNode));
  j = median + 1;
  while (j <= MAX) {
    (*newNode)->val[j - median] = node->val[j];
    (*newNode)->link[j - median] = node->link[j];
    j++;
  }
  node->count = median;
  (*newNode)->count = MAX - median;

  if (pos <= MIN) {
    insertNode(val, pos, node, child);
  } else {
    insertNode(val, pos - median, *newNode, child);
  }
  *pval = node->val[node->count];
  (*newNode)->link[0] = node->link[node->count];
  node->count--;
}

// Set the value
int setValue(int val, int *pval,
           struct BTreeNode *node, struct BTreeNode **child) {
  int pos;
  if (!node) {
    *pval = val;
    *child = NULL;
    return 1;
  }

  if (val < node->val[1]) {
    pos = 0;
  } else {
    for (pos = node->count;
       (val < node->val[pos] && pos > 1); pos--)
      ;
    if (val == node->val[pos]) {
      printf("Duplicates are not permitted\n");
      return 0;
    }
  }
  if (setValue(val, pval, node->link[pos], child)) {
    if (node->count < MAX) {
      insertNode(*pval, pos, node, *child);
    } else {
      splitNode(*pval, pval, pos, node, *child, child);
      return 1;
    }
  }
  return 0;
}

// Insert the value
void insert(int val) {
  int flag, i;
  struct BTreeNode *child;

  flag = setValue(val, &i, root, &child);
  if (flag)
    root = createNode(i, child);
}

// Search node
void search(int val, int *pos, struct BTreeNode *myNode) {
  if (!myNode) {
    return;
  }

  if (val < myNode->val[1]) {
    *pos = 0;
  } else {
    for (*pos = myNode->count;
       (val < myNode->val[*pos] && *pos > 1); (*pos)--)
      ;
    if (val == myNode->val[*pos]) {
      printf("%d is found", val);
      return;
    }
  }
  search(val, pos, myNode->link[*pos]);

  return;
}

// Traverse then nodes
void traversal(struct BTreeNode *myNode) {
  int i;
  if (myNode) {
    for (i = 0; i < myNode->count; i++) {
      traversal(myNode->link[i]);
      printf("%d ", myNode->val[i + 1]);
    }
    traversal(myNode->link[i]);
  }
}

int main() {
  int val, ch;

  insert(8);
  insert(9);
  insert(10);
  insert(11);
  insert(15);
  insert(16);
  insert(17);
  insert(18);
  insert(20);
  insert(23);

  traversal(root);

  printf("\n");
  search(11, &ch, root);
}
6. B树的搜索复杂度

    最坏情况时间复杂度:Θ(log n)
    平均情况时间复杂度:Θ(log n)
    最佳情况时间复杂度:Θ(log n)
    平均情况空间复杂度:Θ(n)
    最差情况空间复杂度:Θ(n)

7. B树应用
  • 数据库和文件系统
  • 存储数据块(辅助存储介质)
  • 多级索引
参考文档

[1]Parewa Labs Pvt. Ltd.B-tree[EB/OL].https://www.programiz.com/dsa/b-tree,2020-01-01.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值