C++ 数据结构B 树

目录

1. 常见的搜索结构

2. B树概念

3. B-树的插入分析

4. B-树的插入实现

        4.1 B-树的节点设计

       4.2 插入key的过程

4.4 B-树的简单验证

4.5 B-树的性能分析

4.6 B-树的删除

5. B+树和B*树

5.1 B+树

5.2 B*树

5.3 总结

6. B-树的应用

6.1 索引

6.2 MySQL索引简介

6.2.1 MyISAM

6.2.2 InnoDB


1. 常见的搜索结构

以上结构适合用于数据量相对不是很大,能够一次性存放在内存中,进行数据查找的场景。如果
数据量很大,比如有 100G 数据,无法一次放进内存中,那就只能放在磁盘上了,如果放在磁盘 上,有需要搜索某些数据,那么如果处理呢?那么我们可以考虑将存放关键字及其映射的数据的 地址放到一个内存中的搜索树的节点中,那么要访问数据时,先取这个地址去磁盘访问数据。

 

使用平衡二叉树搜索树的缺陷:
平衡二叉树搜索树的高度是 logN ,这个查找次数在内存中是很快的。但是当数据都在磁盘中时,访问磁盘速度很慢,在数据量很大时,logN 次的磁盘访问,是一个难以接受的结果。
使用哈希表的缺陷:
哈希表的效率很高是 O(1) ,但是一些极端场景下某个位置冲突很多,导致访问次数剧增,也是难以接受的。那如何加速对数据的访问呢?
1. 提高 IO 的速度 (SSD 相比传统机械硬盘快了不少,但是还是没有得到本质性的提升 )
2. 降低树的高度 --- 多叉树平衡树

2. B树概念

1970 年, R.Bayer E.mccreight 提出了一种适合外查找的树,它是一种平衡的多叉树,称为 B
( 后面有一个 B 的改进版本 B+ 树,然后有些地方的 B 树写的的是 B- 树,注意不要误读成 "B 减树 ")
m (m>2) B 树,是一棵平衡的 M 路平衡搜索树,可以是空树 或者满足一下性质:
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

3. B-树的插入分析

为了简单起见,假设 M = 3. 三叉树,每个节点中存储两个数据,两个数据可以将区间分割成三
个部分,因此节点应该有三个孩子 ,为了后续实现简单期间,节点的结构如下:

用序列 {53, 139, 75, 49, 145, 36, 101} 构建 B 树的过程如下:

 

 

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;// 返回值:PNode代表找到的节点,int为该元素在该节点中的位置
pair<PNode, int> Find(const K &key)
{// 从根节点的位置开始查找PNode pCur = _pRoot;PNode pParent = NULL;size_t i = 0;// 节点存在while (pCur){i = 0;// 在该节点的值域中查找while (i < pCur->_size){// 找到返回if (key == pCur->_keys[i]) return pair<PNode, int>(pCur, i);else if (key < pCur->_keys[i])   // 该元素可能在i的左边的孩子节点中break;else i++;// 继续向右查找}// 在pCur中没有找到,到pCur节点的第i个孩子中查找pParent = pCur;pCur = pCur->_pSub[i];}// 没有找到return pair<PNode, int>(pParent, -1);
}int main()
{system("pause");return 0;
}

 

 

插入过程总结:
1. 如果树为空,直接插入新节点中,该节点为树的根节点
2. 树非空,找待插入元素在树中的插入位置 ( 注意:找到的插入节点位置一定在叶子节点中 )
3. 检测是否找到插入位置 ( 假设树中的 key 唯一,即该元素已经存在时则不插入 )
4. 按照插入排序的思想将该元素插入到找到的节点中
5. 检测该节点是否满足 B- 树的性质:即该节点中的元素个数是否等于 M ,如果小于则满足
6. 如果插入后节点不满足 B 树的性质,需要对该节点进行分裂:申请新节点找到该节点的中间位置将该节点中间位置右侧的元素以及其孩子搬移到新节点中,将中间位置元素以及新节点往该节点的双亲节点中插入,即继续4
7. 如果向上已经分裂到根节点的位置,插入结束。

