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

磁盘存储链式结构——B树与B+树

        红黑树处理数据都是在内存中,考虑的都是内存中的运算时间复杂度。如果我们要操作的数据集非常大,大到内存已经没办法处理了该怎么办呢?
        试想一下,为了要在一个拥有几十万个文件的磁盘中查找一个文本文件,设计的算法需要读取磁盘(磁盘寻址)上万次还是读取几十次,这是有本质差异的,此时为了降低对外存设备的访问次数,我们就需要新的数据结构来处理这样的问题,B树B+树(n叉树)。

B树、B+树的本质是通过降低树的层高,减少对磁盘访问次数,来提升查询速度,查找复杂度logm(n/m),m是叉的数量

B树与B+树区别与联系

  1. B树所有节点即存储key也存储value,内存中存不下后存磁盘,名称为B-Tree,并没有B-树这种叫法
  2. B+树只有在叶子节点存储数据value(叶子节点放在磁盘中),非叶子节点用来做索引key(非叶子结点在内存中),相比于B树,B+树更适合做磁盘索引,在大数据的存储和查找中使用较多,比如海量图像查找引擎
  3. B树和B+树的结点添加、删除、查询基本相同

B树的性质

  • 每个结点最多有m棵子树。
  • 具有k个子树的非叶结点包含k -1个键。
  • 每个非叶子结点(除了根)具有至少⌈ m/2⌉子树,即最少有⌈ m/2⌉-1个关键字。
  • 如果根不是终端结点,则根结点至少有一个关键字,即至少有2棵子树。【根的关键字取值范围是[1,m-1],子树的取值范围是[2,m]】
  • 所有叶子结点都出现在同一水平,没有任何信息(高度一致)。

B+树的性质

每个结点最多有m棵子树。
如果根不是终端结点,则根结点至少有一个关键字,即至少有2棵子树。【根的关键字取值范围是[1,m-1]】
每个关键字对应一棵子树(与B树的不同),具有k个子树的非叶结点包含k 个键。
每个非叶子结点(除了根)具有至少**⌈ m/2⌉子树**,即最少有**⌈m/2⌉个关键字**。
终端结点包含全部关键字及相应记录的指针,叶结点中将关键字按大小顺序排序,并且相邻叶结点按大小顺序相互链接起来。
所有分支结点(可以视为索引的索引)中金包含他的各个子节点(即下一级的索引块)中关键字最大值,及指向其子结点的指针。

B树与B+树对比

  • 在B+树中,叶结点包含信息,所有非叶结点仅起索引作用,非叶子结点中的每个索引项只是包含了对应子树最大关键字和指向该孩子树的指针,不含有该关键字对应记录的存储地址。
  • 在B+树中,终端结点包含全部关键字及相应记录的指针,即非终端结点出现过的关键字也会在这重复出现一次。而B树是不重复的

一、B树的定义

我们以六叉树为例:我们说的6叉树是指,每个节点最多可拥有的子树个数,6叉树每个节点最多可拥有6颗子树,而每个节点中最多存储5个数据,如下图

至于为什么插入后会是如下图形,如何插入,请观看下面b站视频。

B树(B-树) - 来由, 定义, 插入, 构建_哔哩哔哩_bilibili

//6叉树的定义
#define SUB_M   3struct _btree_node{/*int keys[2 * SUB_M-1];      //最多5个关键字struct _btree_node *childrens[2 * SUB_M];   //最多6颗子树    6叉树*/int *keys;      //5struct _btree_node **childrens;   //6int num;    //实际存储的节点数量 <= M-1int leaf;   //是否为叶子节点
}struct _btree {struct _btree_node *root;
}

二、B树添加结点

B树添加结点,只会添加在叶子结点上,重点是结点满了后,会发生分裂并向父结点上位。

  • 添加的数据都是添加在叶子节点上,不会添加到根节点或中间节点

  • 结点数据个数==M-1(结点满了的情况),发生分裂(把(M-1)/2处数据放到父结点,其他数据分成两个结点)

     

  • 添加U,高度+1


