B树:原理、操作及应用

news2024/11/26 14:33:33

B树:原理、操作及应用

  • 一、引言
  • 二、B树概述
    • 1. 定义与性质
    • 2. B树与磁盘I/O
  • 三、B树的基本操作
    • 1. 搜索(B-TREE-SEARCH)
    • 2. 插入(B-TREE-INSERT)
    • 3. 删除(B-TREE-DELETE)
  • 四、B树的C代码实现示例
  • 五、总结

一、引言

在现代计算机科学中,高效的数据存储和检索是许多应用程序成功的关键。B树(B-tree)是一种自平衡的树,它能够保持数据稳定有序,其插入与查询的时间复杂度都是对数级别的,非常适合于磁盘等辅助存储器的存取系统。本文将详细介绍B树的基本原理、基本操作,并通过伪代码和C代码示例来解释其实现。

在这里插入图片描述

二、B树概述

1. 定义与性质

B树是一种多叉树,每个节点可以包含多个关键字和多个子节点。一个m阶的B树(m≥2)满足以下性质:

  • 每个节点至多有m个孩子。
  • 除了根节点外,每个非叶子节点至少有⌈m/2⌉个孩子。
  • 根节点至少有两个孩子,除非它是叶子节点。
  • 所有叶子节点都在同一层,并且不带信息(可以视为外部节点或查找失败的节点)。
  • 非叶子节点包含n个关键字信息(K₁, K₂, …, Kₙ),且满足K₁ < K₂ < … < Kₙ。
  • 非叶子节点的第i个子树中的所有关键字都在K_{i-1}和K_i之间(其中,K₀表示一个比该节点所有关键字都小的值,K_{n+1}表示一个比该节点所有关键字都大的值)。

2. B树与磁盘I/O

由于磁盘I/O操作通常比内存操作慢得多,因此,在设计和实现数据结构时,尽量减少磁盘I/O次数是关键。B树的设计充分考虑了磁盘的存取特性,通过增加树的扇出(即每个节点的子节点数)来降低树的高度,从而减少了查找过程中所需的磁盘I/O次数。

三、B树的基本操作

1. 搜索(B-TREE-SEARCH)

B树的搜索操作与二叉搜索树类似,从根节点开始,根据关键字的大小决定向下搜索的路径,直到找到目标关键字或到达叶子节点为止。以下是B树搜索的伪代码示例:

B-TREE-SEARCH(x, k)
    i = 1
    while i ≤ x.n and k > x.key[i]
        i = i + 1
    if i ≤ x.n and k == x.key[i]
        return (x, i) // 返回包含关键字的节点和关键字在节点中的位置
    elseif x.leaf
        return NIL // 关键字不在树中
    else DISK-READ(x, c[i]) // 读取子节点
        return B-TREE-SEARCH(x.c[i], k) // 递归搜索子树

2. 插入(B-TREE-INSERT)

向B树中插入关键字的过程相对复杂,因为需要维护B树的性质。当向满节点插入新关键字时,需要进行分裂操作。以下是B树插入操作的伪代码框架:

B-TREE-INSERT(T, k)
    r = T.root
    if r.n == 2t - 1 // 根节点满了
        s = ALLOCATE-NODE() // 分配新节点作为根节点的子节点
        T.root = s
        s.leaf = FALSE
        s.n = 0
        s.c[1] = r
        B-TREE-SPLIT-CHILD(s, 1) // 分裂根节点
        B-TREE-INSERT-NONFULL(s, k) // 向非满的新根节点插入关键字
    else
        B-TREE-INSERT-NONFULL(r, k) // 直接向根节点插入关键字

// 辅助过程,向非满节点插入关键字
B-TREE-INSERT-NONFULL(x, k)
    // ... 省略具体实现细节,包括分裂操作等 ...

3. 删除(B-TREE-DELETE)

从B树中删除关键字同样需要维护B树的性质。删除操作可能比插入操作更复杂,因为可能需要合并节点或重新调整关键字。以下是B树删除操作的一个简要描述:

  • 如果要删除的关键字在叶子节点中,直接删除并调整节点大小。
  • 如果要删除的关键字在内部节点中,找到其前驱或后继替代该关键字,并递归删除前驱或后继。
  • 如果删除操作导致节点大小低于最小要求,可能需要从相邻兄弟节点借调关键字,或者合并节点。