4. B-树的插入实现

        4.1 B-树的节点设计

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;// M 叉树,即一个节点最多有M个孩子,M-1 个数据域
template <class K, int M = 3>struct BTreeNode
{K _keys[M]; //存放元素BTreeNode<K, M> *_pSub[M + 1];BTreeNode<K, M> *_pParent;size_t _size;BTreeNode() : _pParent(NULL), _size(0){for (size_t i = 0; i <= M; i++){_pSub[i] = nullptr;}}
};int main()
{system("pause");return 0;
}

       4.2 插入key的过程

按照插入排序的思想插入 key ,注意:在插入 key 的同时,可能还要插入新分裂出来的节点
        
void _InsertKey(PNode pCur, const K& key, PNode pSub)
{
// 按照插入排序思想插入keyint end = pCur->_size-1;while(end >= 0){if(key < pCur->_keys[end]){// 将该位置元素以及其右侧孩子往右搬移一个位置pCur->_keys[end+1] = pCur->_keys[end];pCur->_pSub[end+2] = pCur->_pSub[end+1];end--;}elsebreak;}
// 插入key以及新分裂出的节点pCur->_keys[end+1] = key;pCur->_pSub[end+2] = pSub;// 更新节点的双亲if(pSub)pSub->_pParent = pCur;pCur->_size++;
}

4.3 B-树的插入实现  

        

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;// M 叉树,即一个节点最多有M个孩子,M-1 个数据域
template <class K, int M = 3>struct BTreeNode
{K _keys[M]; //存放元素BTreeNode<K, M> *_pSub[M + 1];BTreeNode<K, M> *_pParent;size_t _size; //节点元素的个数BTreeNode() : _pParent(NULL), _size(0){for (size_t i = 0; i <= M; i++){_pSub[i] = nullptr;}}bool Insert(const K &key){// 如果树为空,直接插入if (NULL == _pRoot){_pRoot = new Node();_pRoot->_keys[0] = key;_pRoot->_size = 1;return true;}// 找插入位置,如果该元素已经存在,则不插入pair<PNode, int> ret = Find(key);if (-1 != ret.second)return false;K k = key;PNode temp = NULL;PNode pCur = ret.first;while (true){// 将key插入到pCur所指向的节点中_InsertKey(pCur, k, temp);// 检测该节点是否满足B-树的性质,如果满足则插入成功返回,否则,对pCur节点进行分裂if (pCur->_size < M) return true;// 申请新节点temp = new Node;// 找到pCur节点的中间位置// 将中间位置右侧的元素以及孩子搬移到新节点中int mid = (M >> 1);for (size_t i = mid + 1; i < pCur->_size; ++i){temp->_keys[temp->_size] = pCur->_keys[i];temp->_pSub[temp->_size++] = pCur->_pSub[i];// 跟新孩子节点的双亲if (pCur->_pSub[i])pCur->_pSub[i]->_pParent = temp;}// 注意:孩子比关键字多搬移一个temp->_pSub[temp->_size] = pCur->_pSub[pCur->_size];if (pCur->_pSub[pCur->_size])pCur->_pSub[pCur->_size]->_pParent = temp;// 更新pCur节点的剩余数据个数pCur->_size -= (temp->_size + 1);// 如果分裂的节点为根节点,重新申请一个新的根节点,将中间位置数据以及分裂出的新节点插入到新的根节点中,插入结束 if (pCur == _pRoot){_pRoot = new Node;_pRoot->_keys[0] = pCur->_keys[mid];_pRoot->_pSub[0] = pCur;4.4 B - 树的简单验证 对B树进行中序遍历,如果能得到一个有序的序列,说明插入正确。 4.5 B - 树的性能分析 对于一棵节点为N度为M的B - 树,查找和插入需要$log{M - 1} N$ ~$log{M / 2} N$次比较,这个很好证 明:对于度为M的B - 树,每一个节点的子节点个数为M / 2 ~(M - 1) 之间,因此树的高度应该在要 $log{M - 1} N$和$log{M / 2} N$之间,在定位到该节点后,再采用二分查找的方式可以很快的定位 到该元素。 B - 树的效率是很高的,对于N = 62 * 1000000000个节点,如果度M为1024,则 $log_{M / 2} N$ <=4,即在620亿个元素中,如果这棵树的度为1024,则需要小于4次即可定位到该节点,然后利用 二分查找可以快速定位到该元素,大大减少了读取磁盘的次数。 4.6 B - 树的删除 学习B树的插入足够帮助我们理解B树的特性了,如果对删除有兴趣的同学们参考《算法导论》--伪代码和《数据结构 - 殷人昆》--C++ 实现代码。 5. B + 树和B * 树 5.1 B + 树 B + 树是B树的变形,是在B树基础上优化的多路平衡搜索树,B + 树的规则跟B树基本类似,但是又 在B树的基础上做了以下几点改进优化: _pRoot->_pSub[1] = temp;_pRoot->_size = 1;pCur->_pParent = temp->_pParent = _pRoot;return true;}else{// 如果分裂的节点不是根节点,将中间位置数据以及新分裂出的节点继续向pCur的双亲中进行插入k = pCur->_keys[mid];pCur = pCur->_pParent;}}return true;}
};int main()
{system("pause");return 0;
}

