B-Tree详解及编码实现

一、概念和特性

      1、定义

        B-Tree是一种平衡的多叉树,适用于外查找多路搜索树,这种数据结构能够保证数据节点查找、顺序访问、插入、删除的动作,其平均时间复杂读控制在O(logN)内;B树为系统大块数据的读写操作做了优化,少定位记录时所经历的中间过程,加快存储速度。

       理解B-Tree的工作原理,必须先介绍阶的概念。假如一个m阶的B-Tree,则这个数需要满足以下条件:

         (1)定义任意非叶子结点最多只有m(m>2)个子节点;

         (2)根节点的儿子节点数为[2, m],除根节点以外的非叶子节点的儿子数为[m/2, m];

         (3)每个节点存放[m/2-1,m-1]个关键字(m/2向上取整);

         (4)非叶子节点有k个子节点,则关键字个数为k-1;

         (5)非叶子节点关键字k[i+1]大于k[i]所指向的儿子节点,k[i]小于自生所指向的儿子节点; 

        (6)所有的叶子节点位于同一层;

         2、特性

        (1)关键字集合分布在整颗树中,任何一个关键字出现且只出现在一个结点中;

        (2)搜索有可能在非叶子节点结束;        

        (3)其搜索性能等价于在关键字全集内做一次二分查找;

        (4)自动层次控制。

         由于m/2的限制,在插入结点时,如果结点已满,需要将结点分裂为两个各占m/2的结点;删除结点时,需将两个不足m/2的兄弟节点合并。

二、B树的应用

          B-Tree这种数据结构常被应用在数据库和文件系统的实现上。

         B-Tree是为磁盘等外存储设备设计的一种平衡查找树。系统从磁盘读取数据到内存时是以磁盘块(block)为基本单位的,位于同一个磁盘块中的数据会被一次性读取到内存中,而不是需要什么取什么,这将会减少磁盘I/O次数,提高查询效率,这遵循计算机的局部性原理

三、B-Tree的变体B+Tree

       B+Tree是在B-Tree基础上的一种优化,使其更适合实现外存储索引结构, B+Tree具有以下几个特点:

      1、有m个子树的节点包含有m个元素(B-Tree中是m-1);

      2、根节点和分支节点中不保存数据,只用于索引,所有数据都保存在叶子节点中;

     3、所有分支节点和根节点都同时存在于子节点中,在子节点元素中是最大或者最小的元素;

     4、叶子节点会包含所有的关键字,以及指向数据记录的指针,并且叶子节点本身是根据关键字的大小从小到大顺序链接。

        以数据库mysql为例,mysql的InnoDB存储引擎中有页的概念,页是其磁盘管理的最小单位。InnoDB存储引擎中默认每个页的大小为16KB,因此InnoDB每次申请磁盘空间时都会是若干地址连续磁盘块来达到页的大小16KB,InnoDB在把磁盘数据读入到磁盘时会以页为基本单位,在查询数据时如果一个页中的每条数据都能有助于定位数据记录的位置,这将会减少磁盘I/O次数,提高查询效率。

       假如非叶子节点索引关键字平均大小为100byte,那么三层树高可以支持(16*1024/100)*(16*1024/100)*(16*1024*100),大约支持430万条记录高效查询。

四、B-Tree编码实现

1、函数声明
#ifndef _B_TREE_H__
#define _B_TREE_H__

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <math.h>
#include <string.h>

#define DEGREE 5
#define KEY_NUM (DEGREE-1)
#define MID (DEGREE/2)
// 插入数据成功
#define INSERT_SUC 0;
// 插入数据失败
#define INSERT_FAIL 500;

typedef  int  BtreeData;
typedef  struct btreenode
{
    /**关键字数组, 数组长度为DEGREE-1*/
    BtreeData* keys;
    /**孩子结点*/
    struct btreenode**  childNodes;
    /**父节点:为了便于操作减少遍历*/
    struct btreenode* parent;
    /**当前关键字个数*/
    int  curKeysNum;
}BtreeNode;

/**
 * 创建结点
 * @brief create_btreenode
 * @return
 */
BtreeNode*  create_btreenode();

/**
 * 插入数据
 * @brief insert_btreenode
 * @param root
 * @param data
 * @return
 */
int  insert_btreenode(BtreeNode** root,BtreeData  data);

/**
 * 查找关键字下标位置
 * @brief find_keys_index
 * @return
 */
