当前位置: 首页 > news >正文

【高阶数据结构】B树

目录

1.B树

2.B+树和B树的不同

3.B*树


B树较于哈希红黑树的优势:外查找:读取磁盘数据   ; B树的高度更低,对磁盘的进行I/O操作的次数更少(磁盘的性能比内存差得多);

1.B树

1.1.B树的概念:

  1. 根节点至少有两个孩子       (空树除外)
  2. 每个分支节点都包含k-1个关键字和k个孩子,其中 ceil(m/2) ≤ k ≤ m ceil是向上取整函数     (分支节点都是依靠叶节点分裂得到,孩子依靠分裂得到)
  3. 每个叶子节点都包含k-1个关键字,其中 ceil(m/2) ≤ k ≤ m       (叶子节点没有孩子)
  4. 所有的叶子节点都在同一层   (因为分裂向上插入)
  5. 每个节点中的关键字从小到大排列,节点当中k-1个元素正好是k个孩子包含的元素的值域划分  ( 所有左孩子 <  关键字  < 所有右孩子 )
  6. 每个结点的结构为:(n,A0,K1,A1,K2,A2,… ,Kn,An)其中,Ki(1≤i≤n)为关键子,且Ki < Ki+1(1<= i <= n-1)  Ai(0≤i≤n)为指向子树根结点的指针。且Ai所指子树所有结点中的关键字均小于Ki+1。n为结点中关键字的个数,满足ceil(m/2)-1≤n≤m-1。

分裂:所有元素都是插入关键字,孩子是指向的节点指针;数组满了,分裂出brother(new出来)节点将【mid+1,r】拷贝给brother,如果父节点为空就,创建新的父节点,父节点的左边为原数组,有孩子为brother;

#pragma once
#include<iostream>
#include<vector>using namespace std;template<class T, size_t N>
class Node {public:Node(){//孩子最多为N个,关键字比孩子少一个//需要多开辟一个,来判断数组元素满_key.resize(N);_children.resize(N+1, nullptr);_parent = nullptr;_size = 0;}~Node(){}
public://关键字vector<T> _key;//孩子数据vector<Node<T, N>*> _children;//父亲节点Node<T, N>* _parent;//有效个数size_t _size;
};
template<class T, size_t N>
class BTree {
public:typedef Node<T, N> Node;//返回节点和下标pair<Node*, int> Find(T val){Node* parent = nullptr;Node* cur = _root;//找到合适位置,从左向右找 比当前元素大,判断是否有左孩子while (cur){size_t i = 0;while (i < cur->_size){//找到比我大的了if ( val < cur->_key[i] )break;else if ( val > cur->_key[i] )i++;else//元素存在了,退出return make_pair(cur, i);}//保存父亲parent = cur;cur = cur->_children[i];}//不存在,返回父亲和-1return make_pair(parent, -1);}void _Insert(T val, Node* parent, Node* child){int end = parent->_size - 1;//从最后一个元素挪数据while (end >= 0){//目标元素更小,挪if (val < parent->_key[end]){parent->_key[end + 1] = parent->_key[end];parent->_children[end + 2] = parent->_children[end + 1];//挪右孩子end--;}elsebreak;}//合适的插入位置parent->_key[end + 1] = val;parent->_children[end + 2] = child;//右孩子if (child)//指向父亲child->_parent = parent;parent->_size++;}bool Insert(T val){//第一个插入的元素if (_root == nullptr){_root = new Node;_root->_key[0] = val;_root->_size++;}else{//查找是否存在pair<Node*, int> pr = Find(val);if (pr.second >= 0)//元素已存在,不用在插入return false;//该插入的位置Node* parent = pr.first;Node* child = nullptr;_Insert(val, parent, child);while (true){if (parent->_size < N)return true;else//数组满,分离{//分裂 [l, mid-1]   [mid+1, r]int mid = N / 2;size_t i = 0;size_t j = mid + 1;//分离兄弟节点Node* brother = new Node;for (; j < N; j++, i++){brother->_key[i] = parent->_key[j];brother->_children[i] = parent->_children[j];//有孩子节点,brother做新父亲if (parent->_children[j])parent->_children[j]->_parent =  brother;//分裂给兄弟的关键字和孩子置空parent->_children[j] = nullptr;parent->_key[j] = T();}//还有一个右孩子给brotherbrother->_children[i] = parent->_children[j];if (parent->_children[j])parent->_children[j]->_parent = brother;parent->_children[j] = nullptr;//分裂完处理个数;brother->_size = i;parent->_size -= (i + 1);//减去兄弟和中间//中间值向上插入T midKey = parent->_key[mid];parent->_key[mid] = T();//头节点if (parent->_parent == nullptr){_root = new Node;_root->_key[0] = midKey;_root->_children[0] = parent;_root->_children[1] = brother;_root->_size = 1;//孩子的父亲为头parent->_parent = _root;brother->_parent = _root;break;}else{//非头重新插入_Insert(midKey, parent->_parent, brother);//继续循环,看上一层是否满了parent = parent->_parent;}}}}}
public:
private:Node* _root = nullptr;
};