4.4 B-树的简单验证

B 树进行中序遍历,如果能得到一个有序的序列,说明插入正确。
        
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;// M 叉树,即一个节点最多有M个孩子,M-1 个数据域
template <class K, int M = 3>struct BTreeNode
{K _keys[M]; //存放元素BTreeNode<K, M> *_pSub[M + 1];BTreeNode<K, M> *_pParent;size_t _size; //节点元素的个数BTreeNode() : _pParent(NULL), _size(0){for (size_t i = 0; i <= M; i++){_pSub[i] = nullptr;}}bool Insert(const K &key){// 如果树为空,直接插入if (NULL == _pRoot){_pRoot = new Node();_pRoot->_keys[0] = key;_pRoot->_size = 1;return true;}// 找插入位置,如果该元素已经存在,则不插入pair<PNode, int> ret = Find(key);if (-1 != ret.second)return false;K k = key;PNode temp = NULL;PNode pCur = ret.first;while (true){// 将key插入到pCur所指向的节点中_InsertKey(pCur, k, temp);// 检测该节点是否满足B-树的性质,如果满足则插入成功返回,否则,对pCur节点进行分裂if (pCur->_size < M) return true;// 申请新节点temp = new Node;// 找到pCur节点的中间位置// 将中间位置右侧的元素以及孩子搬移到新节点中int mid = (M >> 1);for (size_t i = mid + 1; i < pCur->_size; ++i){temp->_keys[temp->_size] = pCur->_keys[i];temp->_pSub[temp->_size++] = pCur->_pSub[i];// 跟新孩子节点的双亲if (pCur->_pSub[i])pCur->_pSub[i]->_pParent = temp;}// 注意:孩子比关键字多搬移一个temp->_pSub[temp->_size] = pCur->_pSub[pCur->_size];if (pCur->_pSub[pCur->_size])pCur->_pSub[pCur->_size]->_pParent = temp;// 更新pCur节点的剩余数据个数pCur->_size -= (temp->_size + 1);// 如果分裂的节点为根节点,重新申请一个新的根节点,将中间位置数据以及分裂出的新节点插入到新的根节点中,插入结束 if (pCur == _pRoot){_pRoot = new Node;_pRoot->_keys[0] = pCur->_keys[mid];_pRoot->_pSub[0] = pCur;4.4 B - 树的简单验证 对B树进行中序遍历,如果能得到一个有序的序列,说明插入正确。 4.5 B - 树的性能分析 对于一棵节点为N度为M的B - 树,查找和插入需要$log{M - 1} N$ ~$log{M / 2} N$次比较,这个很好证 明:对于度为M的B - 树,每一个节点的子节点个数为M / 2 ~(M - 1) 之间,因此树的高度应该在要 $log{M - 1} N$和$log{M / 2} N$之间,在定位到该节点后,再采用二分查找的方式可以很快的定位 到该元素。 B - 树的效率是很高的,对于N = 62 * 1000000000个节点,如果度M为1024,则 $log_{M / 2} N$ <=4,即在620亿个元素中,如果这棵树的度为1024,则需要小于4次即可定位到该节点,然后利用 二分查找可以快速定位到该元素,大大减少了读取磁盘的次数。 4.6 B - 树的删除 学习B树的插入足够帮助我们理解B树的特性了,如果对删除有兴趣的同学们参考《算法导论》--伪代码和《数据结构 - 殷人昆》--C++ 实现代码。 5. B + 树和B * 树 5.1 B + 树 B + 树是B树的变形,是在B树基础上优化的多路平衡搜索树,B + 树的规则跟B树基本类似,但是又 在B树的基础上做了以下几点改进优化: _pRoot->_pSub[1] = temp;_pRoot->_size = 1;pCur->_pParent = temp->_pParent = _pRoot;return true;}else{// 如果分裂的节点不是根节点,将中间位置数据以及新分裂出的节点继续向pCur的双亲中进行插入k = pCur->_keys[mid];pCur = pCur->_pParent;}}return true;}
};
void _InOrder(PNode pRoot)
{if (NULL == pRoot)return;for (size_t i = 0; i < pRoot->_size; ++i){_InOrder(pRoot->_pSub[i]);cout << pRoot->_keys[i] << " ";}_InOrder(pRoot->_pSub[pRoot->_size]);
}int main()
{system("pause");return 0;
}