int  find_keys_index(BtreeNode* node,BtreeData data);

/**
 * 通过下标查找child节点
 * @brief find_node_by_index
 * @param node
 * @param index
 * @return
 */
BtreeNode* find_childnode_by_keyindex(BtreeNode* node,BtreeData  data);

/**
 * 将当前数值插入到关键字数组
 * @brief insert_data_to_keys
 * @return index 返回关键字坐标
 */
int add_data_to_keys(BtreeNode* node,BtreeData data);

/**
 * 分裂操作
 * @brief division_btreenode
 * @param node
 */
void  division_btreenode(BtreeNode** root,BtreeNode* node);

/**
 * 查找关键字所在的节点
 * @brief find_btrenode_by_key
 * @param root
 * @param node
 * @return
 */
BtreeNode*   find_btrenode_by_key(BtreeNode* root,BtreeData  data);

/**
 * 删除节点
 * @brief delete_btreenode
 * @param root
 * @param data
 */
void  delete_btreenode(BtreeNode** root,BtreeData  data);

/**
 * 删除关键字
 * @brief delete_key_by_index
 * @param root
 * @param data
 */
void  delete_key_by_index(BtreeNode* node,BtreeData  data);

/**
 * 合并操作
 * @brief merge_btreenode
 * @param root
 * @param node
 */
void   merge_btreenode(BtreeNode** root,BtreeNode* node,BtreeData data);

/**
 * 遍历某个节点的关键字
 * @brief show_node_kyes
 * @param node
 * @param func
 */
void  show_node_kyes(BtreeNode* node);

/**
 * 遍历B-Tree
 * @brief show_btreenode
 * @param root
 */
void   show_btreenode(BtreeNode*  root);

#endif
2、函数定义
#include "btree.h"

BtreeNode*  create_btreenode()
{
    BtreeNode* btreeNode = (BtreeNode*) malloc(sizeof(BtreeNode));
    if(btreeNode==NULL)
    {
        perror("malloc btree_node failed");
        return NULL;
    }
    int keySizeLen = sizeof(BtreeData)*KEY_NUM;
    BtreeData*  keys = (BtreeData*) malloc(keySizeLen);
    memset(keys,0,keySizeLen);
    if(keys==NULL)
    {
        perror("malloc keys failed");
        free(btreeNode);
        return NULL;
    }
    int  childSizeLen = sizeof(BtreeNode*)*DEGREE;
    BtreeNode** childNode = (BtreeNode**) malloc(sizeof(BtreeNode*)*DEGREE);
    memset(childNode,0,childSizeLen);
    if(childNode==NULL)
    {
        perror("malloc childNode failed");
        free(keys);
        free(btreeNode);
        return NULL;
    }
    btreeNode->keys = keys;
    btreeNode->childNodes=childNode;
    btreeNode->parent=NULL;
    btreeNode->curKeysNum=0;
    return btreeNode;
}

int  insert_btreenode(BtreeNode** rootPtr,BtreeData  data)
{
    ///初始化根节点
    if((*rootPtr)==NULL)
    {
        BtreeNode* newNode = create_btreenode();
        if(newNode==NULL)
        {
            return INSERT_FAIL;
        }
        newNode->keys[0] = data;
        newNode->curKeysNum = 1;
        (*rootPtr)= newNode;
        return INSERT_SUC;
    }
    ///查找适合插入数据的节点
    BtreeNode* tragetNode = find_childnode_by_keyindex(*rootPtr,data);
    show_node_kyes(tragetNode);
    printf("\n");
    /// 添加关键字
    if(tragetNode!=NULL)
    {
        //添加关键字
        add_data_to_keys(tragetNode,data);
        //当关键字达到KEY_NUM时候,插入新的关键字需要对节点进行分裂操作
        division_btreenode(rootPtr,tragetNode);
        return INSERT_SUC;
    }
    return INSERT_FAIL;
}

int  find_keys_index(BtreeNode* node,BtreeData data)
{
    int index = 0;
    BtreeData* keys = node->keys;
    //平衡查找当前节点关键字的索引
    while(index<node->curKeysNum && keys[index]<data)
    {
        index++;
    }
    return index;
}