添加结点代码如下:

/*用于结点分裂时创建新结点*/
btree_node *btree_create_node(int leaf){btree_node *node = (btree_node*)calloc(1, sizeof(btree_node));  //malloc需要手动清零,calloc会自动清零,set 0if(node == NULL) return NULL;   //在内存分配的时候一定要判断,当内存不够用的时候,malloc/calloc就会出错node->leaf = leaf;node->keys = calloc(2 * SUB_M -1, sizeof(int));node->childrens = (btree_node**)calloc(2 * SUB_M -1, sizeof(btree_node*));node->num = 0;return node;
}/*删除结点*/
void btree_destory_node(btree_node *node){free(node->childrens);free(node->keys);free(node);
}/*
非根结点分裂、上位:发生在B树添加元素的过程中,结点满了,需要先分裂再添加
btree *T:根节点
btree_node *x:被删除元素的父结点
int idx:位于父结点的第几颗子树
*/
void btree_split_child(btree *T, btree_node *x, int idx){btree_node *y = x->childrens[idx];    //满了的结点node_ybtree_node *z = btree_create_node(y->leaf); //创建分裂后的新结点//zz->num = SUB_M - 1;int i=0;for(i=0; i < SUB_M-1; i++){z->keys[i] = y->keys[SUB_M+i];}if(y->leaf == 0){   //inner 是内结点,子树指针也要copy过去for(i=0; i < SUB_M-1; i++){z->childrens[i] = y->childrens[SUB_M+i];}}//yy->num = SUB_M;//中间元素上位//childrens 子树for(i=x->num; i >= idx+1; i--){             //寻找上为父结点的位置x->childrens[i+1] = x->childrens[i];    //父结点元素后移}x->childrens[i+1] = z;//key   for(i=x->num-1; i >= idx; i--){     //寻找上为父结点的位置x->keys[i+1] = x->keys[i];      //父结点后边元素后移 }x->keys[i] = y->keys[SUB_M];x->num += 1;
}/**/
void btree_insert(btree *T, int key){btree_node *r = T->root;//根节点分裂(根节点满了);创建一个空结点 指向root, if(r->num == 2*SUB_M-1){btree_node *node = btree_create_node(0);T->root = node;node->childrens[0] = r;btree_split_child(T, node, 0);}
}

三、B树删除结点

B树删除结点,删除叶子结点和中间结点类似,重点为向父结点借位再合并操作。

  • 先合并或者借位转换成一个B树可以删除的状态,在进行删除


删除B结点,其中路径中间结点“FI”的关键字数量为(M-1)/2-1个,为了避免以后出现资源不足的现象,需要对"FI"先进行借位合并
 


代码如下:

///b树 删除     void btree_merge(btree *T, btree_node *x, int idx){btree_node *left = x->childrens[idx];btree_node *right = x->childrens[idx+1];left->keys[left->num] = x->keys[idx];int i=0;for(i=0; i<right->num; i++){left->keys[SUB_M+i] = right->keys[i];}if(!left->leaf){    //非叶子结点,要合并孩子结点指针for(i=0; i<SUB_M; i++){left->childrens[SUB_M+i] = right->childrens[i];}}left->num += SUB_M;btree_destory_node(right);//x key前移for(i=idx+1; i < x->num; i++){x->keys[i-1] = x->keys[i];x->childrens[i] = x->childrens[i+1];}
}

