c语言实现b树

概述:B 树(B-tree)是一种自平衡的搜索树数据结构,广泛应用于数据库和文件系统等领域。它的设计旨在提供一种高效的插入、删除和查找操作,同时保持树的平衡,确保各个节点的深度相差不大。

B 树的特点包括:

  1. 平衡性: 所有叶子节点到根节点的路径长度相等,确保在查找、插入和删除等操作时,各个节点的访问次数相对均衡,提高了性能。

  2. 多路搜索: B 树每个内部节点可以有多个子节点,这是与二叉搜索树的主要区别。每个节点包含多个关键字和对应的子树,这样可以减少树的高度,提高检索效率。

  3. 节点存储多个关键字: 每个节点可以存储多个关键字,而不仅仅是一个。这样可以提高每个节点的利用率,减少磁盘 I/O 次数。

  4. 自调整: 在插入和删除操作时,B 树会自动调整其结构以保持平衡。这通过节点分裂和合并的方式来实现。

B 树的阶数(order)是一个重要的概念,它表示一个节点最多可以包含的子节点数(或关键字数)。通常,B 树的阶数会根据具体的使用场景进行调整,以满足性能和空间的需求。

B 树广泛应用于数据库系统中,作为索引结构,因为它能够高效地支持范围查询、插入和删除操作。同时,B 树也被用于文件系统,以加速文件的检索和访问。

完整代码:

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

// B 树的阶数
#define ORDER 3

// B 树节点结构
typedef struct BTreeNode {
    int leaf; // 是否是叶子节点
    int n;    // 当前关键字数量
    int keys[ORDER - 1]; // 关键字数组
    struct BTreeNode* child[ORDER]; // 子节点数组
} BTreeNode;

// 创建新节点
BTreeNode* createNode() {
    BTreeNode* newNode = (BTreeNode*)malloc(sizeof(BTreeNode));
    newNode->leaf = 1;
    newNode->n = 0;
    for (int i = 0; i < ORDER - 1; ++i) {
        newNode->keys[i] = 0;
    }
    for (int i = 0; i < ORDER; ++i) {
        newNode->child[i] = NULL;
    }
    return newNode;
}

// 分裂节点
void splitChild(BTreeNode* parent, int index, BTreeNode* child) {
    BTreeNode* newNode = createNode();
    newNode->leaf = child->leaf;
    newNode->n = ORDER / 2 - 1;

    // 将 child 中的一半关键字移动到 newNode 中
    for (int i = 0; i < ORDER / 2 - 1; ++i) {
        newNode->keys[i] = child->keys[i + ORDER / 2];
    }

    // 如果 child 不是叶子节点,将一半子节点移动到 newNode 中
    if (!child->leaf) {
        for (int i = 0; i < ORDER / 2; ++i) {
            newNode->child[i] = child->child[i + ORDER / 2];
            child->child[i + ORDER / 2] = NULL;
        }
    }

    // 调整 child 的关键字数量
    child->n = ORDER / 2 - 1;
    newNode->n = ORDER / 2 - 1;

    // 将 parent 中的一个关键字和 newNode 相关的子节点插入到 parent 中
    for (int i = parent->n; i > index; --i) {
        parent->keys[i] = parent->keys[i - 1];
        parent->child[i + 1] = parent->child[i];
    }
    parent->keys[index] = child->keys[ORDER / 2 - 1];
    parent->child[index + 1] = newNode;

    // 调整 parent 的关键字数量
    parent->n++;

    // 将 parent 中的一个关键字插入到 child 中
    child->keys[ORDER / 2 - 1] = 0;
    child->child[ORDER / 2] = NULL;
}

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

    // 如果是叶子节点,直接插入
    if (node->leaf) {
        while (i >= 0 && key < node->keys[i]) {
            node->keys[i + 1] = node->keys[i];
            i--;
        }
        node->keys[i + 1] = key;
        node->n++;
    } else {
        // 如果是内部节点,找到要插入的子节点
        while (i >= 0 && key < node->keys[i]) {
            i--;
        }
        i++;

        // 如果子节点已满,先分裂再插入
        if (node->child[i]->n == ORDER - 1) {
            splitChild(node, i, node->child[i]);
            if (key > node->keys[i]) {
                i++;
            }
        }

        // 递归插入子节点
        insertNonFull(&(node->child[i]), key);
    }
}

// 插入关键字
void insert(BTreeNode** root, int key) {
    BTreeNode* node = *root;

    // 如果树为空,创建一个新节点作为根
    if (!node) {
        *root = createNode();
        (*root)->keys[0] = key;
        (*root)->n = 1;
        return;
    }

    // 如果根节点已满,先分裂再插入
    if (node->n == ORDER - 1) {
        BTreeNode* newRoot = createNode();
        newRoot->leaf = 0;
        newRoot->child[0] = *root;
        *root = newRoot;
        splitChild(newRoot, 0, node);
        insertNonFull(root, key);
    } else {
        insertNonFull(root, key);
    }
}