BtreeNode* find_childnode_by_keyindex(BtreeNode* node,BtreeData  data)
{
    ///printf("find_childnode_by_keyindex-----data=%d\n",data);
    if(node == NULL)
    {
        perror("find_childnode_by_index fail ,node is null ");
        return NULL;
    }

    BtreeNode** chids=node->childNodes;
    if((*chids)==NULL)
    {
        // 到达叶子节点终止递归
        return node;
    }
    /// 根据索引查找当前数值适合存放的节点
    int index = find_keys_index(node,data);
        ///递归查找子节点
    return find_childnode_by_keyindex(chids[index],data);
}

int add_data_to_keys(BtreeNode* node,BtreeData data)
{
    ///printf("add_data_to_keys  key -> data=%d\n",data);
    int c = 0 ;
    int index = find_keys_index(node,data);
    BtreeData* keys = node->keys;
    node->curKeysNum = node->curKeysNum +1;
    BtreeData  tmp[KEY_NUM];
    for(;c<KEY_NUM;c++)
    {
        tmp[c] = keys[c];
    }
    c = 0 ;
    for(;c<node->curKeysNum;c++)
    {
        if(c >index)
        {
            keys[c] = tmp[c-1];
        }
    }
    keys[index] = data;
    return index;
}

/**
 * 分裂操作
 * @brief division_btreenode
 * @param root
 * @param node
 */
void  division_btreenode(BtreeNode** root,BtreeNode* node)
{
    if(node->curKeysNum<=KEY_NUM)
    {
        return;
    }
    printf("division_btreenode start \n");
    BtreeNode* leftNode = create_btreenode();
    if(leftNode==NULL)
    {
        perror("create left  node  fail");
        return;
    }
    BtreeNode* rightNode = create_btreenode();
    if(rightNode==NULL)
    {
        perror("create right  node  fail");
        free(leftNode);
        return;
    }
    BtreeData*  keys =  node->keys;
    int index = 0;
    while(index < DEGREE/2)
    {
        leftNode->keys[index]=node->keys[index];
        index++;
    }
    index = 0;
    while(index<DEGREE/2)
    {
        rightNode->keys[index] = node->keys[DEGREE/2+index+1];
        index++;
    }
    leftNode->curKeysNum =  DEGREE/2;
    rightNode->curKeysNum = DEGREE/2;
    BtreeData   divisionKey = keys[MID];
    BtreeNode*  parent = node->parent;
    if(parent == NULL)
    {
        /// 根节点分裂
        BtreeNode**  childs = node->childNodes;
        if((*childs)!=NULL)
        {
            index = 0 ;
            int m=0,n=0;
            while (index<=DEGREE) {
                if(index<=MID)
                {
                    leftNode->childNodes[m]=childs[index];
                    m++;
                }
                if(index>MID)
                {
                    rightNode->childNodes[n]=childs[index];
                    n++;
                }
                index++;
            }
        }
        index = 0;
        //重置当前node节点的childs的parent节点
        while (index<=DEGREE && (*(node->childNodes))!=NULL) {
            node->childNodes[index]->parent =index<=MID?leftNode:rightNode;
            index++;
        }
        leftNode->parent =  node;
        rightNode->parent=  node;
        node->childNodes[0] = leftNode;
        node->childNodes[1] = rightNode;
        node->curKeysNum=1;
        /// 重置根结点
        node->keys[0]=divisionKey;
        index= 1;
        while (index<KEY_NUM) {
            node->keys[index]= 0;
            index++;
        }
        (*root)=node;
    }
    else
    {
        int  keyIndex = add_data_to_keys(parent,divisionKey);
        index = 0;
        BtreeNode**  childs = parent->childNodes;
        BtreeNode*   temp[DEGREE];
        for(;index<DEGREE;index++)
        {
            temp[index]= childs[index];
        }
        index = keyIndex;
        while(index<=KEY_NUM-2)
        {
            childs[index+2]=temp[index+1];
            index++;
        }
        index = 0;
        重置当前node节点的childs的parent节点
        while (index<=DEGREE && (*(node->childNodes))!=NULL) {
            node->childNodes[index]->parent =index<=MID?leftNode:rightNode;
            index++;
        }
        leftNode->parent = parent;
        rightNode->parent= parent;
        childs[keyIndex] = leftNode;
        childs[keyIndex+1]= rightNode;
        ///递归处理分裂操作
        division_btreenode(root,parent);
    }
}