4.5 B-树的性能分析

对于一棵节点为 N 度为 M B- 树,查找和插入需要 $log {M-1}N$~$log {M/2}N$ 次比较,这个很好证
明: 对于度为 M B- 树,每一个节点的子节点个数为 M/2 ~(M-1) 之间,因此树的高度应该 $log {M-1}N$ $log {M/2}N$ 之间,在定位到该节点后,再采用二分查找的方式可以很快的定位 到该元素
B- 树的效率是很高的,对于 N = 62*1000000000 个节点,如果度 M 1024 ,则 $log_{M/2}N$ <=
4 ,即在 620 亿个元素中,如果这棵树的度为 1024 ,则需要小于 4 次即可定位到该节点,然后利用 二分查找可以快速定位到该元素,大大减少了读取磁盘的次数

4.6 B-树的删除

学习 B 树的插入足够帮助我们理解 B 树的特性了,如果对删除有兴趣的同学们参考《算法导论》 --
伪代码和《数据结构 - 殷人昆》 --C++ 实现代码。

5. B+树和B*

5.1 B+

B+ 树是 B 树的变形,是在 B 树基础上优化的多路平衡搜索树, B+ 树的规则跟 B 树基本类似,但是又
B 树的基础上做了以下几点改进优化:
2. 分支节点的子树指针与关键字个数相同
3. 分支节点的子树指针 p[i] 指向关键字值大小在 [k[i] k[i+1]) 区间之间
4. 所有叶子节点增加一个链接指针链接在一起
5. 所有关键字及其映射数据都在叶子节点出现

B+树的特性

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

5.2 B*

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

B+ 树的分裂:
当一个结点满时,分配一个新的结点,并将原结点中 1/2 的数据复制到新结点,最后在父结点中增
加新结点的指针; B+ 树的分裂只影响原结点和父结点,而不会影响兄弟结点,所以它不需要指向兄弟的指针。
B* 树的分裂:
当一个结点满时,如果它的下一个兄弟结点未满,那么将一部分数据移到兄弟结点中,再在原结
点插入关键字,最后修改父结点中兄弟结点的关键字(因为兄弟结点的关键字范围改变了);如
果兄弟也满了,则在原结点与兄弟结点之间增加新结点,并各复制 1/3 的数据到新结点,最后在父 结点增加新结点的指针。所以,B*树分配新结点的概率比 B+ 树要低,空间使用率更高;

 

5.3 总结

通过以上介绍,大致将 B 树, B+ 树, B* 树总结如下:
B 树:有序数组 + 平衡多叉树;
B+ 树:有序数组链表 + 平衡多叉树;
B* 树:一棵更丰满的,空间利用率更高的 B+

6. B-树的应用

6.1 索引

B- 树最常见的应用就是用来做索引 。索引通俗的说就是为了方便用户快速找到所寻之物,比如书籍目录可以让读者快速找到相关信息,hao123 网页导航网站,为了让用户能够快速的找到有值的分类网站,本质上就是互联网页面中的索引结构。MySQL官方对索引的定义为:索引 (index) 是帮助 MySQL 高效获取数据的数据结构,简单来说: 索引就是数据结构
 当数据量很大时,为了能够方便管理数据,提高数据查询的效率,一般都会选择将数据保存到数据库,因此数据库不仅仅是帮助用户管理数据,而且数据库系统还维护着满足特定查找算法的数据结构,这些数据结构以某种方式引用数据,这样就可以在这些数据结构上实现高级查找算法,该数据结构就是索引。

