当前位置: 首页 > 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;如文本、数字、日期…...

龙虎榜——20250610

上证指数放量收阴线&#xff0c;个股多数下跌&#xff0c;盘中受消息影响大幅波动。 深证指数放量收阴线形成顶分型&#xff0c;指数短线有调整的需求&#xff0c;大概需要一两天。 2025年6月10日龙虎榜行业方向分析 1. 金融科技 代表标的&#xff1a;御银股份、雄帝科技 驱动…...

观成科技:隐蔽隧道工具Ligolo-ng加密流量分析

1.工具介绍 Ligolo-ng是一款由go编写的高效隧道工具&#xff0c;该工具基于TUN接口实现其功能&#xff0c;利用反向TCP/TLS连接建立一条隐蔽的通信信道&#xff0c;支持使用Let’s Encrypt自动生成证书。Ligolo-ng的通信隐蔽性体现在其支持多种连接方式&#xff0c;适应复杂网…...

SkyWalking 10.2.0 SWCK 配置过程

SkyWalking 10.2.0 & SWCK 配置过程 skywalking oap-server & ui 使用Docker安装在K8S集群以外&#xff0c;K8S集群中的微服务使用initContainer按命名空间将skywalking-java-agent注入到业务容器中。 SWCK有整套的解决方案&#xff0c;全安装在K8S群集中。 具体可参…...

Unity3D中Gfx.WaitForPresent优化方案

前言 在Unity中&#xff0c;Gfx.WaitForPresent占用CPU过高通常表示主线程在等待GPU完成渲染&#xff08;即CPU被阻塞&#xff09;&#xff0c;这表明存在GPU瓶颈或垂直同步/帧率设置问题。以下是系统的优化方案&#xff1a; 对惹&#xff0c;这里有一个游戏开发交流小组&…...

linux 错误码总结

1,错误码的概念与作用 在Linux系统中,错误码是系统调用或库函数在执行失败时返回的特定数值,用于指示具体的错误类型。这些错误码通过全局变量errno来存储和传递,errno由操作系统维护,保存最近一次发生的错误信息。值得注意的是,errno的值在每次系统调用或函数调用失败时…...

【JavaSE】绘图与事件入门学习笔记

-Java绘图坐标体系 坐标体系-介绍 坐标原点位于左上角&#xff0c;以像素为单位。 在Java坐标系中,第一个是x坐标,表示当前位置为水平方向&#xff0c;距离坐标原点x个像素;第二个是y坐标&#xff0c;表示当前位置为垂直方向&#xff0c;距离坐标原点y个像素。 坐标体系-像素 …...

是否存在路径(FIFOBB算法)

题目描述 一个具有 n 个顶点e条边的无向图&#xff0c;该图顶点的编号依次为0到n-1且不存在顶点与自身相连的边。请使用FIFOBB算法编写程序&#xff0c;确定是否存在从顶点 source到顶点 destination的路径。 输入 第一行两个整数&#xff0c;分别表示n 和 e 的值&#xff08;1…...

Redis:现代应用开发的高效内存数据存储利器

一、Redis的起源与发展 Redis最初由意大利程序员Salvatore Sanfilippo在2009年开发&#xff0c;其初衷是为了满足他自己的一个项目需求&#xff0c;即需要一个高性能的键值存储系统来解决传统数据库在高并发场景下的性能瓶颈。随着项目的开源&#xff0c;Redis凭借其简单易用、…...

Spring Security 认证流程——补充

一、认证流程概述 Spring Security 的认证流程基于 过滤器链&#xff08;Filter Chain&#xff09;&#xff0c;核心组件包括 UsernamePasswordAuthenticationFilter、AuthenticationManager、UserDetailsService 等。整个流程可分为以下步骤&#xff1a; 用户提交登录请求拦…...

【把数组变成一棵树】有序数组秒变平衡BST,原来可以这么优雅!

【把数组变成一棵树】有序数组秒变平衡BST,原来可以这么优雅! 🌱 前言:一棵树的浪漫,从数组开始说起 程序员的世界里,数组是最常见的基本结构之一,几乎每种语言、每种算法都少不了它。可你有没有想过,一组看似“线性排列”的有序数组,竟然可以**“长”成一棵平衡的二…...