BtreeNode*  find_btrenode_by_key(BtreeNode* root,BtreeData data)
{
    if((root)==NULL)
    {
        return NULL;
    }
    int index = find_keys_index(root,data);
    BtreeData  keyData = root->keys[index];
    if(keyData==data)
    {
        return  root;
    }
    BtreeNode*  node = root->childNodes[index];
    return find_btrenode_by_key(node, data);
}

/**
 * 删除节点
 * @brief delete_btreenode
 * @param root
 * @param data
 */
void  delete_btreenode(BtreeNode** root,BtreeData  data)
{
    BtreeNode* tragetNode = find_btrenode_by_key(*root,data);
    ///BtreeNode**  childs = tragetNode->childNodes;
    delete_key_by_index(tragetNode,data);
    //处逻辑理合并
    merge_btreenode(root,tragetNode,data);
}

void  delete_key_by_index(BtreeNode* node,BtreeData  data)
{

    int index = find_keys_index(node,data);
    BtreeData* keys = node->keys;
    BtreeData  tmp[KEY_NUM];
    int c = 0;
    for(;c<KEY_NUM;c++)
    {
        tmp[c] = c<node->curKeysNum?keys[c]:0;
    }
    while(index < node->curKeysNum)
    {
        keys[index]=tmp[index+1];
        index++;
    }
    node->curKeysNum =node->curKeysNum-1;
}

/**
 * 合并操作
 * @brief merge_btreenode
 * @param root
 * @param node
 */
void   merge_btreenode(BtreeNode** root,BtreeNode* node,BtreeData data)
{
    if(node==NULL)
    {
        return;
    }
    if(node->parent==NULL)
    {
        (*root) =  node;
        return;
    }
    BtreeNode*  parent = node->parent;
    int index = find_keys_index(parent,data);
    BtreeNode** childs = parent->childNodes;
    BtreeNode*  leftNode;
    BtreeNode*  rightNode;
    if(index<parent->curKeysNum)
    {
        leftNode=childs[index];
        rightNode=childs[index+1];
    }
    else
    {
        leftNode=childs[index-1];
        rightNode=childs[index];
    }
    int totalKeysNum= 1 + leftNode->curKeysNum + rightNode->curKeysNum;
    if(totalKeysNum>KEY_NUM)
    {
        return;
    }
    ///执行合并
    int  c = 0;
    int  leftMidIndex =  leftNode->curKeysNum;
    BtreeData parentMergeData = parent->keys[index-1];
    leftNode->keys[leftMidIndex] = parentMergeData;
    //重置关键字
    while (c < rightNode->curKeysNum) {
        leftNode->keys[leftMidIndex+1+c]=rightNode->keys[c];
        c++;
    }
    c= 0;
     /// 重置子节点
    while(c<=rightNode->curKeysNum)
    {
        leftNode->childNodes[leftMidIndex+1+c]= rightNode->childNodes[c];
        c++;
    }
    leftNode->curKeysNum = totalKeysNum;
    free(rightNode);
    if(parent->parent==NULL)
    {
        (*root) = leftNode;
        free(parent);
        return;
    }
    delete_key_by_index(parent,parentMergeData);
    merge_btreenode(root,parent,data);
}

void  show_node_kyes(BtreeNode* node)
{
    if(node==NULL)
    {
        printf("show_node_kyes  node  is null \n");
        return;
    }
    int  len =  node->curKeysNum;
    BtreeData* keys = node->keys;
    int  c = 0;
    for(;c<len;c++)
    {
        printf("%d ",keys[c]);
    }
}

void show_btreenode(BtreeNode*  root)
{
    if(root==NULL)
    {
        return;
    }
    BtreeNode** childs =  root->childNodes;
    int len  = root->curKeysNum;
    int c = 0 ;
    show_node_kyes(root);
    printf("\n");
    /// 为了方便看结果,这里值展示三层效果,如果需要展多层,可采用递归查询
    while((*childs)!=NULL && c<=len){
        BtreeNode* chid =  childs[c];
        show_node_kyes(chid);
        c++;
    }
    printf("\n");
    c=0;
    while((*childs)!=NULL && c<=len){
        BtreeNode* chid =  childs[c];
        BtreeNode** subChids = chid->childNodes;
        int n = 0;
        int subLen = chid->curKeysNum;
        while ((*subChids)!=NULL && n<=subLen ) {
            BtreeNode*  tmp =  subChids[n];
            show_node_kyes(tmp);
            n++;
        }
        c++;
    }
    printf("\n");
}
3、测试
#include <stdio.h>
#include "btree.h"