 测试代码:

#include"BTree.h"
void TestBtree()
{int a[] = { 53, 139, 75, 49, 145, 36, 101 };BTree<int, 3> t;for (auto e : a){t.Insert(e);}
}
int main()
{TestBtree();
}

2.B+树和B树的不同

  1. 分支节点的子树指针与关键字个数相同
  2. 分支节点的子树指针p[i]指向关键字值大小在[k[i],k[i+1])区间之间
  3. 所有叶子节点增加一个链接指针链接在一起
  4. 所有关键字及其映射数据都在叶子节点出现

B+树的特性:

  1. 所有关键字都出现在叶子节点的链表中,且链表中的节点都是有序的。
  2. 不可能在分支节点中命中。 
  3. 分支节点相当于是叶子节点的索引,叶子节点才是存储数据的数据层。

3.B*树

B*树是B+树的变形,在B+树的非根和非叶子节点再增加指向兄弟节点的指针。

区别就是分裂方式不同:不同当前节点和下一个兄弟节点都满才分裂,都区1/3构成一个new节点,提高利用率, 最多3/1被浪费;

相关文章:

【高阶数据结构】B树

目录 1.B树 2.B树和B树的不同 3.B*树 B树较于哈希红黑树的优势&#xff1a;外查找&#xff1a;读取磁盘数据 &#xff1b; B树的高度更低&#xff0c;对磁盘的进行I/O操作的次数更少&#xff08;磁盘的性能比内存差得多&#xff09;&#xff1b; 1.B树 1.1.B树的概念&am…...

Android-Framework 应用间跳转时,提供 Android Broadcast 通知

一、环境 高通865 Android 10 二、情景 应用跳转时,通过广播发送源app的包名和目标app的包名 三、代码实现 frameworks/base/services/core/java/com/android/server/wm/ActivityStarter.java -132,6 132,14 import java.io.PrintWriter;import java.text.DateFormat;imp…...

【Javascript】函数返回值的作用

目录 返回值 中断函数 只能写在函数体里面 返回值 function a(){var b3;return b3? 4:5;} console.log(a()); 创建一个函数&#xff0c;给b赋值3&#xff0c; return b3? 4:5; 判断b是不是等于3&#xff0c;如果是就返回4&#xff0c; 如果不是就返回5 中断函数…...

蓝桥杯 Java k倍区间

前缀和的一个神奇算法&#xff0c;这道题暴力是遍历前缀和的差&#xff0c;也就是遍历所有区间和看他是不是能不能正好除尽k 这道题的技巧是将所有前缀和和k求余 按照求余的结果放在一个数组中 那么余数为0的前缀和a一定满足要求&#xff08;[0,a]&#xff09; 余数相同的两两…...

万宾科技亮相2023中国传感器与应用技术大会,创始人CEO发表演讲

10月25日-26日&#xff0c;由厦门市工业和信息化局指导;中国传感器与物联网产业联盟、厦门火炬高技术产业开发区管理委员会主办的2023中国(厦门)传感器与应用技术大会暨展览会在厦门召开。本次展会聚焦传感器与储能、物联网、海洋、智慧生活、城市安全与基础设施的融合&#xf…...

#力扣:LCP 06. 拿硬币@FDDL

LCP 06. 拿硬币 - 力扣&#xff08;LeetCode&#xff09; 一、Java class Solution {public int minCount(int[] coins) {int ans0;for(int i0;i<coins.length;i)ans(coins[i]1)/2;return ans;} }...

【Node.js】暴露自定义响应头和预检请求的时机

1. 暴露自定义响应头 // server.js app.post(/api/user/hello, (req, res) > {res.setHeader(Access-Control-Allow-Origin, *)// 权限设置&#xff08;如果有个多&#xff0c;用 &#xff0c;隔开&#xff09;&#xff0c;暴露给前端res.setHeader(Access-Control-expose-…...

包管理工具与配置文件package.json

1&#xff0c;了解工程化管理核心 1.1 nodejs 理解&#xff1a; 在前端工程化发展中&#xff0c;nodejs的出现让前端开始了工程化&#xff0c;结束了仅静态页和切图的工作。他为前端提供了一个运行环境&#xff0c;让前端彻底变成了一个单独的工程&#xff0c;可以运行、编译…...

uni-app:解决异步请求返回值问题

可以使用 Promise 或者回调函数来处理异步请求的返回值。 方法一&#xff1a; Promise处理异步请求的返回值 使用 Promise 可以将异步请求的结果通过 resolve 和 reject 返回&#xff0c;然后通过 .then() 方法获取成功的结果&#xff0c;通过 .catch() 方法获取错误信息。 …...

<多线程章节七>wait() 和 notify()

&#x1f490;专栏导读 本篇文章收录于多线程&#xff0c;也欢迎翻阅博主的其他文章&#xff0c;可能也会让你有不一样的收获&#x1f604; &#x1f342;JavaSE &#x1f337;多线程 &#x1f33c;数据结构 文章目录 &#x1f490;专栏导读&#x1f490;wait()&#x1f490;no…...

竹云产品入选《2023年度上海市网络安全产业创新攻关成果目录》

为推进网络安全产业发展&#xff0c;建设网络安全产业创新高地&#xff0c;上海市经济和信息化委员会于10月24日正式发布《2023年度上海市网络安全产业创新攻关成果目录》&#xff0c;共评选出16项创新成果&#xff0c;其中包括基础技术创新8项、应用技术创新4项、服务业态创新…...

客户端负载均衡策略:loadBalancer,ribbon

客户端负载均衡是指在分布式系统中&#xff0c;客户端通过某种策略将请求分发到多个服务提供者实例上&#xff0c;以达到负载均衡和提高系统的可用性和性能。 在 Java 生态系统中&#xff0c;Ribbon 是一个常用的客户端负载均衡框架&#xff0c;它是 Netflix 开源的一部分&…...

canvas基础3 -- 交互

点击交互 使用 isPointInPath(x, y) 判断鼠标点击位置在不在图形内 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"&…...

Flutter——最详细(Scaffold)使用教程

Scaffold简介 相当于界面的主体&#xff08;类似于安卓最外层PhoneWindow&#xff09;&#xff0c;组件的展示都必须依附于它。 使用场景&#xff1a; 每一个界面都是脚手架&#xff0c;通过它来进行架构实现&#xff0c;优美的布局效果。 属性作用appBar顶部的标题栏body显示整…...

C语言编写图形化界面-创建按钮-为其指定样式

文章目录 前置章节指定窗口样式给按钮加边框扁平化按钮复选框样式按钮自动复选框 单选按钮三态按钮自动三态按钮 默认按钮样式&#xff08;对话框Enter键&#xff09; 设置按钮位置和大小封装函数 前置章节 开始之前&#xff0c;需要学习以下章节&#xff1a; 创建窗口 窗口过…...

C++并发与多线程(7) | 创建多个线程时数据共享的问题

一、创建和等待多个线程 借助vector存放多个线程thread对象,借助vector和它的迭代器实现创建和运行多个线程,代码如下: #include <iostream> #include <thread> #include <vector> using namespace std;void myprint(int inum) {cout << "mypr…...

进程间通信(匿名管道、命名管道、消息队列、共享内存、信号量、信号、Socket)

文章目录 一、什么是进程间通信二、管道1.匿名管道(pipe)a).创建匿名管道b).管道的读写规则c).匿名管道的特点 2.有名管道(FIFO)a).创建命名管道b).命名管道的特点c).基于命名管道的进程间通信&#xff08;服务端/客户端&#xff09; 三、消息队列四、共享内存1.什么是共享内存…...

