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.mzph.cn/news/622488.shtml

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

相关文章

怎么使用好爬虫IP代理?爬虫代理IP有哪些使用技巧?

在互联网时代&#xff0c;爬虫技术被广泛应用于数据采集和处理。然而&#xff0c;在使用爬虫技术的过程中&#xff0c;经常会遇到IP被封禁的问题&#xff0c;这给数据采集工作带来了很大的困扰。因此&#xff0c;使用爬虫IP代理成为了解决这个问题的有效方法。本文将介绍如何使…

Java中泛型和Object类型 初级进阶教程(一)

在学习的过程中&#xff0c;常常看到某个类或者接口等中使用 List<T>, Test<T>&#xff0c;其中<T>的作用是什么呢&#xff1f; 1 在类中使用泛型 public class Box<T> {private T content;public void setContent(T content) {this.content conten…

深度学习与药物发现在健康衰老中的应用

深度学习是一种模拟人脑神经网络处理信息的方法&#xff0c;其已在语音、图像、自然语言等处理中发挥了巨大作用。但在健康衰老这一领域的应用中&#xff0c;它面临着很多挑战。 首先&#xff0c;健康衰老是一个复杂的生物学过程&#xff0c;涉及众多因素&#xff0c;如基因、…

Linux———top命令详解(狠狠爱住)

top 命令 是一个常用的系统性能监测工具&#xff0c;它可以实时显示系统中各个进程的状态和资源占用情况。 启动 top 命令&#xff1a; 直接在终端输入 top 命令即可启动。默认情况下&#xff0c;top 显示的是按照 CPU 使用率排序的进程列表。 功能键说明&#xff1a; h&…

【redis基础1】基础数据类型详解和应用案例

博客计划 &#xff0c;我们从redis开始&#xff0c;主要是因为这一块内容的重要性不亚于数据库&#xff0c;但是很多人往往对redis的问题感到陌生&#xff0c;所以我们先来研究一下。 本篇&#xff0c;我们先看一下redis的基础数据类型详解和应用案例。 1.redis概述 以mysql为…

文章测试测试

系列文章目录 提示&#xff1a;这里可以添加系列文章的所有文章的目录&#xff0c;目录需要自己手动添加 例如&#xff1a;第一章 Python 机器学习入门之pandas的使用 提示&#xff1a;写完文章后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目…

xtu oj 1340 wave

题目描述 一个n列的网格&#xff0c;从(0,0)网格点出发&#xff0c;波形存在平波(从(x,y)到(x1,y))&#xff0c;上升波(从(x,y)到(x1,y1))&#xff0c;下降波(从(x,y)到(x1,y−1))三种波形&#xff0c;请问从(0,0)出发&#xff0c;最终到达(n,0)的不同波形有多少种&#xff1f…

C++PythonC# 三语言OpenCV从零开发(1):环境配置

文章目录 前言课程选择环境配置PythonC#COpenCV官网下载新建C项目测试运行Csharp版Python版 gitee仓库总结 前言 由于老王我想转机器视觉方向的上位机行业&#xff0c;我就打算开始从零学OpenCV。但是目前OpenCV有两个官方语言&#xff0c;C和Pyhont。C# 有大佬做了对应的Open…

快速幂板子

快速幂是快速算 a 的 c 次幂 原理&#xff1a; 我们用分治思想是比一个一个乘快的 即比如我们求a的8次方 &#xff1a;a1*a1 a2 ,那么我们直接a2*a2 a4&#xff0c;a4*a4 a8 参数就是几次幂。返回值是对应参数的幂 &#xff08;这里对p取余了&#xff09;(一般也把a当参数…

vue 自定义网页图标 favicon.ico 和 网页标题