四、B树的C代码实现示例

由于完整的B树C代码实现较长且复杂,这里仅提供一个简化的框架和关键部分的代码示例,以便读者理解其实现思路。

首先,我们定义B树节点的结构体和一些辅助函数:

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

#define MAX_KEYS 5
#define MAX_CHILDREN 6

typedef int KeyType;

typedef struct BTreeNode {
    int n; // 关键字数量
    KeyType keys[MAX_KEYS]; // 关键字数组
    struct BTreeNode *children[MAX_CHILDREN]; // 子节点指针数组
    bool is_leaf; // 是否为叶子节点
} BTreeNode;

// 创建新节点
BTreeNode* createNode(bool is_leaf) {
    BTreeNode* node = (BTreeNode*)malloc(sizeof(BTreeNode));
    node->n = 0;
    node->is_leaf = is_leaf;
    for (int i = 0; i < MAX_CHILDREN; i++) {
        node->children[i] = NULL;
    }
    return node;
}

// 分裂节点
void splitNode(BTreeNode* parent, int index, BTreeNode* child) {
    // 创建新节点,并分配中间关键字之后的元素
    BTreeNode* newNode = createNode(child->is_leaf);
    newNode->is_leaf = child->is_leaf;
    int mid = MAX_KEYS / 2;

    for (int i = mid + 1; i <= MAX_KEYS; i++) {
        newNode->keys[newNode->n] = child->keys[i];
        newNode->n++;
    }

    if (!child->is_leaf) {
        for (int i = mid + 1; i <= MAX_CHILDREN; i++) {
            newNode->children[newNode->n] = child->children[i];
            newNode->n++;
        }
    }

    // 将中间关键字上升到父节点
    parent->keys[index] = child->keys[mid];
    child->n = mid;

    // 插入新节点为父节点的一个子节点
    for (int i = parent->n; i > index; i--) {
        parent->keys[i] = parent->keys[i - 1];
        parent->children[i + 1] = parent->children[i];
    }
    parent->children[index + 1] = newNode;
    parent->n++;
}

// 插入非满节点
void insertNonFull(BTreeNode* node, KeyType key) {
    int i = node->n - 1;

    // 找到新关键字的插入位置
    while (i >= 0 && key < node->keys[i]) {
        node->keys[i + 1] = node->keys[i];
        i--;
    }

    node->keys[i + 1] = key;
    node->n++;
}

// B树插入操作
void insert(BTreeNode** root, KeyType key) {
    BTreeNode* node = *root;

    // 如果树为空,创建一个新节点
    if (node == NULL) {
        *root = createNode(true);
        insertNonFull(*root, key);
        return;
    }

    BTreeNode* current = node;
    BTreeNode* parent = NULL;
    int index = 0;

    // 查找插入位置
    while (!current->is_leaf) {
        index = 0;
        while (index < current->n && key > current->keys[index]) {
            index++;
        }
        parent = current;
        current = current->children[index];
    }

    // 插入到叶子节点
    insertNonFull(current, key);

    // 检查是否需要分裂
    while (current->n == MAX_KEYS + 1) {
        splitNode(parent, index, current);

        if (parent == NULL) {
            // 根节点满了,创建一个新的根节点
            *root = createNode(false);
            (*root)->children[0] = node;
            splitNode(*root, 0, node);
            return;
        }

        index = 0;
        while (parent->keys[index] < current->keys[0]) {
            index++;
        }

        current = parent;
        parent = parent->children[0] == current ? NULL : current->children[index + 1];
    }
}

// 主函数,用于测试
int main() {
    BTreeNode* root = NULL;

    // 插入一些关键字进行测试
    insert(&root, 10);
    insert(&root, 20);
    insert(&root, 5);
    insert(&root, 15);
    insert(&root, 7);
    // ... 可以继续插入其他关键字进行测试 ...

    // 这里可以添加代码来遍历和打印B树的内容,以验证插入操作的正确性

    return 0;
}