浅谈中国汽车充电桩行业市场状况及充电桩选型的介绍

安科瑞虞佳豪 车桩比降低是完善新能源汽车行业配套的一大重要趋势&#xff0c;目前各国政府都在努力推进政策&#xff0c;通过税收减免、建设补贴等措施提升充电桩建设速度&#xff0c;以满足新能源汽车需求。 近年来&#xff0c;在需求和技术的驱动下&#xff0c;充电桩的平…...

Postgresql在jdbc处理bit字段的解决方案

问题&#xff1a; bit如果长度为1&#xff0c;则会默认为布尔型&#xff08;1-true 0-false&#xff09;&#xff1b; bit如果长度大于1&#xff0c;则会默认为bit类型&#xff0c;但是代码中以前常用的两种set方式&#xff0c;会报错 第一种方式&#xff1a; ps.setObject(i1,…...

ESMapping字段

在 Elasticsearch 中&#xff0c;字段&#xff08;field&#xff09;是指用于表示数据的最小单元。每个文档&#xff08;document&#xff09;都由一个或多个字段组成&#xff0c;字段存储了文档的不同属性或数据。 字段可以包含不同的数据类型&#xff0c;如文本、数字、日期…...

进程地址空间(比特课总结)

一、进程地址空间 1. 环境变量 1 &#xff09;⽤户级环境变量与系统级环境变量 全局属性&#xff1a;环境变量具有全局属性&#xff0c;会被⼦进程继承。例如当bash启动⼦进程时&#xff0c;环 境变量会⾃动传递给⼦进程。 本地变量限制&#xff1a;本地变量只在当前进程(ba…...

