C++【B树】【B+树】

news2024/10/6 8:39:22

文章目录

  • 一、什么是B树
    • 1.为什么要存在B树?
    • 2.B树的规则
  • 二、B树的插入
  • 三、B树的实现
    • 时间复杂度
  • 四、B+树
    • 1.B+树的分类过程
  • 五、B*树
  • 六、B树系列的应用
    • 1.MyISAM
    • 2.InnoDB

一、什么是B树

相比于我们别的数据结构,我们的B树更加适合进行外查找
B树也可以进行内查找,但是有一点浪费空间

1.为什么要存在B树?

当我们的数据量很大,无法一次全部都放进内存的话,那就只能存在磁盘上。
那么我们应该如何将这些磁盘的文件进行管理起来呢?
磁盘当中的数据只能挨着存。
我们可以考虑将存放关键字及其映射的数据的地址放到一个内存中的搜索树的节点中,那么要访问数据时,先取这个地址去磁盘访问数据。
在这里插入图片描述
从上面的图中我们可以看出,我们从树的根开始读取的话,我们需要读取树的高度次磁盘IO
但是多次进行磁盘读取,就会非常缓慢。每次要读取新的数据,要去定位这个过程是非常缓慢地。

在这里插入图片描述
我们来看一下我们之前的数据结构:
AVL树/红黑树:logN
哈希表:O(1):极端场景下哈希冲突非常严重,效率下降很多。
这时我们就需要用到B树
如果是10亿个数据,我们的AVL树大概需要存30层。
我们要对这30层进行压缩,我们就要想办法我们对我们每一层进行压缩

在平衡搜索树的基础上寻找优化方法
1.压缩高度,二叉变多插
2.一个结点里面存多行的值,也就是一个结点里面有多个关键字以及映射的值

2.B树的规则