这个示例代码实现了B树的插入操作,包括节点的分裂和根节点的提升。请注意,这个代码是为了教学目的而简化的,并没有处理所有的边界情况,也没有实现删除和查找等操作。在实际应用中,还需要进一步完善和优化。

五、总结

B树作为一种高效的数据结构,广泛应用于数据库和文件系统的索引中。其自平衡的特性保证了高效的插入、删除和搜索操作,尤其适用于磁盘等辅助存储器的存取系统。通过伪代码和C代码示例的介绍,我们可以更深入地理解B树的原理和实现细节。在实际应用中,根据具体需求和场景,可以对B树进行适当的变种和优化,以进一步提高其性能。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1639401.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

selenium 4.x 之验证码处理(python)

验证码处理 一般情况公司如果涉及web自动化测试需要对验证码进行处理的方式一般有一下几种&#xff1a; 关闭验证码功能&#xff08;开发处理&#xff09;设置万能验证码&#xff08;开发处理&#xff09;使用智能识别库进行验证 通过第三方打码平台识别验证码 1. 跳过验证功…

[基础] Unity Shader:顶点着色器(vert)函数

顶点着色器&#xff08;Vertex Shader&#xff09;是图形渲染的第一个阶段&#xff0c;它的输入来自于CPU。顶点着色器的处理单位是顶点&#xff0c;CPU输入进来的每个顶点都会调用一次顶点着色器函数&#xff0c;也就是我们在Shader代码里所定义的vert函数。本篇我们将会通过顶…

uniapp+vue社区车位预订租赁系统 微信小程序

本私家车位共享系统有管理员&#xff0c;用户两个角色。管理员可以对用户信息&#xff0c;车辆类型信息进行管理&#xff0c;并且可以审核用户提交的租赁订单&#xff0c;用户可以注册登录&#xff0c;新增车辆信息&#xff0c;查看车位信息并且租赁&#xff0c;并且可以支付。…

SQL 基础 | UNION 用法介绍

在SQL中&#xff0c;UNION操作符用于合并两个或多个SELECT语句的结果集&#xff0c;形成一个新的结果集。 使用UNION时&#xff0c;合并的结果集列数必须相同&#xff0c;并且列的数据类型也需要兼容。 默认情况下&#xff0c;UNION会去除重复的行&#xff0c;只保留唯一的行。…

企业计算机服务器中了lockbit勒索病毒如何处理,lockbit勒索病毒解密流程建议

在虚拟的网络世界里&#xff0c;人们利用网络获取信息的方式有很多&#xff0c;网络为众多企业提供了极大便利性&#xff0c;也大大提高了企业生产运营效率&#xff0c;方便企业开展各项工作业务。但随着网络技术的不断发展与应用&#xff0c;越来越多的企业开始关注企业网络数…

06 - metastore服务、hive服务启动脚本以及相关使用技巧

目录 1、metastore服务 1.1、metastore运行模式 1.2、metastore部署 1.3、测试 2、编写Hive服务启动脚本 3、Hive使用技巧 3.1、Hive常用交互命令 3.2、Hive参数配置方式 3.3、Hive常见属性配置 1、metastore服务 Hive的metastore服务的作用是为Hive CLI或者Hiveserv…

linux内核源码分析--核心网络文件和目录

图3-2显示了在/proc/sys中由网络代码所使用的主要目录&#xff0c;就每个目录而言&#xff0c;都列出了在哪一章描述其文件。 proc/sys/net bridge ipv4 core route neigh conf 图3-2/proc/sys/net 中的核心目录 根据前借所述&#xff0c;我们来看net中的树根是如何定义的&…

SpringCloudAlibaba:3.1dubbo

dubbo 概述 简介 Apache Dubbo 是一款 RPC 服务开发框架&#xff0c;用于解决微服务架构下的服务治理与通信问题 官方提供了 Java、Golang、Rust 等多语言 SDK 实现 Dubbo的开源故事 最早在2008年&#xff0c;阿里巴巴就将Dubbo捐献到开源社区&#xff0c;它很快成为了国内开源…

R语言的学习—5—多元数据直观表示