6.2 MySQL索引简介

mysql 是目前 非常流行的开源关系型数据库,不仅是免费的,可靠性高,速度也比较快,而且拥 有灵活的插件式存储引擎 ,如下:

MySQL 中索引属于存储引擎级别的概念,不同存储引擎对索引的实现方式是不同的。
注意:索引是基于表的,而不是基于数据库的。

6.2.1 MyISAM

MyISAM 引擎是 MySQL5.5.8 版本之前默认的存储引擎,不支持事物,支持全文检索,使用 B+Tree
作为索引结构,叶节点的 data 域存放的是数据记录的地址,其结构如下。

 

上图是以以 Col1 为主键, MyISAM 的示意图,可以看出 MyISAM 的索引文件仅仅保存数据记录的 地址 MyISAM 中,主索引和辅助索引( Secondary key )在结构上没有任何区别,只是主索 要求 key 是唯一的,而辅助索引的 key 可以重复 。如果想在 Col2 上建立一个辅助索引,则此索引 的结构如下图所示:

  同样也是一棵 B+Tree data 域保存数据记录的地址。因此, MyISAM 中索引检索的算法为首先按照B+Tree 搜索算法搜索索引,如果指定的 Key 存在,则取出其 data 域的值,然后以 data 域的值为地址,读取相应数据记录。MyISAM 的索引方式也叫做 非聚集索引 的。

6.2.2 InnoDB

InnoDB 存储引擎支持事务 ,其设计目标主要面向在线事务处理的应用,从 MySQL 数据库 5.5.8
本开始, InnoDB 存储引擎是默认的存储引擎 InnoDB 支持 B+ 树索引、全文索引、哈希索引。但
InnoDB 使用 B+Tree 作为索引结构时,具体实现方式却与 MyISAM 截然不同。
第一个区别是 InnoDB 的数据文件本身就是索引文件 MyISAM 索引文件和数据文件是分离的, 索引文件仅保存数据记录的地址 。而 InnoDB 索引,表数据文件本身就是按 B+Tree 组织的一个索引结构,这棵树的叶节点data 域保存了完整的数据记录。这个索引的 key 是数据表的主键,因此 InnoDB表数据文件本身就是主索引.

上图是 InnoDB 主索引 (同时也是数据文件)的示意图,可以看到 叶节点包含了完整的数据记录,
这种索引叫做聚集索引 。因为 InnoDB 的数据文件本身要按主键聚集,所以 InnoDB 要求表必须有
主键 MyISAM 可以没有), 如果没有显式指定,则 MySQL 系统会自动选择一个可以唯一标识数
据记录的列作为主键 如果不存在这种列,则 MySQL 自动为 InnoDB 表生成一个隐含字段作为主 键,这个字段长度为6 个字节,类型为长整型。第二个区别是InnoDB 的辅助索引 data 域存储相应记录主键的值而不是地址 , 所有辅助索引都引用主键作为data 域。

 

聚集索引这种实现方式使得按主键的搜索十分高效 ,但是 辅助索引搜索需要检索两遍索引:首先 检索辅助索引获得主键,然后用主键到主索引中检索获得记录。

 参考资料:

CodingLabs - MySQL索引背后的数据结构及算法原理

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

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

相关文章

计算机网络————运输层

文章目录 概述UDPTCP首部格式 连接管理连接建立连接释放 概述 从IP层看&#xff0c;通信双方是两个主机。 但真正进行通信的实体是在主机中的进程&#xff0c;是这个主机中的一个进程和另一个主机中的一个进程在交换数据。 所以严格的讲&#xff0c;两个主机进行通信就是两个…

关于邮件协议的理解、实验以及java mail的实现

目录 1、几种电子邮件系统组成 传统电子邮件系统 用户代理 UA (User Agent) 邮箱服务器 基于万维网的电子邮件系统 2、电子邮件协议 SMTP 连接建立 邮件传送 连接释放 局限 POP3 IMAP 补充 3、telnet实验电子邮件协议 SMTP POP3 4、java mail 参考文章 1、几…