IGP(Interior Gateway Protocol,内部网关协议)

IGP&#xff08;Interior Gateway Protocol&#xff0c;内部网关协议&#xff09; 是一种用于在一个自治系统&#xff08;AS&#xff09;内部传递路由信息的路由协议&#xff0c;主要用于在一个组织或机构的内部网络中决定数据包的最佳路径。与用于自治系统之间通信的 EGP&…...

STM32F4基本定时器使用和原理详解

STM32F4基本定时器使用和原理详解 前言如何确定定时器挂载在哪条时钟线上配置及使用方法参数配置PrescalerCounter ModeCounter Periodauto-reload preloadTrigger Event Selection 中断配置生成的代码及使用方法初始化代码基本定时器触发DCA或者ADC的代码讲解中断代码定时启动…...

鸿蒙中用HarmonyOS SDK应用服务 HarmonyOS5开发一个医院挂号小程序

一、开发准备 ​​环境搭建​​&#xff1a; 安装DevEco Studio 3.0或更高版本配置HarmonyOS SDK申请开发者账号 ​​项目创建​​&#xff1a; File > New > Create Project > Application (选择"Empty Ability") 二、核心功能实现 1. 医院科室展示 /…...

C++ 求圆面积的程序(Program to find area of a circle)

给定半径r&#xff0c;求圆的面积。圆的面积应精确到小数点后5位。 例子&#xff1a; 输入&#xff1a;r 5 输出&#xff1a;78.53982 解释&#xff1a;由于面积 PI * r * r 3.14159265358979323846 * 5 * 5 78.53982&#xff0c;因为我们只保留小数点后 5 位数字。 输…...

OPENCV形态学基础之二腐蚀

一.腐蚀的原理 (图1) 数学表达式&#xff1a;dst(x,y) erode(src(x,y)) min(x,y)src(xx,yy) 腐蚀也是图像形态学的基本功能之一&#xff0c;腐蚀跟膨胀属于反向操作&#xff0c;膨胀是把图像图像变大&#xff0c;而腐蚀就是把图像变小。腐蚀后的图像变小变暗淡。 腐蚀…...

让回归模型不再被异常值“带跑偏“,MSE和Cauchy损失函数在噪声数据环境下的实战对比

在机器学习的回归分析中&#xff0c;损失函数的选择对模型性能具有决定性影响。均方误差&#xff08;MSE&#xff09;作为经典的损失函数&#xff0c;在处理干净数据时表现优异&#xff0c;但在面对包含异常值的噪声数据时&#xff0c;其对大误差的二次惩罚机制往往导致模型参数…...

力扣热题100 k个一组反转链表题解

题目: 代码: func reverseKGroup(head *ListNode, k int) *ListNode {cur : headfor i : 0; i < k; i {if cur nil {return head}cur cur.Next}newHead : reverse(head, cur)head.Next reverseKGroup(cur, k)return newHead }func reverse(start, end *ListNode) *ListN…...

DiscuzX3.5发帖json api

参考文章&#xff1a;PHP实现独立Discuz站外发帖(直连操作数据库)_discuz 发帖api-CSDN博客 简单改造了一下&#xff0c;适配我自己的需求 有一个站点存在多个采集站&#xff0c;我想通过主站拿标题&#xff0c;采集站拿内容 使用到的sql如下 CREATE TABLE pre_forum_post_…...

规则与人性的天平——由高考迟到事件引发的思考

当那位身着校服的考生在考场关闭1分钟后狂奔而至&#xff0c;他涨红的脸上写满绝望。铁门内秒针划过的弧度&#xff0c;成为改变人生的残酷抛物线。家长声嘶力竭的哀求与考务人员机械的"这是规定"&#xff0c;构成当代中国教育最尖锐的隐喻。 一、刚性规则的必要性 …...