(B树的设计都是为了服务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。

(分支节点孩子的数量要比关键字的数量多一个)
假设现在我们的m是10
按照上面的规则,也就是说我们
最少需要4个关键字5个孩子
最多需要9个关键字0个孩子
然后我们这个节点中的关键字按照从小到大的顺序进行排列
(n,A0,K1,A1,K2,A2,… ,Kn,An)
K1<K2<K3<…<Kn
A0节点中的值<K1<A1节点中的值<K2<……
在这里插入图片描述
也就是说,如果比K1小,我们就在A0节点中继续寻找,如果比K2小比K1大,我们就在A1节点中进行查找。

也就是说如果采用了B树的设计,我们一次就可以读取出最多m个人的信息,读取更多人的信息,IO不会变慢吗?
IO慢的事查找定位到对应的位置的时间,如果是连续的存取的话,影响是不太大的。

在实际的情况下,M一般被设置成比较大的数字,比方说1024,也就是一个节点中最多存1023个关键字,1024个孩子
这时候,我们如果想要在单节点的m歌数据中进行查找的话,我们就可以使用二分进行查找。logN。

但是这样我们的空间的开销就比较大,所以它指定我们的一个节点中最少存m/2个孩子
(这跟B树的分裂有关)

所以我们B树的本质是一个多叉的搜索树

二、B树的插入

这里我们先假设M=3。
也就是最少存1个关键字,最多两个关键字,最少2个孩子,最多3个孩子
这里是我们的数据:{53, 139, 75, 49, 145, 36, 101}

首先我们将53,139和75插入
(我们这里多开一个空间,便于我们的插入。否则我们的第m个元素插入的时候,也就是我们刚刚好越界的时候,我们就不知道插入在哪里,我们可能还要分情况进行讨论,这样就非常麻烦。多开辟一个空间的话,我们就可以先将这第M个元素先插进去,然后再进行分裂操作,就省去了分类讨论)
在这里插入图片描述
关键字的数量等于M,那就是满了,满了就分裂,分裂出一个兄弟(兄弟里面最初始没有值),然后分一半的值给兄弟
在这里插入图片描述
满了的结点有M个关键字,(最多只能存M-1个),分裂M/2个给兄弟,还要提取中位数给父亲,没有父亲就创建新的根。(如果不提取值给父亲的话,这两个兄弟就裂开了)
在这里插入图片描述
再插入36的时候,我们左边的结点1就满了,我们又需要进行分裂
在这里插入图片描述
49是我们的中位数。
所以我们将49放入我们的父节点中
(我们的关键字要比我们孩子的数量少一个。现在我们有三个孩子和两个关键字)
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
最右边的子树满了,进行持续分裂
在这里插入图片描述
在这里插入图片描述

B树天然平衡
因为它是向右和向上生长的
新插入的结点一定是在叶子插入的。叶子没有孩子,所以不会影响孩子和关键字的关系(孩子比关键字多一个)
叶子结点满了,就分裂出一个兄弟,提取中位数,向父亲插入一个值和一个孩子。
根节点分裂才会增加一层。

假设M=1024,那么一个4层的M路的B树可以存多少个值呢?
如果这棵树是全满的情况下
第一层1023个关键字,1024个孩子
第二层10241023个关键字(上一层的每一个孩子也就是这一层的每一个结点都有1023个关键字),10241024个孩子
第三层102410241023个关键字(上一层的每一个孩子也就是这一层的每一个结点都有1023个关键字),102410241024个孩子
第三层1024102410241023个关键字(上一层的每一个孩子也就是这一层的每一个结点都有1023个关键字),1024102410241024个孩子

满树的情况下
第一层大概就是1000
第二层大概就是100w
第三层大概就是10亿
第四层大概就是1万亿

最差的情况:
第一层只有1个关键字,2个孩子
第二层有2512个关键字,大概1000个关键字,1000个孩子
第三层大概1000
512个关键字,1000512个孩子
第四层大概50w
512个关键字,约等于2.5亿个关键字

三、B树的实现


template<class K, size_t M>
struct BTreeNode
{
    //K _keys[M - 1];
    //BTreeNode<K, M>* _subs[M];

    // 为了方便插入以后再分裂,多给一个空间
    K _keys[M];
    BTreeNode<K, M>* _subs[M+1];
    BTreeNode<K, M>* _parent;
    size_t _n; // 记录实际存储多个关键字

    //初始化构造函数
    BTreeNode()
    {
        for (size_t i = 0; i < M; ++i)
        {
            _keys[i] = K();
            _subs[i] = nullptr;
        }

        _subs[M] = nullptr;
        _parent = nullptr;
        _n = 0;
    }
};

// 数据是存在磁盘,K是磁盘地址,是M路的搜索树,我们的M事不确定的
template<class K, size_t M>
class BTree
{
    typedef BTreeNode<K, M> Node;
public:
    //返回这个节点和下标
    pair<Node*, int> Find(const K& key)
    {
        Node* parent = nullptr;
        Node* cur = _root;

        while (cur)
        {
            // 在一个节点查找
            size_t i = 0;
            while (i < cur->_n)
            {
                if (key < cur->_keys[i])
                {
                    break;
                }
                else if (key > cur->_keys[i])
                {
                    ++i;
                }
                //找到了就返回这个节点
                else
                {
                    return make_pair(cur, i);
                }
            }

            // 往孩子去跳
            //在往下一层跳之前先将当前的结点给parent
            parent = cur;
            cur = cur->_subs[i];
        }

        //找不到
        return make_pair(parent, -1);
    }

    void InsertKey(Node* node, const K& key, Node* child)
    {
        int end = node->_n - 1;
        while (end >= 0)
        {
            if (key < node->_keys[end])
            {
                // 挪动key和他的右孩子
                node->_keys[end + 1] = node->_keys[end];
                node->_subs[end + 2] = node->_subs[end + 1];
                --end;
            }
            else
            {
                break;
            }
        }

        node->_keys[end + 1] = key;
        node->_subs[end + 2] = child;
        if (child)
        {
            child->_parent = node;
        }

        node->_n++;
    }

    //插入
    bool Insert(const K& key)
    {
        if (_root == nullptr)
        {
            //如果我们整颗树一个结点都没有
            _root = new Node;
            //将我们的第一个关键字传入
            _root->_keys[0] = key;
            _root->_n++;

            return true;
        }

        // key已经存在,不允许插入
        pair<Node*, int> ret = Find(key);
        if (ret.second >= 0)
        {
            return false;
        }

        // 如果没有找到,find顺便带回了要插入的那个叶子节点

        // 循环每次往cur插入 newkey和child
        Node* parent = ret.first;
        K newKey = key;
        Node* child = nullptr;
        while (1)
        {
            InsertKey(parent, newKey, child);
            // 满了就要分裂
            // 没有满,插入就结束
            if (parent->_n < M)
            {
                return true;
            }
            else
            {
                size_t mid = M / 2;
                // 分裂一半[mid+1, M-1]给兄弟
                Node* brother = new Node;
                size_t j = 0;
                size_t i = mid + 1;
                for (; i <= M - 1; ++i)
                {
                    // 分裂拷贝key和key的左孩子
                    brother->_keys[j] = parent->_keys[i];
                    brother->_subs[j] = parent->_subs[i];
                    if (parent->_subs[i])
                    {
                        parent->_subs[i]->_parent = brother;
                    }
                    ++j;

                    // 拷走重置一下方便观察
                    parent->_keys[i] = K();
                    parent->_subs[i] = nullptr;
                }

                // 还有最后一个右孩子拷给
                brother->_subs[j] = parent->_subs[i];
                if (parent->_subs[i])
                {
                    parent->_subs[i]->_parent = brother;
                }
                parent->_subs[i] = nullptr;

                brother->_n = j;
                parent->_n -= (brother->_n + 1);

                K midKey = parent->_keys[mid];
                parent->_keys[mid] = K();


                // 说明刚刚分裂是根节点
                if (parent->_parent == nullptr)
                {
                    //创建一个新的父节点
                    _root = new Node;
                    _root->_keys[0] = midKey;
                    _root->_subs[0] = parent;
                    _root->_subs[1] = brother;
                    _root->_n = 1;

                    parent->_parent = _root;
                    brother->_parent = _root;
                    break;
                }
                else
                {
                    // 转换成往parent->parent 去插入parent->[mid] 和 brother
                    newKey = midKey;

                    child = brother;
                    parent = parent->_parent;
                }
            }
        }

        return true;
    }

    void _InOrder(Node* cur)
    {
        if (cur == nullptr)
            return;

        // 左 根  左 根  ...  右
        size_t i = 0;
        for (; i < cur->_n; ++i)
        {
            _InOrder(cur->_subs[i]); // 左子树
            cout << cur->_keys[i] << " "; // 根
        }

        _InOrder(cur->_subs[i]); // 最后的那个右子树
    }

    void InOrder()
    {
        _InOrder(_root);
    }

private:
    Node* _root = nullptr;
};

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

在这里插入图片描述

时间复杂度

第一层:M
第二层:MM
第三层:M
MM
第四层:M
MMM

N=M+M2 +M3 +M4 +……+Mh
h约等于log{M}{N}(M为底数,N为指数)

四、B+树

B+树是在B树的基础上进行了优化

1.分支节点的子树指针与关键字个数相同。(就相当于是取消掉了原先B树每个结点的最左边的那个孩子)
2.分支节点的子树指针p[i]指向关键字值大小在[k[i],k[i+1])区间之间
3.所有叶子节点增加一个链接指针链接在一起
4.所有关键字及其映射数据都在叶子节点出现

(分支节点跟叶子结点有重复的值,分支节点存的是叶子结点的索引)
(父亲中存的是孩子结点中的最小值做索引)
(分支节点可以只存key,叶子结点存key/value)
在这里插入图片描述

1.B+树的分类过程

假设这是一棵M==3的B+树,然后我们B+树要插入的数据是
{53,139,75,49,145,36,101,150,155};

在这里插入图片描述

插入49的时候进行第一次分裂

在这里插入图片描述

插入146和35
在这里插入图片描述

插入101的时候发生第二次分裂
在这里插入图片描述
在这里插入图片描述
插入150,插入155的时候发生连续的两次分裂
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

B+树的插入过程根B树是基本类似的,区别在于第一次插入的时候需要插入两层节点,一层做分支,一层做根,后面一样往叶子去插入,插入满了以后,分一半给兄弟,转换成往父亲插入一个key和一个孩子,孩子就是兄弟,key为兄弟结点的第一个最小值的key

总结:
1.简化孩子比关键字多一个的规则,变成相等。
2.所有值都在叶子上,方便便利查找所有值。

五、B*树

B树和的结点关键字和孩子数量->[2/3M,M]在这里插入图片描述
B*树的分裂:
当一个结点满时,如果它的下一个兄弟结点未满,那么将一部分数据移到兄弟结点中,再在原结点插入关键字,最后修改父结点中兄弟结点的关键字(因为兄弟结点的关键字范围改变了);如果兄弟也满了,则在原结点与兄弟结点之间增加新结点,并各复制1/3的数据到新结点,最后在父结点增加新结点的指针。
所以,B*树分配新结点的概率比B+树要低,空间使用率更高;

![在这里插入图片描述](https://img-blog.csdnimg.cn/5ddce6ecf59a495090853e6a19d902a3.png =400x+)

六、B树系列的应用

在内存中做内查找的话和哈希、平衡搜索树对比:
单纯论树的高度,搜索效率而言,B树确实不错。
但是B树系列存在一些隐形的坏处:
1.空间利用率低,消耗高
2.插入和删除数据、分裂和合并节点,那么必然挪动数据。
3.虽然高度更低,但是在内存中而言,跟哈希和平衡搜索树还是在一个量级的
结论:实质上B树系列在内存中体现不出优势。
内存中搜索3次和30次差别不大,
磁盘中搜索3次和30次差别巨大

B树系列的应用:数据库中的引擎MyISAM或者InnoDB
在这里插入图片描述

比方说表格中:
一行就是一个人的成绩信息
一列就是所有人的一项的信息
数据库建表的时候就要选择一列作为主键

CREATE  TABLE StuInfo
(
stuID int,
age int,
name varchar(255)
...

);

当我们将上面的sql语句传给我们的MySQL数据库的时候,他会为我们建立一棵B+树来索引磁盘数据。
建表的主键就是B+树的key,B+树的value是存储一行数据的地址(一般主键要求是唯一的,不允许冗余的mysql:电话,身份证号码比较适合作为主键,名字、地址不适合作为主键)

如果没有字段能保持唯一怎么办?
设置一个自增主键(其实他自己建立一个自增整数作为主键)
一般数据库不要求索引唯一,像mysql建立索引可以考虑使用B+树还是Hash表,数据结构允许冗余。

我们可以将stuID设置成我们的主键key,其余的字段就作为value

分支节点也是要存到磁盘中的
因为数据量大了,内存中存不下的时候,
分支节点中应该存磁盘地址。
但是分支节点理论应该尽量缓存在cache当中。

以下两种sql语句的写法,第一种的查找方式更快
1.UPDATE StuInfo SET age=35 WHERE stuID=15;
2.UPDATE StuInfo SET age=35 WHERE name=‘BOb’
因为stuID是我们的主键,按照主键进行查找的话,就可以用我们的B+树的规则进行查找log_{M}N
但是如果查找条件是name的话,就需要将数据一条一条遍历,这样就非常缓慢。O(N)(全表扫描,我们尽量需要去避免)

如果经常想使用name进行查找怎么办?

可以用name字段创建一个索引。
MySQL创建索引的时候,可以指定是用B树创建索引还是用哈希表创建索引

CREATE INDEX nameIndex on stuInfo(name);
对name创建索引以后,相当于使用B+树用name做key穿件一棵树,
当然value只想磁盘数据,那么在执行sql语句,效率性就高了。

B+树做主键索引相比B树的优势

1.B+树所有的值都在叶子,遍历很方便,方便qujianchazhao。
2.对于没有建立索引的字段,全表扫描的遍历很方便
3.分支节点只存储key,一个分支节点空间占用更小,可以尽可能加载到缓存。

B树相比于B+树的优势

B树不用到叶子就能找到值,B+树一定要到叶子
但是B+树的高度足够低,所以差别不大

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的索引方式也叫做“非聚集索引”的。
(索引文件中存的是数据文件的地址)

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域。
(先用name,name对应主键id,再用主键id再去搜索一次,也就是说他用索引查找需要查找两次)
在这里插入图片描述

说明:B树节点数据都在磁盘文件中。访问节点都是IO行为,只是他们会热数据缓存到Cache中

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

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

相关文章

元启发式算法-模拟退火算法MATLAB实现

元启发式算法-模拟退火算法MATLAB实现 模拟退火介绍 模拟退火算法来源于固体退火原理&#xff0c;是一种基于概率的算法&#xff0c;将固体加温至充分高&#xff0c;再让其徐徐冷却&#xff0c;加温时&#xff0c;固体内部粒子随温升变为无序状&#xff0c;内能增大&#xff0…

SpringBoot系列教程之定义接口返回类型的几种方式

本文节选自 《Spring WEB专栏》 WEB系列】 定义接口返回类型的几种方式 实现一个 web 接口返回 json 数据&#xff0c;基本上是每一个 javaer 非常熟悉的事情了&#xff1b;那么问题来了&#xff0c;如果我有一个接口&#xff0c;除了希望返回 json 格式的数据之外&#xff0c…

Linux内核学习笔记——内核页表隔离KPTI机制

接前文。 一步一步理解CPU芯片漏洞&#xff1a;Meltdown与Spectre ARM系列之MMU TLB和ASID基础概念介绍。 一、Meltdown & Spectre 漏洞 Meltdown 和 Spectre 这两个漏洞厉害的地方就在于&#xff0c;利用现代CPU speculative execution (预测执行)的漏洞&#xff0c;在…

退役记——破铜烂铁的一生

写在前面 今天刚刚结束大三上的所有课程。我慢慢鼓起勇气去整理这段零碎的竞赛记忆&#xff0c;或许是最终也没拿到一个满意的奖项&#xff0c;来给我的竞赛生涯画上一个圆满的句号。 我该怎么回忆这破铜烂铁的一生&#xff0c;上万次尝试提交、数以千计的习题、上百次练习赛…

01、Java 数据结构:数据结构和算法的概述

数据结构和算法的概述1 参考教材2 数据结构2.1 数据的逻辑结构2.2 数据的存储结构2.3 数据的运算3 基本的数学概念的复习3.1 函数的定义3.2 极限3.3 对数4 算法4.1 算法的基本特性4.2 算法设计的要求4.3 时间复杂度和空间复杂度是衡量算法优劣的重要指标1 参考教材 主要参考的…

wy的leetcode刷题记录_Day62——二叉树结束

wy的leetcode刷题记录_Day62 声明 本文章的所有题目信息都来源于leetcode 如有侵权请联系我删掉! 时间&#xff1a;2022-12-27 前言 目录wy的leetcode刷题记录_Day62声明前言1750. 删除字符串两端相同字符后的最短长度题目介绍思路代码收获108. 将有序数组转换为二叉搜索树题…

各类遥测终端机RTU/水文遥测终端机简介

平升电子测遥测终端机RTU/水文遥测终端机基于4G、5G、NB-IoT、光纤、北斗三号卫星等通信网络&#xff0c;实现数据采集、存储、处理分析、传输&#xff0c;远程/自动控制现场泵、闸、阀等设备运行。它广泛应用于智慧水利领域的灌区信息化、水库安全监测、山洪灾害预警、水资源税…

泛型学习(java)

1.泛型的理解和好处 1.1看一个需求 1)请编写程序&#xff0c;在ArrayList中&#xff0c;添加3个Dog对象 Dog对象含有name和age,并输出name和age(要求使用getXxx()) 先使用传统的方法来解决->引出泛型 import java.util.ArrayList;public class Generic01 {public stati…

前端性能优化(一):指标和工具

目录 一&#xff1a;性能指标和优化目标 1.1.网络加载性能 1.2.用户交互体验 二&#xff1a;RAIL测量模型 2.1.Response&#xff08;响应&#xff09;: 处理事件应在在50ms内完成 2.2.Animation&#xff08;动画&#xff09;: 每10ms产生一帧 2.3.Idle&#xff08;空闲&…

SpringBoot — 初始创建项目小白教程

这里写目录标题前言SpringBoot简介重要策略Spring Boot 项目约定IntelliJ IDEA 直接创建Maven项目改造创建常见项目结构代码层资源文件结构主要文件说明SpringBootApplication 注解分析总结前言 使用 Servlet/JSP 开发 JavaWeb 时&#xff0c;一个接口对应一个Servlet&#xf…

mysql分区之RANGE类型

目录 首先查看MySQL是否支持分区 在实际操作分区前我们得了解下分区的几点限制&#xff1a; RANGE分区实操 SQL如何查询分区数据 首先查看MySQL是否支持分区 show plugins; 当查询结果显示partition的状态为active则表示当前MySQL版本支持分区。分区方案一般有四种&#…

CVPR 2017|SfMLearner:单目视频中深度和姿态估计的无监督算法

&#x1f3c6;作者提出了一个单目相机的视频序列进行深度估计与运动估计&#xff0c;作者的方法是完全无监督的&#xff0c;端到端的学习&#xff0c;作者使用了单视角深度网络和多姿态网络&#xff0c;提出了一个图像&#xff08;predict&#xff09;与真实的下一帧&#xff0…

09---Vue使用路由

由于之前数据、主页全部放在Home.vue中&#xff0c;不能够实现复用&#xff0c;于是&#xff0c;现在进行拆分&#xff0c;拆分出数据主体&#xff08;user.vue&#xff09;&#xff0c;侧边栏&#xff08;aside&#xff09;&#xff0c;顶部栏&#xff08;Header&#xff09;&…

SpringCloudAlibaba 学习笔记

❤ 作者主页&#xff1a;Java技术一点通的博客 ❀ 个人介绍&#xff1a;大家好&#xff0c;我是Java技术一点通&#xff01;(&#xffe3;▽&#xffe3;)~* &#x1f34a; 记得关注、点赞、收藏、评论⭐️⭐️⭐️ &#x1f4e3; 认真学习&#xff0c;共同进步&#xff01;&am…

疫情卷土重来,如何利用SRM系统打造数字化的“免疫系统”

2022年末&#xff0c;国内疫情再次卷土重来&#xff0c;形势严峻。国内企业也再次面临业务发展的压力。但实际上&#xff0c;在疫情常态化后&#xff0c;我国许多大中型企业都建立了全面的数字化“免疫系统”&#xff0c;增强了抗风险和跨周期的能力&#xff0c;大大增强了抵御…

【B站】Presto + Alluxio:B站数据库系统性能提升实践

欢迎来到【微直播间】&#xff0c;2min纵览大咖观点 在日常线上生产环境中有大量的数据需要被访问&#xff0c;为了保证数据同步以及查询效率&#xff0c;需要耗费较大的资源&#xff0c;同时&#xff0c;很多被查询和访问的数据是重复的&#xff0c;这对数据库系统造成极大压…

C++类和对象概念及实现详解(下篇)

文章目录 一、类的六个默认成员函数详解 1、拷贝构造 1、1 拷贝构造的引入及概念 1、2 拷贝构造函数的特征 2、赋值运算符重载 2、1 运算符重载 2、2 赋值运算符重载 3、普通对象取地址 4、const对象取地址 二、类和对象重点知识点 1、初始化列表 2、static成员 3、友元函数 4、…

一文带你走进MySQL索引

文章目录索引1. 索引的介绍2. 索引的本质3. 索引的结构3.1 Hash3.2 B树3.3 常见面试题之为什么用B树4. 索引的分类4.1 功能逻辑层次4.2 存储形式层次5. 索引的失效5.1 最左前缀原则5.2 索引失效的场景6. 索引常见面试题7. 总结及参考文献索引 1. 索引的介绍 索引是通过某种算…

潘多拉-视频播放器,一个轻量的视频播放器

潘多拉-视频播放器 轻量视频播放器,该项目是从https://github.com/getActivity/AndroidProject-Kotlin 中抽离出的一个视频播放器,之前没有 单独设置项目,我在使用过程中觉得这个挺方便好用的,所以为了方便使用,单独剥离出来,可以单独在项目中使用,后续我也会基于这个项目进行…

【数据结构】Leetcode旋转数组

目录 一、题目说明 二、题目解析 一、题目说明 题目链接&#xff1a;leetcode旋转数组 给你一个数组&#xff0c;将数组中的元素向右轮转k个位置&#xff0c;其中k是非负数。 示例1&#xff1a; 输入&#xff1a;nums [1,2,3,4,5,6,7],k 3 输出&#xff1a;[5,6,7,1,2,3,4…