// 打印 B 树
void printBTree(BTreeNode* node, int level) {
    if (node) {
        printf("Level %d: ", level);
        for (int i = 0; i < node->n; ++i) {
            printf("%d ", node->keys[i]);
        }
        printf("\n");

        if (!node->leaf) {
            for (int i = 0; i <= node->n; ++i) {
                printBTree(node->child[i], level + 1);
            }
        }
    }
}

int main() {
    BTreeNode* root = NULL;

    // 插入一些关键字
    insert(&root, 3);
    insert(&root, 7);
    insert(&root, 2);
    insert(&root, 9);
    insert(&root, 1);
    insert(&root, 6);
    insert(&root, 4);
    insert(&root, 5);
    insert(&root, 8);

    // 打印 B 树
    printBTree(root, 0);

    return 0;
}

首先定义了B树的阶数ORDER为3,即每个节点最多可以有3个子节点。然后定义了一个B树节点的结构体,包含以下成员:

  • leaf:表示该节点是否为叶子节点,如果是叶子节点则为1,否则为0。
  • n:表示当前节点中关键字的数量。
  • keys:关键字数组,用于存储节点中的关键字。
  • child:子节点数组,用于存储指向子节点的指针。

接下来实现了创建新节点的函数createNode(),用于分配内存并初始化节点的成员变量。

然后实现了分裂节点的函数splitChild(),用于将一个节点分裂成两个节点。分裂过程包括将原节点的一半关键字移动到新节点中,并将原节点的一半子节点移动到新节点中。同时调整原节点的关键字数量和新节点的关键字数量。最后将原节点中的一个关键字和与新节点相关的子节点插入到原节点中,并调整原节点的关键字数量。

接着实现了插入非满节点的函数insertNonFull(),用于在非满节点中插入关键字。如果节点是叶子节点,则直接插入关键字;如果节点是内部节点,则找到要插入的子节点,如果子节点已满,则先分裂再插入。然后递归插入子节点。

最后实现了插入关键字的函数insert(),用于向B树中插入关键字。如果树为空,则创建一个新节点作为根;如果根节点已满,则先分裂再插入。然后调用insertNonFull()函数插入关键字。

最后实现了打印B树的函数printBTree(),用于按层次遍历的方式打印B树的结构。

在main()函数中,创建了一个空的根节点root,然后插入了一些关键字,并调用printBTree()函数打印B树的结构。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

springCloud使用apache的http类和RestTemplate以及Eureka

使用apache的&#xff1a; package com.csgholding.pvgpsp.eqp.util;import com.esotericsoftware.minlog.Log; import org.apache.commons.collections4.MapUtils; import org.apache.http.HttpEntity; import org.apache.http.client.config.RequestConfig; import org.apac…

洛谷 P1439 【模板】最长公共子序列【线性dp+dp模型转换】

原题链接&#xff1a;https://www.luogu.com.cn/problem/P1439 题目描述 给出 1,2,…,n 的两个排列 P1​ 和 P2​ &#xff0c;求它们的最长公共子序列。 输入格式 第一行是一个数 n。 接下来两行&#xff0c;每行为 n 个数&#xff0c;为自然数 1,2,…,n 的一个排列。 输…

1359 · 有序数组转换为二叉搜索树

链接&#xff1a;LintCode 炼码 - ChatGPT&#xff01;更高效的学习体验&#xff01; 题解&#xff1a; ### 解题思路 1.每次随机一个要插入的数字&#xff08;避免搜索树过度不平衡&#xff09; 2.插入过的数字&#xff0c;就不在插入了 3.调用Insert1函数进行插入二叉搜索树…

TypeScript进阶(四)声明文件

✨ 专栏介绍 TypeScript是一种由微软开发的开源编程语言&#xff0c;它是JavaScript的超集&#xff0c;意味着任何有效的JavaScript代码都是有效的TypeScript代码。TypeScript通过添加静态类型和其他特性来增强JavaScript&#xff0c;使其更适合大型项目和团队开发。 在TypeS…

AI副业拆解:随心所欲地替换任何内容

在瞬息万变的世界里&#xff0c;保持“物体ID”的核心特质&#xff0c;同时创造无限可能的新内容&#xff0c;这是一场市场需求与技术挑战的双重交响。此刻&#xff0c;为您揭开一款颠覆性创新产品——ReplaceAnything框架。 直击痛点&#xff0c;破茧成蝶&#xff0c;Replace…

有趣的事,讲给有趣的人听

哈哈哈&#xff0c;今天不写技术了&#xff0c;今天分享一下生活&#xff0c;技术我们什么时候都可以学&#xff0c;但是生活更值得我们现在就去更好的体验&#xff01; 两年多的涤生大数据&#xff0c;认识了形形色色的小伙伴&#xff0c;陆续沟通下来6000多人&#xff0c;彼时…

Vue框架入门基础知识

什么是Vue&#xff1f; Vue 是一套前端框架&#xff0c;免除原生JavaScript中的DOM操作&#xff0c;简化书写 框架:是一个半成品软件&#xff0c;是一套可重用的、通用的、软件基础代码模型。基于框架进行开发&#xff0c;更加快捷、更加高效。 基于MVVM(Model-View-ViewModel…

看完这篇带你了解大学生必考安全证书NISP详解