四、完整代码

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>#define DEGREE		3
typedef int KEY_VALUE;typedef struct _btree_node {KEY_VALUE* keys;struct _btree_node** childrens;int num;int leaf;
} btree_node;typedef struct _btree {btree_node* root;int t;
} btree;btree_node* btree_create_node(int t, int leaf) {btree_node* node = (btree_node*)calloc(1, sizeof(btree_node));if (node == NULL) assert(0);node->leaf = leaf;node->keys = (KEY_VALUE*)calloc(1, (2 * t - 1) * sizeof(KEY_VALUE));node->childrens = (btree_node**)calloc(1, (2 * t) * sizeof(btree_node*));node->num = 0;return node;
}void btree_destroy_node(btree_node* node) {assert(node);free(node->keys);//free(node->childrens);free(node);
}void btree_create(btree* T, int t) {T->t = t;btree_node* x = btree_create_node(t, 1);T->root = x;
}void btree_split_child(btree* T, btree_node* x, int i) {int t = T->t;btree_node* y = x->childrens[i];btree_node* z = btree_create_node(t, y->leaf);z->num = t - 1;int j = 0;for (j = 0; j < t - 1; j++) {z->keys[j] = y->keys[j + t];}if (y->leaf == 0) {for (j = 0; j < t; j++) {z->childrens[j] = y->childrens[j + t];}}y->num = t - 1;for (j = x->num; j >= i + 1; j--) {x->childrens[j + 1] = x->childrens[j];}x->childrens[i + 1] = z;for (j = x->num - 1; j >= i; j--) {x->keys[j + 1] = x->keys[j];}x->keys[i] = y->keys[t - 1];x->num += 1;}void btree_insert_nonfull(btree* T, btree_node* x, KEY_VALUE k) {int i = x->num - 1;if (x->leaf == 1) {while (i >= 0 && x->keys[i] > k) {x->keys[i + 1] = x->keys[i];i--;}x->keys[i + 1] = k;x->num += 1;}else {while (i >= 0 && x->keys[i] > k) i--;if (x->childrens[i + 1]->num == (2 * (T->t)) - 1) {btree_split_child(T, x, i + 1);if (k > x->keys[i + 1]) i++;}btree_insert_nonfull(T, x->childrens[i + 1], k);}
}void btree_insert(btree* T, KEY_VALUE key) {//int t = T->t;btree_node* r = T->root;if (r->num == 2 * T->t - 1) {btree_node* node = btree_create_node(T->t, 0);T->root = node;node->childrens[0] = r;btree_split_child(T, node, 0);int i = 0;if (node->keys[0] < key) i++;btree_insert_nonfull(T, node->childrens[i], key);}else {btree_insert_nonfull(T, r, key);}
}void btree_traverse(btree_node* x) {int i = 0;for (i = 0; i < x->num; i++) {if (x->leaf == 0)btree_traverse(x->childrens[i]);printf("%C ", x->keys[i]);}if (x->leaf == 0) btree_traverse(x->childrens[i]);
}void btree_print(btree* T, btree_node* node, int layer)
{btree_node* p = node;int i;if (p) {printf("\nlayer = %d keynum = %d is_leaf = %d\n", layer, p->num, p->leaf);for (i = 0; i < node->num; i++)printf("%c ", p->keys[i]);printf("\n");
#if 0printf("%p\n", p);for (i = 0; i <= 2 * T->t; i++)printf("%p ", p->childrens[i]);printf("\n");
#endiflayer++;for (i = 0; i <= p->num; i++)if (p->childrens[i])btree_print(T, p->childrens[i], layer);}else printf("the tree is empty\n");
}int btree_bin_search(btree_node* node, int low, int high, KEY_VALUE key) {int mid;if (low > high || low < 0 || high < 0) {return -1;}while (low <= high) {mid = (low + high) / 2;if (key > node->keys[mid]) {low = mid + 1;}else {high = mid - 1;}}return low;
}//{child[idx], key[idx], child[idx+1]} 
void btree_merge(btree* T, btree_node* node, int idx) {btree_node* left = node->childrens[idx];btree_node* right = node->childrens[idx + 1];int i = 0;/data mergeleft->keys[T->t - 1] = node->keys[idx];for (i = 0; i < T->t - 1; i++) {left->keys[T->t + i] = right->keys[i];}if (!left->leaf) {for (i = 0; i < T->t; i++) {left->childrens[T->t + i] = right->childrens[i];}}left->num += T->t;//destroy rightbtree_destroy_node(right);//node for (i = idx + 1; i < node->num; i++) {node->keys[i - 1] = node->keys[i];node->childrens[i] = node->childrens[i + 1];}node->childrens[i + 1] = NULL;node->num -= 1;if (node->num == 0) {T->root = left;btree_destroy_node(node);}
}void btree_delete_key(btree* T, btree_node* node, KEY_VALUE key) {if (node == NULL) return;int idx = 0, i;while (idx < node->num && key > node->keys[idx]) {idx++;}if (idx < node->num && key == node->keys[idx]) {if (node->leaf) {for (i = idx; i < node->num - 1; i++) {node->keys[i] = node->keys[i + 1];}node->keys[node->num - 1] = 0;node->num--;if (node->num == 0) { //rootfree(node);T->root = NULL;}return;}else if (node->childrens[idx]->num >= T->t) {btree_node* left = node->childrens[idx];node->keys[idx] = left->keys[left->num - 1];btree_delete_key(T, left, left->keys[left->num - 1]);}else if (node->childrens[idx + 1]->num >= T->t) {btree_node* right = node->childrens[idx + 1];node->keys[idx] = right->keys[0];btree_delete_key(T, right, right->keys[0]);}else {btree_merge(T, node, idx);btree_delete_key(T, node->childrens[idx], key);}}else {btree_node* child = node->childrens[idx];if (child == NULL) {printf("Cannot del key = %d\n", key);return;}if (child->num == T->t - 1) {btree_node* left = NULL;btree_node* right = NULL;if (idx - 1 >= 0)left = node->childrens[idx - 1];if (idx + 1 <= node->num)right = node->childrens[idx + 1];if ((left && left->num >= T->t) ||(right && right->num >= T->t)) {int richR = 0;if (right) richR = 1;if (left && right) richR = (right->num > left->num) ? 1 : 0;if (right && right->num >= T->t && richR) { //borrow from nextchild->keys[child->num] = node->keys[idx];child->childrens[child->num + 1] = right->childrens[0];child->num++;node->keys[idx] = right->keys[0];for (i = 0; i < right->num - 1; i++) {right->keys[i] = right->keys[i + 1];right->childrens[i] = right->childrens[i + 1];}right->keys[right->num - 1] = 0;right->childrens[right->num - 1] = right->childrens[right->num];right->childrens[right->num] = NULL;right->num--;}else { //borrow from prevfor (i = child->num; i > 0; i--) {child->keys[i] = child->keys[i - 1];child->childrens[i + 1] = child->childrens[i];}child->childrens[1] = child->childrens[0];child->childrens[0] = left->childrens[left->num];child->keys[0] = node->keys[idx - 1];child->num++;node->keys[idx - 1] = left->keys[left->num - 1];left->keys[left->num - 1] = 0;left->childrens[left->num] = NULL;left->num--;}}else if ((!left || (left->num == T->t - 1))&& (!right || (right->num == T->t - 1))) {if (left && left->num == T->t - 1) {btree_merge(T, node, idx - 1);child = left;}else if (right && right->num == T->t - 1) {btree_merge(T, node, idx);}}}btree_delete_key(T, child, key);}}int btree_delete(btree* T, KEY_VALUE key) {if (!T->root) return -1;btree_delete_key(T, T->root, key);return 0;
}int main() {btree T = { 0 };btree_create(&T, 3);srand(48);int i = 0;char key[27] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";for (i = 0; i < 26; i++) {//key[i] = rand() % 1000;printf("%c ", key[i]);btree_insert(&T, key[i]);}btree_print(&T, T.root, 0);for (i = 0; i < 26; i++) {printf("\n---------------------------------\n");btree_delete(&T, key[25 - i]);//btree_traverse(T.root);btree_print(&T, T.root, 0);}
}

相关文章:

磁盘存储链式结构——B树与B+树

红黑树处理数据都是在内存中&#xff0c;考虑的都是内存中的运算时间复杂度。如果我们要操作的数据集非常大&#xff0c;大到内存已经没办法处理了该怎么办呢&#xff1f; 试想一下&#xff0c;为了要在一个拥有几十万个文件的磁盘中查找一个文本文件&#xff0c;设计的…...

如何批量从sql语句中提取表名

简介 使用的卢易表 的提取表名功能&#xff0c;可以从sql语句中批量提取表名。采用纯文本sql语法分析&#xff0c;无需连接数据库&#xff0c;支持从含非sql语句的文件文件中提取&#xff0c;支持各类数据库sql语法。 特点 快&#xff1a;从成百个文件中提取上千个表名只需1…...

怎么把音频的速度调慢?6个方法调节音频速度

怎么把音频的速度调慢&#xff1f;调慢音频速度不仅可以帮助我们更好地捕捉细节&#xff0c;还能让我们在分析和学习时更加从容。这对于音乐爱好者来说&#xff0c;尤其有助于理解复杂的旋律和和声&#xff0c;使学习过程变得更加高效。而在语言学习中&#xff0c;放慢语速则能…...

K8s-services+pod详解1

一、Service 我们能够利用Deployment创建一组Pod来提供具有高可用性的服务。 虽然每个Pod都会分配一个单独的Pod IP&#xff0c;然而却存在如下两问题&#xff1a; Pod IP 会随着Pod的重建产生变化Pod IP 仅仅是集群内可见的虚拟IP&#xff0c;外部无法访问 这样对于访问这…...

从RNN讲起(RNN、LSTM、GRU、BiGRU)——序列数据处理网络

文章目录 RNN&#xff08;Recurrent Neural Network&#xff0c;循环神经网络&#xff09;1. 什么是RNN&#xff1f;2. 经典RNN的结构3. RNN的主要特点4. RNN存在问题——长期依赖&#xff08;Long-TermDependencies&#xff09;问题 LSTM&#xff08;Long Short-Term Memory&a…...

python:假的身份信息生成模块faker

前言 发现一个有趣的python模块&#xff08;faker&#xff09;&#xff0c;他支持生成多个国家语言下的假身份信息&#xff0c;包含人名、地址、邮箱、公司名、电话号码、甚至是个人简历&#xff01; 你可以拿它做一些自动化测试&#xff0c;或一些跟假数据有关的填充工作。 代…...

spring task的使用场景

spring task 简介 spring task 是spring自带的任务调度框架按照约定的时间执行某个方法的工具&#xff0c;类似于闹钟 应用场景 cron表达式 周和日两者必定有一个是问号 简单案例...

美畅物联丨剖析 GB/T 28181 与 GB 35114:视频汇聚领域的关键协议

我们在使用畅联云平台进行视频汇聚时&#xff0c;经常会用的GB/T 28181协议&#xff0c;前面我们写了关于GB/T 28181的相关介绍&#xff0c;​ 详见《畅联云平台&#xff5c;关于GB28181你了解多少&#xff1f;》。 ​最近也有朋友向我们咨询GB 35114协议与GB/T 28181有什么不同…...

uni-app 开发的应用快速构建成鸿蒙原生应用

uni-app 是一个使用 Vue.js 开发所有前端应用的框架&#xff0c;它支持编译到 iOS、Android、小程序等多个平台。对于 HarmonyOS&#xff08;鸿蒙系统&#xff09;&#xff0c;uni-app 提供了特定的支持&#xff0c;允许开发者构建鸿蒙原生应用。 一、uni-app 对 HarmonyOS 的支…...

代码随想录算法训练营| 669. 修剪二叉搜索树 、 108.将有序数组转换为二叉搜索树 、 538.把二叉搜索树转换为累加树

669. 修剪二叉搜索树 题目 参考文章 思路&#xff1a;这题其实就是删除不符合上下边界的节点。注意&#xff1a;这里删除不符合上下边界节点时&#xff0c;这个不符合上下边界的节点的左或右子树可能存在符合上下边界的节点&#xff0c;所i有每次比较完之后&#xff0c;要继…...

Django模型实现外键自关联

Django模型实现外键自关联 1、场景 省市区、评论 2、模型models.py from django.db import models 资讯评论:资讯,用户,是否取消,时间class CommentInfomation(models.Model):info = models...

Android ViewModel

一问&#xff1a;ViewModel如何保证应用配置变化后能够自动继续存在&#xff0c;其原理是什么&#xff0c;ViewModel的生命周期和谁绑定的? ViewModel 的确能够在应用配置发生变化&#xff08;例如屏幕旋转&#xff09;后继续存在&#xff0c;这得益于 Android 系统的 ViewMod…...

优先算法1--双指针

“一念既出&#xff0c;万山无阻。”加油陌生人&#xff01; 目录 1.双指针--移动零 2.双指针-复写零 ok&#xff0c;首先在学习之前&#xff0c;为了方便大家后面的学习&#xff0c;我们这里需要补充一个知识点&#xff0c;我这里所谓的指针&#xff0c;不是之前学习的带有…...

利用弹性盒子完成移动端布局(第二次实验作业)

需要实现的效果如下&#xff1a; 下面是首先是这个项目的框架&#xff1a; 然后是html页面的代码&#xff1a; <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"wid…...

C# 字符串(string)三个不同的处理方法:IsNullOrEmpty、IsInterned 、IsNullOrWhiteSpace

在C#中&#xff0c;string.IsNullOrEmpty、string.IsInterned 和 string.IsNullOrWhiteSpace 是三个不同的字符串处理方法&#xff0c;它们各自有不同的用途&#xff1a; 1.string.IsNullOrEmpty&#xff1a; 这个方法用来检查字符串是否为null或者空字符串&#xff08;"…...

读书笔记 - 虚拟化技术 - 0 QEMU/KVM概述与历史

《QEMU/KVM源码解析与应用》 - 王强 概述 虚拟化简介 虚拟化思想 David Wheeler&#xff1a;计算机科学中任何问题都可以通过增加一个中间层来解决。 虚拟化思想存在与计算机科学的各个领域。 主要思想&#xff1a;通过分层将底层的复杂&#xff0c;难用的资源虚拟抽象为简…...

常见的负载均衡

1.常见的负载均衡服务 负载均衡服务是分布式系统中用于分配网络流量和请求的关键组件&#xff0c;它可以帮助提高应用程序的可用性、可扩展性和响应速度。以下是一些常用的负载均衡服务&#xff1a; Nginx&#xff1a;一个高性能的Web服务器和反向代理&#xff0c;广泛用于实现…...

利用sessionStorage收集用户访问信息,然后传递给后端

这里只是简单的收集用户的停留时间、页面加载时间、当前页面URL及来源页面&#xff0c;以做示例 <html><head><meta http-equiv"content-type" content"text/html; charsetUTF-8"/><title>测试sessionStorage存储用户访问信息<…...

什么是Qseven?模块电脑(核心板)规范标准简介二

1.概念 Qseven是一种通用的、小尺寸计算机模块标准&#xff0c;适用于需要低功耗、低成本和高性能的应用。 Qseven模块电脑&#xff08;核心板&#xff09;采用230Pin金手指连接器 2.Qseven的起源 Qseven最初是由Congatec、SECO、MSC三家欧洲公司于2008年发起&#xff0c;旨在…...

leetcode数组(三)-有序数组的平方

题目 . - 力扣&#xff08;LeetCode&#xff09; 给你一个按 非递减顺序 排序的整数数组 nums&#xff0c;返回 每个数字的平方 组成的新数组&#xff0c;要求也按 非递减顺序 排序。 例1 输入&#xff1a;nums [-4,-1,0,3,10] 输出&#xff1a;[0,1,9,16,100] 解释&#…...

HCIP-HarmonyOS Application Developer 习题(五)

1、以下哪种原子化布局能力属于自适应变化能力? A. 拉伸 B.占比 C. 隐藏 D.拆行 答案&#xff1a;A 分析&#xff1a;划分为“自适应变化能力”和“自适应布局能力”两类。 其中&#xff0c;自适应变化能力包含了缩放能力和拉伸能力&#xff0c;自适应布局能力包含了隐藏、折…...

【详细教程】如何使用YOLOv11进行图像与视频的目标检测

《博主简介》 小伙伴们好&#xff0c;我是阿旭。专注于人工智能、AIGC、python、计算机视觉相关分享研究。 ✌更多学习资源&#xff0c;可关注公-仲-hao:【阿旭算法与机器学习】&#xff0c;共同学习交流~ &#x1f44d;感谢小伙伴们点赞、关注&#xff01; 《------往期经典推…...

H7-TOOL的LUA小程序教程第14期:任意波形信号发生器,0-20mA输出和微型数控电源(2024-10-11,已更新)

LUA脚本的好处是用户可以根据自己注册的一批API&#xff08;当前TOOL已经提供了几百个函数供大家使用&#xff09;&#xff0c;实现各种小程序&#xff0c;不再限制Flash里面已经下载的程序&#xff0c;就跟手机安装APP差不多&#xff0c;所以在H7-TOOL里面被广泛使用&#xff…...

Redis面试篇3

1、Redis的数据类型&#xff0c;以及每种数据类型的使用场景&#xff1f; 常见的几种数据类型和使用场景如下&#xff1a; 字符串(String)&#xff1a;字符串类型是Redis最基本的数据结构&#xff0c;一个键最大能存储512MB。 使用场景&#xff1a;适用于计数器、分布式锁、缓…...

集成方案 | 借助 Microsoft Copilot for Sales 与 Docusign,加速销售流程!

加速协议信息提取&#xff0c;随时优化邮件内容~ 在当今信息爆炸的时代&#xff0c;销售人员掌握着丰富的数据资源。他们能够通过 CRM 平台、电子邮件、合同库以及其他多种记录系统&#xff0c;随时检索特定个人或组织的关键信息。这些数据对于销售沟通至关重要。然而&#x…...

k8s 1.28.2 集群部署 MinIO 分布式集群

文章目录 [toc]MinIO 介绍MinIO 生产硬件要求MinIO 存储要求MinIO 内存要求MinIO 网络要求MinIO 部署架构分布式 MinIO复制的 MinIO 部署 MinIO创建目录节点打标签创建 namespace创建 pv创建 MinIO配置 ingress问题记录通过代理服务器访问 MinIO 的 Object Browser 界面一直显示…...

HAL库常用的函数:

目录 HAL库&#xff1a; 1.GPIO常用函数&#xff1a; 1.HAL_GPIO_ReadPin( ) 2.HAL_GPIO_WritePin( ) 3.HAL_GPIO_TogglePin( ) 4.HAL_GPIO_EXTI_IRQHandler( ) 5.HAL_GPIO_EXTI_Callback( ) 2.UART常用函数&#xff1a; 1.HAL_U…...

如何捕捉行情爆发的前兆

在金融市场的激烈角逐中&#xff0c;每一次行情的爆发都是投资者获取丰厚回报的关键时刻。然而&#xff0c;如何识别并把握这些时刻&#xff0c;却是一门需要深厚金融专业知识和敏锐洞察力的艺术。今天&#xff0c;我们就来深入探讨行情爆发的初期信号&#xff0c;揭示那些能够…...

【万字长文】Word2Vec计算详解(一)CBOW模型

【万字长文】Word2Vec计算详解&#xff08;一&#xff09;CBOW模型 写在前面 本文用于记录本人学习NLP过程中&#xff0c;学习Word2Vec部分时的详细过程&#xff0c;本文与本人写的其他文章一样&#xff0c;旨在给出Word2Vec模型中的详细计算过程&#xff0c;包括每个模块的计…...

React Native源码学习

核心组件 基础组件&#xff1a;View、Text、Image、TextInput、ScrollView&#xff08;性能没有FlatList好&#xff0c;因为它会一次性把子元素渲染出来&#xff09;、StyleSheet交互组件&#xff1a;button列表视图&#xff1a;FlatList&#xff08;优先渲染屏幕上可见的元素&…...