int main()
{
    printf("Hello World  Btree come !\n");
    BtreeData  arr[] = {20,10,11,12,30,31,32,33,15,17,18,5,8,26,35,6,36,37};
    //-----------------添加元素 分裂--------------------------
    //                      18
    //    8       12        ->         31       35
    //5 6 -> 10 11 -> 15 17 -> 20 26 30 -> 32 33 -> 36 37
    BtreeNode* root = NULL;
    int  i ;
    int len =  sizeof(arr)/sizeof(BtreeData);
    for(i=0;i<len;i++)
    {
        insert_btreenode(&root,arr[i]);
    }
    printf("\nstart ------show tree--------------add\n");
    show_btreenode(root);

    //-----------------删除元素 合并---------------------------
    //    8       12       18          31
    //5 6 -> 10 11 -> 15 17 -> 20 26 30 -> 32 33 35 36
    printf("\nstart ------show tree--------------del\n");
    delete_btreenode(&root,37);
    show_btreenode(root);

    return 0;
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

HCIP 交换

拓扑图&IP划分如下&#xff1a; 第一步&#xff0c;配制VLAN LSW1&#xff0c;LSW2&LSW3同理 检测 LSW1 LSW2 测试

最适合家用的洗地机哪个牌子好?清洁力强的洗地机推荐

随着家用市场的不断壮大&#xff0c;洗地机逐渐为人们熟知。众多厂家为提升深度清洁效果投入大量成本和时间&#xff0c;然而消费者在选择洗地机时往往难以判断品质。无线洗地机市场上涌现多个品牌&#xff0c;如何找到性能优越、实惠耐用的机型呢?在了解洗地机时&#xff0c;…

实战内网穿透NPS搭建过程

前提条件 首先你要有个公网IP的服务器&#xff0c;既然是内网穿透&#xff0c;那必然是通过公网IP或者域名访问本地服务。 官网下载地址 https://github.com/ehang-io/nps/releases 服务端 选择linux_amd64_server.tar.gz 客户端 选择windows_amd64_client.tar.gz 服…

列表的创建与删除

Python 中列表可以动态地添加、修改和删除元素&#xff0c;是 Python 编程中不可或缺的一部分。本文将介绍如何使用 Python 创建和删除列表&#xff0c;以及常用的方法和技巧。 创建列表 在 Python 中&#xff0c;我们可以使用一对方括号 [ ] 来创建一个空列表&#xff0c;也可…

UF_UI_select_with_single_dialog()通过单选对话框选择单个对象。对象可以通过光标或输入名称进行选择。对象被突显出来。

int response0;//返回用户操作类型&#xff0c;点了哪一种返回取消或者确定tag_t objtagNULL_TAG;//输出选择对象tag;double cursor[ 3 ];//输出光标位置tag_t view_tagNULL_TAG;//输出视图tag;UF_UI_select_with_single_dialog("请选择一个对象","获取对象类型…

dolphinscheduler节点二次开发需要改动的部分

dolphinscheduler节点二次开发需要改动的部分 前端 在dolphinscheduler-ui/public/images/task-icons/目录下新增两个节点的logo图片&#xff0c;一个为激活状态的一个为非激活状态的&#xff0c;如下。 修改文件dolphinscheduler-ui/src/views/projects/task/constants/task…

CSS高级技巧导读

1&#xff0c;精灵图 1.1 为什么需要精灵图&#xff1f; 目的&#xff1a;为了有效地减少服务器接收和发送请求的次数&#xff0c;提高页面的加载速度 核心原理&#xff1a;将网页中的一些小背景图像整合到一张大图中&#xff0c;这样服务器只需要一次请求就可以了 1.2 精灵…

centos7.9安装redmine5.1.1

前提&#xff1a; 安装mysql并新建数据库--教程太多了此步骤省略&#xff1b; 用sqlyog连上mysql创建数据库redmine&#xff1b; 1.下载redmine-5.1.1.tar.gz&#xff0c;上传到/usr/local/software目录下&#xff1b; 2.解压 cd /usr/local/software tar -zxvf redmine-5.…

JavaScript进阶:WebAPIs重点知识整理2

目录 1 对节点的相关操作 1.1 查找节点 1.1.1 查找节点的父节点 1.1.2 查找节点的子节点 1.1.3 查找节点的兄弟节点 1.2 新增节点&#xff08;先创建&#xff0c;后追加&#xff09; 1.3 克隆节点 1.4 删除节点 2 M 端&#xff08;移动端&#xff09;事件 3 JS清空表…

uniapp使用uni-forms表单校验无效

查看是否写了name属性&#xff0c;且name属性的属性值得和下面v-model绑定的一致&#xff0c;否则校验不生效 官网

C#string字符串相关面试题

C#字符串&#xff08;string&#xff09;是什么类型 C#中的字符串是一种引用类型&#xff0c;属于.NET Framework中的System.String类。在C#中&#xff0c;字符串是不可变的&#xff0c;也就是说&#xff0c;一旦被创建&#xff0c;就不能再被修改。这意味着对于任何字符串的操…

2024年可能会用到的几个地图可视化模板

前言 在数字化的过程中&#xff0c;数据可视化变得越来越重要。用户喜欢通过酷炫的视觉效果和直观的数据展示来理解数据。可视化地图组件是数据可视化的重要组成部分。这些地图组件提供多样化的效果&#xff0c;能够更好地展示数据的关系和地理分布&#xff0c;直观地将数据与…

JUC-CAS

1. CAS概述 CAS(Compare ans swap/set) 比较并交换&#xff0c;实现并发的一种底层技术。它将预期的值和内存中的值比较&#xff0c;如果相同&#xff0c;就更新内存中的值。如果不匹配&#xff0c;一直重试&#xff08;自旋&#xff09;。Java.util.concurrent.atomic包下的原…

二叉树

目录 1翻转二叉树 2对称二叉树 3二叉树的深度 最大深度 最小深度 4二叉树的结点数量 完全二叉树的结点数量 5平衡二叉树 6 中序 后序求前序 二叉树结构体如下&#xff1a; struct freenode {int data;struct freenode *lchild, *rchild;//左孩子 右孩子 }T; 1翻转二…

基于springboot+vue的在线商城系统(前后端分离)

博主主页&#xff1a;猫头鹰源码 博主简介&#xff1a;Java领域优质创作者、CSDN博客专家、公司架构师、全网粉丝5万、专注Java技术领域和毕业设计项目实战 主要内容&#xff1a;毕业设计(Javaweb项目|小程序等)、简历模板、学习资料、面试题库、技术咨询 文末联系获取 项目介绍…

大数据处理,Pandas与SQL高效读写大型数据集

大家好&#xff0c;使用Pandas和SQL高效地从数据库中读取、处理和写入大型数据集&#xff0c;以实现最佳性能和内存管理&#xff0c;这是十分重要的。 处理大型数据集往往是一项挑战&#xff0c;特别是在涉及到从数据库读取和写入数据时。将整个数据集加载到内存中的传统方法可…

【第十六课】哈希表(acwing-840模拟散列表 / 拉链法 / 开放寻址法 / c++代码 )

目录 前言 哈希表思想 拉链法 开放寻址法 acwing-840模拟散列表 拉链法代码如下 开放寻址法代码 前言 我对哈希表的印象就是&#xff1a;感觉可以类比数组&#xff0c;像数组的下标和该下标所对的元素之间的关系一样&#xff0c;就是比如ha[0]1&#xff0c;那么我下标为…

mask transformer相关论文阅读

前面讲了mask-transformer对医学图像分割任务是非常适用的。本文就是总结一些近期看过的mask-transformer方面的论文。 因为不知道mask transformer是什么就看了一些论文。后来得出结论&#xff0c;应该就是生成mask的transformer就是mask transformer。 DETR 很多这些论文都…

机器学习 | 掌握Matplotlib的可视化图表操作

Matplotlib是python的一个数据可视化库&#xff0c;用于创建静态、动态和交互式图表。它可以制作多种类型的图表&#xff0c;如折线图、散点图、柱状图、饼图、直方图、3D 图形等。以渐进、交互式方式实现数据可视化。当然博主也不能面面俱到的讲解到所有内容&#xff0c;详情请…

新特性Record最全用法总结---动力节点总结

目录 0、有用的新特性 一、Record 1.1、Record的介绍&#xff1a; 1.2、Record的声明&#xff1a; 1.3、Record的创建&#xff1a; 1.4、Record使用举例&#xff1a; 1.5、Record-实例方法、静态方法 1.6、Record-三类构造方法 1.6.1、紧凑型构造、定制构造方法&#…