效果预览 1. 添加配置 vue.config.js 在 module.exports { 内添加 // 自定义网页图标pwa: {iconPaths: {favicon32: "./favicon.ico",favicon16: "./favicon.ico",appleTouchIcon: "./favicon.ico",maskIcon: "./favicon.ico",msTil…

Java进阶第一天

Java进阶第一天 文章目录 Java进阶第一天双列集合特点Map的常见APIMap集合的遍历方式 双列集合 特点 双列集合一次需要存一对数据,分别是键和值(键值对)键不能重复,值可以重复键和值一一对应 Map的常见API Map是双列集合的顶层接口,它的功能是全部双列集合都可以继承使用的…

memory泄露分析方法(java篇)

#memory泄露主要分为java和native 2种&#xff0c;本文主要介绍java# 测试每天从monkey中筛选出内存超标的app&#xff0c;提单流转到我 首先&#xff0c;辨别内存泄露类型&#xff08;java&#xff0c;还是native&#xff09; 从采到的dumpsys_meminfo_pid看java heap&…

【ROS2】使用C++实现简单的发布订阅方

1 构建自定义数据类型 1、自定义消息类型Student 1.1 创建base_interfaces_demo包 1.2 创建Student.msg文件 string name int32 age float64 height 1.2 在cmakeLists.txt中增加如下语句 #增加自定义消息类型的依赖 find_package(rosidl_default_generators REQUIRED) # 为…

C++ namespace高级用法

高级用法 C++中的命名空间(namespace)是一种用于组织代码的机制,它可以帮助避免命名冲突,并使代码更加清晰和易于维护。以下是C++命名空间的一些高级用法: 嵌套命名空间:命名空间可以嵌套在其他命名空间中,形成一个层次结构。嵌套命名空间可以进一步细化命名空间,使其更…

k8s operator从0到1实践

文章目录 环境准备一个k8s集群开发工具包mac安装 实践初始化operator项目核心逻辑编写测试验证验证 部署 参考 环境准备 一个k8s集群 推荐使用docker-desktop&#xff0c;本地单机集群 开发工具包 这里推荐使用脚手架工具kubebuilder 使用脚手架工具&#xff0c;能生成项目…

Java基础-常量,变量,数据类型-笔记

1.关键字分类 用于定义数据类型的关键字&#xff1a;class&#xff0c;interface&#xff0c;enum&#xff0c;byte&#xff0c;short&#xff0c;int&#xff0c;long&#xff0c;float&#xff0c;double&#xff0c;char&#xff0c;boolean,void。 用于定义流程控制的关键字…

「微服务」企业微服务架构

首先&#xff0c;来自Darren的消息是&#xff0c;微服务架构并不是构建大规模企业应用程序的新方式。Netflix和亚马逊等公司已经实施了微服务架构&#xff0c;在过去几年中提供了成功的产品。 但是微服务架构适合您的组织吗&#xff1f;答案不是简单的是或否&#xff0c;但我会…

【Vue样式绑定详细介绍】

Vue样式绑定详细介绍 1. 样式绑定2. 字符串语法3. 对象语法4. 数组语法4. 自动添加前缀5. 多重值 (2.x的.9版本或3.x) 1. 样式绑定 在Vue中&#xff0c;样式绑定是通过 v-bind:style 或简写 :style 来实现的&#xff0c;它允许你将多种样式动态地绑定到元素上&#xff0c;样式…

Atcoder beginner contest 336 -- D -- Pyramid

目录 D -- Pyramid: 题目大意&#xff1a; 思路解析&#xff1a; 代码实现&#xff1a; D -- Pyramid: 题目大意&#xff1a; 给你一个长度为n的数组&#xff0c;你可以对这个数组进行以下操作。 操作1&#xff1a;选择任意一个元素&#xff0c;使其值大小减一。 操作2&…

web前端javaScript笔记——(11)DOM

一、DOM简介 DOM简介 <!DOCTYPE html> <head><meta charset"UTF-8"><title></title><style></style><script type"text/javascript">/*宿主对象&#xff0c;由浏览器&#xff0c;运行环境为我们提供的对…