el-carousel和el-image组合实现swiper左右滑动图片,点击某张图片放大预览的效果

<template><el-carousel class"image-swiper" :height"100%" :indicator-position"swiperItems.length < 1 ? none : ":arrow"swiperItems.length < 1 ? never : "><el-carousel-item v-for"(a, $i) in s…

websocket前端的连接与接收数据

什么是websocket 1, WebSocket是一种用于在客户端和服务器之间进行全双工通信的网络协议。它使得在单个TCP连接上可以进行双向通信&#xff0c;允许服务器主动地发送数据给客户端&#xff0c;同时客户端也可以向服务器发送数据。与传统的HTTP请求-响应模型不同&#xff0c;Web…

Scrapy框架--settings配置 (详解)

目录 settings配置 官网-参考配置 配置文档 Scrapy默认BASE设置 settings配置 Scrapy框架中的配置文件&#xff08;settings.py&#xff09;是用来管理爬虫行为和功能的关键部分。它是一个Python模块&#xff0c;提供了各种配置选项&#xff0c;可以自定义和控制爬虫的行为。…

【IMX6ULL驱动开发学习】12.Linux驱动之设备树

承接上一篇博客 【IMX6ULL驱动开发学习】11.驱动设计之面向对象_分层思想&#xff08;学习设备树过渡部分&#xff09; 代码获取&#xff1a;https://gitee.com/chenshao777/imx6-ull_-drivers 我后面将三个层合并了&#xff08;实际上只有前两层&#xff09;&#xff0c;合并…

[论文阅读] (31)李沐老师视频学习——4.研究的艺术·理由、论据和担保

《娜璋带你读论文》系列主要是督促自己阅读优秀论文及听取学术讲座&#xff0c;并分享给大家&#xff0c;希望您喜欢。由于作者的英文水平和学术能力不高&#xff0c;需要不断提升&#xff0c;所以还请大家批评指正&#xff0c;非常欢迎大家给我留言评论&#xff0c;学术路上期…

Element-Plus select选择器-下拉组件错位bug(有高度滚动时)

1. bug重现 由于项目不便展示&#xff0c;因此在官网复现bug https://element-plus.org/zh-CN/component/select.html#基础用法 2. 调试 源码调试时发现下拉菜单是直接放在body 元素里&#xff0c;这时候希望它不要直接放在body里&#xff0c; 查阅文档看到这两个属性&#x…

软件工程期末报告(登录注册部分)

云小智微校园工具系统的设计与实现成员1注册模块 目录 云小智微校园工具系统的设计与实现成员1注册模块 第一章 绪论 第二章需求分析&#xff1a; 1.活动图&#xff1a; 2.用例图&#xff1a; 什么用户参与了业务模块&#xff1a; 这类用户在模块中使用什么功能学生用户…

【分布式技术专题】「缓存解决方案」一文带领你好好认识一下企业级别的缓存技术解决方案的运作原理和开发实战(数据更新场景策略和方案分析)

一文带领你好好认识一下企业级别的缓存技术解决方案的运作原理和开发实战&#xff08;数据更新场景策略和方案分析&#xff09; 数据更新场景Cache Aside Pattern策略思想具体操作分析失效&#xff08;Invalidation&#xff09;命中&#xff08;Cache Hit&#xff09;更新&…

【python】python编程基础

基础工具包 python 原生数据结构元组 Tuple列表 list集合 set字典 dictionary NumPy 数据结构数组 Ndarray矩阵 Matrix Pandas 数据结构序列 Series &#xff08;一维&#xff09;数据框 DataFrame &#xff08;二维&#xff09; Matplotlib 数据可视化绘制饼图绘制折线图绘制直…

git学习使用技巧

目录 关于版本控制 本地版本控制系统 集中化的版本控制系统 分布式版本控制系统 Git 是什么 直接记录快照&#xff0c;而非差异比较 近乎所有操作都是本地执行 Git 保证完整性 Git 一般只添加数据 三种状态 起步 - 初次运行 Git 前的配置 初次运行 Git 前的配置 用户…