NISP证书详解 NISP证书介绍&#xff1a;NISP证书等级&#xff1a;NISP&#xff08;一级&#xff09;报名&#xff1a;NISP&#xff08;一级&#xff09;课程大纲&#xff1a;NISP&#xff08;二级&#xff09;报名NISP&#xff08;二级&#xff09;课程大纲NISP二级置换CISP指南…

Java中的泛型

泛型 什么是泛型泛型类泛型接口泛型方法通配符泛型的上下限 泛型的注意事项擦除问题基本数据类型问题 什么是泛型 定义类、接口、方法时&#xff0c;同时声明了一个或者多个类型变量&#xff08;如&#xff1a;&#xff09;&#xff0c;称为泛型类、泛型接口&#xff0c;泛型方…

说说TCP 3次握⼿和4次握手

三次握手过程 client端建⽴连接&#xff0c;发送⼀个SYN同步包&#xff0c;发送之后状态变成SYN_SENTserver端收到SYN之后&#xff0c;同意建⽴连接&#xff0c;返回⼀个ACK响应&#xff0c;同时也会给client发送⼀个SYN包&#xff0c;发送完成之后状态变为SYN_RCVDclient端收到…

PySide6/PyQt6中的时间管理类:QTime的使用方法

文章目录 📖 介绍 📖🏡 环境 🏡📒 使用方法 📒📝 创建QTime对象📝 常用方法⚓️ 相关链接 ⚓️📖 介绍 📖 QTime是PySide6中用于处理时间段的类,可以用来表示一天中的时间,例如小时、分钟和秒。它提供了许多操作和格式化时间的功能,使得处理时间变得更加…

MATLAB中simulink中scope同时显示两个输入信号

在使用scope时&#xff0c;需要两个输入信号的设置方法 1.点开scope图标 2 点击设置按钮&#xff0c; 然后弹出configuration properties&#xff1a;scope配置图&#xff0c;在Main选项下&#xff0c;在Number of input ports&#xff1a;1这里面更改数字&#xff0c;需要几…

vscode中如何解决 Comments are not permitted(JSON中不允许注释)

vs code中如何解决Comments are not permitted&#xff08;JSON中不允许注释&#xff09;&#xff1f; 简单几步&#xff0c;让你轻松解决。 1.使用vscode打开json文件后&#xff0c;一些注释显示如图所示&#xff0c;有红色波浪线&#xff0c;影响阅读 2. 悬浮在波浪线报错信…

【MySQL】mysql集群

文章目录 一、mysql日志错误日志查询日志二进制日志慢查询日志redo log和undo log 二、mysql集群主从复制原理介绍配置命令 读写分离原理介绍配置命令 三、mysql分库分表垂直拆分水平拆分 一、mysql日志 MySQL日志 是记录 MySQL 数据库系统运行过程中不同事件和操作的信息的文件…

RocketMQ源码阅读-Broker消息接收

RocketMQ源码阅读-Broker消息接收 1. 从单元测试入手2. Broker启动流程3. Broker接收消息4. Broker接收消息时序图5. 小结 Broker接收 Producer发送的消息。 Broker在RocketMQ中也是一个独立的Model&#xff0c;rocketmq-broker。 Broker的核心类为SendMessageProcessor。 …

opencv多张图片实现全景拼接

最近camera项目需要用到全景拼接&#xff0c;故此查阅大量资料&#xff0c;终于将此功能应用在实际项目上&#xff0c;下面总结一下此过程中遇到的一些问题及解决方式&#xff0c;同时也会将源码附在结尾处&#xff0c;供大家参考&#xff0c;本文采用的opencv版本为3.4.12。 首…

一天吃透JVM面试八股文

内容摘自我的学习网站&#xff1a;topjavaer.cn 什么是JVM&#xff1f; JVM&#xff0c;全称Java Virtual Machine&#xff08;Java虚拟机&#xff09;&#xff0c;是通过在实际的计算机上仿真模拟各种计算机功能来实现的。由一套字节码指令集、一组寄存器、一个栈、一个垃圾回…

前端基础知识整理汇总(下)

react 生命周期 React v16.0前的生命周期 初始化(initialization)阶段 此阶段只有一个生命周期方法&#xff1a;constructor。 constructor() 用来做一些组件的初始化工作&#xff0c;如定义this.state的初始内容。如果不初始化 state 或不进行方法绑定&#xff0c;则不需…

Jenkins自动化部署docker

Jenkins自动化部署docker和普通方式构建 docker外挂目录 准备测试服务器docker环境准备jdk环境将上传jar包修改为app.jar对外暴露1000端口启动jar FROM openjdk:8-jdk-alpine ARG JAR_FILE COPY ${JAR_FILE} app.jar EXPOSE 1000 ENTRYPOINT ["java","-jar&q…

spring-boot2.7.8添加swagger

一、新建项目swaggerdemo 二、修改pom.xml 注意修改&#xff1a;spring-boot-starter-parent版本为&#xff1a;2.7.8 添加依赖&#xff1a; springfox-swagger2 springfox-swagger-ui springfox-boot-starter <?xml version"1.0" encoding"UTF-8"…
最新文章