1、数据读取 ## 数据整理 d3.1read.xlsx(adstats.xlsx,d3.1,rowNamesT);d3.1 #读取adstats.xlsx表格d3.1数据 barplot(apply(d3.1,1,mean)) #按行做均值条形图 barplot(apply(d3.1,1,mean),las3) barplot(apply(d3.1,2,mean)) #按列做均值图条形图 barplot(a…

JavaEE >> Spring MVC(1)

MVC MVC&#xff1a;Model View Controller 的缩写&#xff0c;是一种软件架构模式&#xff0c;将软件系统分为模型、视图和控制器三个部分。 Mode&#xff08;模型&#xff09;&#xff1a;是应⽤程序中⽤于处理应⽤程序数据逻辑的部分。通常模型对象负责在数据库中存取数据…

【C++STL详解(五)】--------list的介绍与使用

目录 前言 一、list的介绍 二、list的使用 Ⅰ.默认成员函数 1、构造函数 2、赋值重载 3、析构函数 Ⅱ、容量 1.size() Ⅲ、迭代器与遍历 1.beginend (正向迭代器) 2.rbeginrend (反向迭代器) 3.front 4.back Ⅳ、增删查改 1.push_front 2.pop_front 3.push_b…

【跟马少平老师学AI】-【神经网络是怎么实现的】(九)长短期记忆网络

一句话归纳&#xff1a; 1&#xff09;RNN也会存在梯度消失的问题。 2&#xff09;同一句话&#xff0c;对于不同的任务&#xff0c;句中不同的词起的作用也不一样。 3&#xff09;LSTM&#xff08;长短期记忆&#xff09;子网络&#xff1a; 门&#xff0c;让输入经过运算&…

目标检测算法YOLOv4简介

YOLOv4由Alexey Bochkovskiy等人于2020年提出&#xff0c;论文名为&#xff1a;《YOLOv4: Optimal Speed and Accuracy of Object Detection》&#xff0c;论文见&#xff1a;https://arxiv.org/pdf/2004.10934 &#xff0c;GitHub Code&#xff1a;https://github.com/AlexeyA…

05_机器学习赛事_优惠券使用预测

1. 函数库导入 # import libraries necessary for this project import os, sys, pickleimport numpy as np import pandas as pdimport matplotlib.pyplot as plt import matplotlib.dates as mdatesimport seaborn as sns import datetime as dtfrom datetime import datefr…

webm视频转mp4,webm视频格式转换,6个方法介绍!

如何把webm格式转换成mp4&#xff1f;随着生活节奏的加快&#xff0c;视频的应用范围愈发广泛&#xff0c;我们较常见于短视频平台、网站页面等等。同样的&#xff0c;视频已经成为当前分享信息、传播信息的关键工具之一。在技术不断革新的基础上&#xff0c;视频技术也在不断完…

C++深度解析教程笔记4

C深度解析教程笔记4 第7课 - 函数参数的扩展实验-默认参数实验-从右提供的默认参数实验-默认值与占位参数结合小结 第8课 - 函数重载分析&#xff08;上&#xff09;实验-函数重载实验-有歧义的重载实验-重载函数是同一函数吗查看vs2010的obj文件的符号表 小结 第9课 - 函数重载…

How a window is added to windowmanager when you start an activity

finally call mWindowSession.addToDisplayAsUser how surfacecontrol is showed when you start an activity

Redis教程——事务

在上篇文章我们学习了Redis教程——持久化&#xff08;AOF&#xff09;&#xff0c;这篇文章我们学习Redis教程——事务。 Redis事务 事务是一组操作的集合&#xff0c;它是一个不可分割的工作单位&#xff0c;事务会把所有的操作作为一个整体一起向系统提交或撤销操作请求&a…

ROS1快速入门学习笔记 - 014launch启动文件的使用方法

一、定义 Launch文件&#xff1a;通过XML文件实现多节点的配置和启动&#xff08;可自动启动ROSMaster&#xff09; 二、常用语法 1. 根标签 <launch> - launch文件中的根元素采用<launch>标签定义 <launch>表示开始&#xff1b;<launch>表示结束&…

搜狗输入法自动切换双拼方案

解决方法&#xff0c; 安装 13.2.0 &#xff0c; to be verified SGSRv13206899_搜狗输入法13.2.0 需要关闭自动升级