数据结构07:查找[C++][朴素二叉排序树BST]

news2024/10/6 22:25:10

图源:文心一言

考研笔记整理8k+字,小白友好、代码可跑,请小伙伴放心食用~~🥝🥝

第1版:查资料、写BUG、画导图、画配图~🧩🧩

参考用书:王道考研《2024年 数据结构考研复习指导》

参考用书配套视频:7.3_1 二叉排序树_哔哩哔哩_bilibili

特别感谢: Chat GPT老师、文心一言老师~


📇目录

📇目录

🦮思维导图 

🧵基本概念

⏲️定义

🌰推算举栗

⌨️代码实现

🧵分段代码

 🔯P0:调用库文件

 🔯P1:定义结点与指针

 🔯P2:封装创建结点

 🔯P3:插入结点

 🔯P4:构造二叉树

 🔯P5:树的遍历

 🔯P6:结点查询

 🔯P7:结点删除

 🔯P8:main函数

🧵完整代码

 🔯P0:完整代码

 🔯P1:执行结果

🔚结语


🦮思维导图 

备注:

  • 思维导图为整理王道教材第7章 查找的所有内容;
  • 本篇仅涉及到朴素二叉排序树(BST)的代码;
  • 后期会在博文列表中整理平衡树、红黑树的相关内容[交可爱Ada小助手布置的红黑树作业],也可能会增加B树、线性查找的相关内容~    //博文写作时间很长,但是愿意点赞的小伙伴很少,因此还在犹豫中~😶‍🌫️😶‍🌫️

🧵基本概念

⏲️定义

  • 二叉排序树,若树非空,满足下列特性:
    • 若左子树非空:左子树上所有结点的值<根结点的值;
    • 若右子树非空:右子树上所有结点的值>根结点的值;
    • 左、右子树分别是一棵二叉排序树。
  • 简而言之,满足“ 左子树结点值 < 根结点值<右子树结点值 ” 的二叉树。

树的插入操作:与结点进行比较,小于则向左子树遍历,大于则向右子树遍历,直到遍历为空结点时,插入该结点。因此,插入的结点均为叶子结点。

注意:同一个序列不同的输入顺序,可能会得到不同的二叉树~

🌰推算举栗

  • 输入序列为递增/递减序列,或者从两端向中间逼近,例如:{3、7、8、9、10、15}、{15、3、7、10、9、8},这种就很容易形成度为1的长树~
  • 输入序列为从中间向两段逼近,例如:{8、7、10、3、9、15},这种就很容易形成比较理想的宽树形[度为2],甚至是平衡树~ //这棵树的创建过程博文后会详细说明~

平衡树的定义,可见:🌸数据结构05:树与二叉树[C++]

  • ASL:平均查找长度,计算方式为 Σ(第 i 层结点数 x i 的层高)/ (结点个数),表示整棵树所有查找过程中,进行关键字比较次数的平均值~
  • 通过图中比较,可知:
    • 左侧树的查找:接近链表,与顺序查找相似,时间复杂度近似O(n);
    • 右侧树的查找:接近平衡树,与折半查找相似,时间复杂度近似O(log n);
  • 因此,朴素二叉排序树的查找的时间复杂度在O(n)~O(log n)波动,可以通过尽量调整树的高度以降低时间复杂度[🌸涉及到平衡二叉树,算法会在下一篇博文中提到]~

下面我们以图中右侧的小树为例,说明如何创建及遍历朴素二叉排序树~


图源:文心一言

⌨️代码实现

🧵分段代码

 🔯P0:调用库文件

此次用到输入输出流文件iostream与创造动态数组的向量vector~

#include <iostream>
#include <vector>

 🔯P1:定义结点与指针

typedef struct BSTNode {
    int data;    //数据域
    struct BSTNode *lchild, *rchild;    //左孩子指针、右孩子指针
}BSTNode,*BiTree;    //结点BSTNode,指针BiTree

 🔯P2:封装创建结点

创建结点的步骤在创建树时重复出现,因此使用函数封装~

思路:(1)创建结点、(2)赋值、(3)指针置空,(4)返回结点~

//创建结点
BSTNode* CreateNode(int data) {
    BSTNode* newNode = new BSTNode();    //新建结点
    newNode->data = data;         //赋值数据域
    newNode->lchild = nullptr;    //指针置空
    newNode->rchild = nullptr;
    return newNode;               //返回结点
}

 🔯P3:插入结点

采用递归的方式创建树,朴素二叉树插入的结点通常为叶节点:

  • 若二叉排序树为空,则创建根结点;若结点为空,则插入结点。
  • 若二叉树不为空:
    • 关键字 = 根结点值,树中已有此元素;
    • 关键字<根结点值,继续遍历左子树;
    • 关键字>根结点值,继续遍历右子树。
int BST_Insert(BiTree &tree, int key) {
    if (tree == NULL) {            //若树为空,创建根结点;若遍历到结点为空,插入结点
        tree = CreateNode(key);
        return 1;
    }
    else if(key == tree->data)     //若结点已在树中存在,返回错误
        return 0;

    else if(key < tree->data)      //若待插入结点<关键字
        return BST_Insert(tree->lchild,key);    //向左子树查找

    else                           //若待插入结点>关键字
        return BST_Insert(tree->rchild,key);    //向右子树查找
}

 🔯P4:构造二叉树

通过main函数中声明的树地址BiTree &tree,以及传入的整数型动态数组std::vector<int> &vec,通过调用P3插入结点的函数完成树的创建~

void Creat_BST(BiTree &tree, std::vector<int> &vec){
    tree = nullptr;    //初始时树置空

    //将main中传入的数组,每个元素以插入的操作完成树的创建
    for(int i = 0; i < vec.size(); i++){    
        BST_Insert(tree, vec[i]);
    }
}

具体的创建过程可参考下图~

 🔯P5:树的遍历

传入树的根结点内存地址,由于二叉树遵循:“左<根<右” 的原则,因此可以通过二叉树的中序遍历完成,此处采用递归方式完成~

void InOrderTraversal(BiTree tree) {
    if (tree == nullptr)    //如果树为空,返回
        return;

    InOrderTraversal(tree->lchild);    //遍历左子树

    std::cout << tree->data << " ";    //输出当前结点的值

    InOrderTraversal(tree->rchild);    //遍历右子树
}

 如果我没记错的话,运行起来应该是这样的~

  • 树指针的路径一路向左,结点8、结点7、结点3[以上3个结点入系统调用栈],结点3没有左孩子,打印结点3,结点3出栈;
  • 结点3没有右孩子结点,系统调用栈退1位,结点7出栈,打印结点7
  • 结点7没有右孩子结点,系统调用栈退1位,结点8出栈,打印结点8
  • 结点8没有右孩子结点,栈为空,向结点8的右子树结点10的左子树结点9移动[结点10、结点9入系统调用栈],结点9没有左孩子,打印结点9,出栈;
  • 结点9没有右孩子结点,系统调用栈退1位,结点10出栈,打印结点10
  • 结点10具有右孩子结点,打印结点10的右孩子结点15
  • 结点15没有孩子结点,且系统调用栈空,结束递归过程。

对于中序遍历原理感兴趣的小伙伴可以参考: 🌸数据结构05:树与二叉树[C++],该篇博文也含非递归方式先序、中序、后序遍历树的代码 [ 区别就是手动创建了一个调用栈 ]~

 🔯P6:结点查询

此处为了方便后序的删除操作,函数这边写成了结点的形式BSTNode*,需要传入两个值,树的地址BiTree tree和关键字int key~

  • 若树非空,且查询的值key与树中当前结点的值不同:
    • 查询的值key < 树中当前结点的值,向左子树走;
    • 查询的值key > 树中当前结点的值,向右子树走;
  • 若树为空或未找到结点,输出:未找到结点;
  • 除上述情况,输出:找到目标结点,与查询的值key 。
BSTNode* LocateElem(BiTree tree, int key) {
    while (tree != nullptr && key != tree->data) {    //树非空,且结点与关键字不等
        if (key < tree->data)    //关键字 < 结点,向左子树查询
            tree = tree->lchild;
        else                     //关键字 > 结点,向左子树查询
            tree = tree->rchild;
    }

    if (tree == nullptr) {    //数为空遍历结束,未找到结点,返回
        std::cout << "未找到目标节点\n";
        return nullptr;
    } else {                  //反馈信息:找到目标结点
        std::cout << "找到目标节点:" << tree->data << "\n";
        return tree;
    }
}

 🔯P7:结点删除

删除的情况略微复杂,传入树的地址BiTree tree和关键字int key~

删除可分为以下4种情况考虑——

  • 叶子结点:
    • 删除结点对于树的结构没有影响~
    • 当前孩子的父节点→NULL,并删除本结点~
  • 单左子树结点:
    • 删除结点时,其相邻的右孩子结点需要替代本结点的位置~
    • 当前孩子的父节点→当前孩子的子结点,并删除本结点~
  • 单右子树结点:
    • ​​​​​​​删除结点时,其相邻的左孩子结点需要替代本结点的位置~
    • 当前孩子的父节点→当前孩子的子结点,并删除本结点~
  • 双子树结点:
    • ​​​​​​​删除结点时,其右子树最大的结点(即中序遍历后继结点)需要替代本结点的位置~
    • 当前结点的数值==中序遍历后继结点的数值~
    • 但中序遍历后继结点此时可能会有孩子结点,因此需要其当前孩子的父节点→当前孩子的子结点(同单子树结点)~

有点绕对不对,用图模拟一下这个过程,如果我没有理解错的话是这样的~

void BST_Delete(BiTree& tree, int key) {
    if (tree == nullptr) {
        return;  // 树为空,直接返回
    }

    BiTree parent = nullptr;  // 记录要删除结点的父节点
    BiTree current = tree;    // 当前遍历到的结点

    // 查找要删除的结点以及其父节点
    while (current != nullptr && current->data != key) {
        parent = current;

        if (key < current->data) {
            current = current->lchild;  // 向左子树查找
        } else {
            current = current->rchild;  // 向右子树查找
        }
    }

    if (current == nullptr) {
        return;  // 未找到要删除的结点
    }

    // 根据不同情况进行删除
    if (current->lchild == nullptr && current->rchild == nullptr) {
        // 叶子结点,直接删除
        if (parent == nullptr) {
            tree = nullptr;  // 删除的是根结点
        } else if (parent->lchild == current) {
            parent->lchild = nullptr;  // 删除的是左子结点
        } else {
            parent->rchild = nullptr;  // 删除的是右子结点
        }

        delete current;  // 释放内存
    } else if (current->lchild == nullptr) {
        // 左子树为空,用右子树替代当前结点
        if (parent == nullptr) {
            tree = current->rchild;  // 删除的是根结点
        } else if (parent->lchild == current) {
            parent->lchild = current->rchild;  // 删除的是左子结点
        } else {
            parent->rchild = current->rchild;  // 删除的是右子结点
        }

        delete current;  // 释放内存
    } else if (current->rchild == nullptr) {
        // 右子树为空,用左子树替代当前结点
        if (parent == nullptr) {
            tree = current->lchild;  // 删除的是根结点
        } else if (parent->lchild == current) {
            parent->lchild = current->lchild;  // 删除的是左子结点
        } else {
            parent->rchild = current->lchild;  // 删除的是右子结点
        }

        delete current;  // 释放内存
    } else {
        // 左右子树都不为空,用右子树中最小的结点替代当前结点
        BiTree minNode = current->rchild;  // 最小结点
        BiTree minNodeParent = current;    // 最小结点的父节点

        while (minNode->lchild != nullptr) {
            minNodeParent = minNode;
            minNode = minNode->lchild;
        }

        current->data = minNode->data;  // 用最小结点的值替代当前结点的值

        if (minNodeParent == current) {
            minNodeParent->rchild = minNode->rchild;  // 最小结点是当前结点的右子结点
        } else {
            minNodeParent->lchild = minNode->rchild;  // 最小结点是当前结点右子树的最左子结点
        }

        delete minNode;  // 释放内存
    }
}

 🔯P8:main函数

main函数除了P0~P6的函数调用,就创建了1棵树,以及示意性地增加了与删除了结点~

int main() {
    BiTree tree = nullptr;
    //BiTree root = nullptr;

    // 增加结点:动态数组
    std::vector<int> vec = {8, 7, 10, 3, 9, 15};
    Creat_BST(tree, vec);
    //root = tree;  // 记录根节点的指针

    std::cout << "\n";

    // 输出结点:中序遍历
    std::cout << "遍历二叉树: ";
    InOrderTraversal(tree);
    std::cout << "\n";

    // 按值查找[本例为7]
    int target = 7;
    LocateElem(tree, target);

    //插入结点
    int node2 = 11;
    BST_Insert(tree, node2);
    std::cout << "插入节点:" << node2 << "\n";

    //删除结点
    int node3 = 8;
    BST_Delete(tree, node3);
    std::cout << "删除节点:" << node3 << "\n";

    // 输出结点:中序遍历
    std::cout << "遍历二叉树: ";
    InOrderTraversal(tree);

    std::cout << std::endl;

    return 0;
}

🧵完整代码

 🔯P0:完整代码

为了凑本文的字数,我这里贴一下整体的代码,删掉了细部注释~

Ps:改掉了以往博文二叉树需要手动输入结点搭建的缺点,扔到C++在线网站就可以测~🫥🫥

//头文件
#include <iostream>
#include <vector>

//结点结构
typedef struct BSTNode{
    int data;
    struct BSTNode *lchild, *rchild;
}BSTNode,*BiTree;

//创建结点
BSTNode* CreateNode(int data) {
    BSTNode* newNode = new BSTNode();
    newNode->data = data;
    newNode->lchild = nullptr;
    newNode->rchild = nullptr;
    return newNode;
}

//插入结点
int BST_Insert(BiTree &tree, int key) {
    if (tree == NULL) {
        tree = CreateNode(key);
        return 1;
    }
    else if(key == tree->data)
        return 0;

    else if(key < tree->data)
        return BST_Insert(tree->lchild,key);

    else
        return BST_Insert(tree->rchild,key);
}

//创建树
void Creat_BST(BiTree &tree, std::vector<int> &vec){
    tree = nullptr;
    for(int i = 0; i < vec.size(); i++){
        BST_Insert(tree, vec[i]);
    }
}

//中序遍历
void InOrderTraversal(BiTree tree) {
    if (tree == nullptr)
        return;

    InOrderTraversal(tree->lchild);
    std::cout << tree->data << " ";
    InOrderTraversal(tree->rchild);
}

//按值查找
BSTNode* LocateElem(BiTree tree, int key) {
    while (tree != nullptr && key != tree->data) {
        if (key < tree->data)
            tree = tree->lchild;
        else
            tree = tree->rchild;
    }

    if (tree == nullptr) {
        std::cout << "未找到目标节点\n";
        return nullptr;
    } else {
        std::cout << "找到目标节点:" << tree->data << "\n";
        return tree;
    }
}

//删除结点
void BST_Delete(BiTree& tree, int key) {
    if (tree == nullptr) {
        return;
    }

    BiTree parent = nullptr;
    BiTree current = tree;  

    // 查找要删除的结点以及其父节点
    while (current != nullptr && current->data != key) {
        parent = current;

        if (key < current->data) {
            current = current->lchild;  
        } else {
            current = current->rchild; 
        }
    }

    if (current == nullptr) {
        return; 
    }

    // 根据不同情况进行删除
    if (current->lchild == nullptr && current->rchild == nullptr) {
        // 叶子结点,直接删除
        if (parent == nullptr) {
            tree = nullptr; 
        } else if (parent->lchild == current) {
            parent->lchild = nullptr; 
        } else {
            parent->rchild = nullptr; 
        }

        delete current;
    } else if (current->lchild == nullptr) {
        // 左子树为空,用右子树替代当前结点
        if (parent == nullptr) {
            tree = current->rchild; 
        } else if (parent->lchild == current) {
            parent->lchild = current->rchild; 
        } else {
            parent->rchild = current->rchild; 
        }

        delete current;
    } else if (current->rchild == nullptr) {
        // 右子树为空,用左子树替代当前结点
        if (parent == nullptr) {
            tree = current->lchild; 
        } else if (parent->lchild == current) {
            parent->lchild = current->lchild; 
        } else {
            parent->rchild = current->lchild; 
        }

        delete current; 
    } else {
        // 左右子树都不为空,用右子树中最小的结点替代当前结点
        BiTree minNode = current->rchild; 
        BiTree minNodeParent = current;  

        while (minNode->lchild != nullptr) {
            minNodeParent = minNode;
            minNode = minNode->lchild;
        }

        current->data = minNode->data; 

        if (minNodeParent == current) {
            minNodeParent->rchild = minNode->rchild; 
        } else {
            minNodeParent->lchild = minNode->rchild; 
        }

        delete minNode; 
    }
}

int main() {
    BiTree tree = nullptr;

    std::vector<int> vec = {8, 7, 10, 3, 9, 15};
    Creat_BST(tree, vec);

    std::cout << "\n";

    std::cout << "遍历二叉树: ";
    InOrderTraversal(tree);
    std::cout << "\n";

    int target = 7;
    LocateElem(tree, target);

    int node2 = 11;
    BST_Insert(tree, node2);
    std::cout << "插入节点:" << node2 << "\n";

    int node3 = 8;
    BST_Delete(tree, node3);
    std::cout << "删除节点:" << node3 << "\n";

    std::cout << "遍历二叉树: ";
    InOrderTraversal(tree);

    std::cout << std::endl;

    return 0;
}

 🔯P1:执行结果

运行结果如下图所示~


🔚结语

博文到此结束,写得模糊或者有误之处,欢迎小伙伴留言讨论与批评,督促博主优化内容,不限于以下内容~😶‍🌫️😶‍🌫️

  • 有错误:这段注释南辕北辙,理解错误,需要更改~
  • 难理解:这段代码雾里看花,需要更换排版、增加语法、逻辑注释或配图~
  • 不简洁:这段代码瘠义肥辞,好像一座尸米山,需要更改逻辑;如果是C++语言,调用某库某语法还可以简化~
  • 缺功能:这段代码败絮其中,能跑,然而不能用,想在实际运行或者通过考试需要增加功能~
  • 跑不动:这不可能——好吧,如果真不能跑,告诉我哪里不能跑我再回去试试...

博文若有帮助,欢迎小伙伴动动可爱的小手默默给个赞支持一下~🌟🌟

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

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

相关文章

【MATLAB第45期】基于MATLAB的深度学习SqueezeNet卷积神经网络混凝土裂纹图像识别预测模型

【MATLAB第45期】基于MATLAB的深度学习SqueezeNet卷积神经网络混凝土裂纹图像识别预测模型 引言 该文章展示如何微调名为SqueezeNet的预训练深度卷积网络&#xff0c;以执行裂纹图像分类预测。并使用一种称为Grad-CAM的技术来解释和分析分类输出。文章使用L.Zhang介绍的混凝土…

C++初阶之C++入门最全详解

C入门 1. C关键字&#xff08;C98&#xff09;2. 命名空间2.1 命名空间定义2.2 命名空间使用 3. C输入&输出4. 缺省参数4.1 缺省参数概念4.2 缺省参数分类 5. 函数重载5.1 函数重载概念5.1.1 参数类型不同5.1.2 参数个数不同5.1.3 参数类型顺序不同 5.2 C支持函数重载的原理…

Spring Cloud Alibaba Seata(二)

目录 一、Seata 1、Seata-AT模式 1.1、具体案例 1.2、通过Seata的AT模式解决分布式事务 2、Seata-XA模式 3、Seata-TCC模式 4、Seata-SAGA模式 一、Seata 1、Seata-AT模式 概念&#xff1a;AT模式是一种无侵入的分布式事务解决方案&#xff0c;在 AT 模式下&#xff0c…

git修改默认主分支main为master和设置git默认创建的项目默认分支都为master

文章目录 前言一、设置新建仓库默认分支为master1.点击GitHub右上角的头像2. 选中settings&#xff08;设置&#xff09;3.点击Repositories&#xff08;存储库&#xff09;4.更改main为master后点击update 二、设置已建仓库的默认分支为master1.找到你要改的项目点击settings&…

STL序列式容器的概念

文章目录 1 迭代器2 什么是序列式容器3 序列式容器容器中常见的函数成员参考 1 迭代器 迭代器和C指针非常类似&#xff0c;它可以是需要的任意类型&#xff0c;通过迭代器可以指向容器中的某个元素&#xff0c;如果需要&#xff0c;还可以对该元素进行读写操作。 迭代器类别 …

ThreeJS案例一——在场景中添加视频,使用人物动作以及用键盘控制在场景中行走的动画

准备 首先我们需要两个模型&#xff0c;一个是场景模型&#xff0c;另一个是人物模型。 人物模型我这里用的Threejs官网中的给的模型&#xff0c;名称是Xbot.glb。 当然人物模型也可以自己去这个网站下载sketchfab&#xff0c;下载后给模型添加动画mixamo 下载模型动画 先让…

C++ STL vector容器用法

文章目录 1 vector初始化方法2 vector容器迭代器3 data()函数4 emplace_back()和push_back()的区别5 insert()函数6 vector删除元素参考 1 vector初始化方法 方式1&#xff1a; std::vector<double> values;//创建空的vcetor values.reserve(20); //设置容器的内存分配…

【实战】 JWT、用户认证与异步请求(1) —— React17+React Hook+TS4 最佳实践,仿 Jira 企业级项目(四)

文章目录 一、项目起航&#xff1a;项目初始化与配置二、React 与 Hook 应用&#xff1a;实现项目列表三、TS 应用&#xff1a;JS神助攻 - 强类型四、JWT、用户认证与异步请求1.login2.middleware of json-server3.jira-dev-tool&#xff08;imooc-jira-tool&#xff09;安装问…

《流浪地球 2》的硬核黑科技

电影中&#xff0c;由刘德华饰演的量子计算机工程师图恒宇有一个惊心动魄的情节。为了同步启动全球地球发动机&#xff0c;需要重启互联网&#xff0c;避免地壳破碎和地质灾害。而重启互联网的关键则是要启动“根服务器”。电影中没有具体交代是什么根服务器&#xff0c;但是当…

Ubuntu18.04屏幕分辨率问题

本篇博客最早发布于实验室公共博客&#xff0c;但已无人维护&#xff0c;现迁移至个人博客 起因 本来昨天还好好的&#xff0c;过了一夜&#xff0c;就变了&#xff0c;像极了咳咳(自行脑补) redwallbot-2小车上固定的屏幕&#xff0c;屏幕分辨率本来应该是1920x1080的&#…

DevOps系列文章之 linux安装ftp

第一步 1、用root 进入系统 2、使用命令 rpm -qa|grep vsftpd 查看系统是否安装了ftp&#xff0c;若安装了vsftp&#xff0c;使用这个命令会在屏幕上显示vsftpd的版本 3、使用命令rpm -e vsftpd 即可卸载ftp 4、再使用rpm -qa|grep vsftpd 查看系统是否已删除ftp&#xff0…

【小技巧】vscode 在 JS 文件中补全 HTML标签

文章目录 vscode中有很多插件可以支持 HTML 标签自动补全&#xff0c;在.vue和.html文件中都没有问题&#xff0c;但是在使用react时&#xff0c;HTML标签是写在js或者是ts文件中&#xff0c;插件就不起作用了 解决方案&#xff1a; 在设置中插入这段设置代码 "emmet.i…

uniapp 微信小程序sourcemap映射

uniapp 微信小程序sourcemap映射 错误捕获 由于微信小程序中没有window对象&#xff0c;不能通过window.onerror和window.onunhandledRejection方法进行全局的监听。不过我们也可以使用以下几种方法。 使用try…catch 将可能出现的错误的代码使用try...catch包裹 try{cont…

【C++】一文读懂C++中的异常处理机制

文章目录 C 中的异常处理机制1.1 什么是异常&#xff1f;1.2 调用abort()1.3 返回错误码1.4 异常机制1.5 将对象用作异常类型1.6 异常规范和C111.7 栈解退1.7.1 return和throw的区别1.7.2 什么是栈解退 1.8 其他异常特性1.9 excepyion类1.9.1 stdexcept异常类1.9.2 bad_alloc异…

329款超有设计感的英文字体合集

一组超有设计感的英文字体合集&#xff0c;总共329个字库包含多种字体风格&#xff1a;手写字体、签名字体、复古字体、笔刷字体、漫画字体等无衬线字体。适用于签名、文具、标志、排版引言、杂志或书籍封面。素材获取&#xff1a;取括号内容&#xff0c;&#xff08;scwan&…

【 openGauss数据库】--运维指南01

【 openGauss数据库】--运维指南01 &#x1f53b; 一、 openGauss数据库运维指南&#x1f530; 1.1 启停openGauss&#x1f530; 1.2 查看openGauss数据库状态 &#x1f53b; 二、 维护检查项&#x1f530; 2.1 检查实例状态&#x1f530; 2.2 检查锁信息&#x1f530; 2.3 统计…

个人向非企业,基于目前主流图床的选购指南

1. 为什么需要搭建自己的图床 最近研究了一下国内外比较主流的图床与对象存储&#xff0c;因为个人写作更加偏向于使用Markdown&#xff0c;而国内很多平台如掘金&#xff0c;简书&#xff0c;csdn等等网站都做了相关的防盗链&#xff0c;即使是我为作者本人&#xff0c;想取用…

C语言里面那些你必须知道的常用关键字(详细讲解)

前言 哈喽&#xff0c;各位铁汁们好啊&#xff01;✨今天来给大家带来的是C语言中我们常用的关键字静态static的详细讲解和typedef 、#define定义常量和宏。   既然是详解想必大家必定是想学一些平常学不到的东西吧&#xff01;这里博主给大家详细讲解static修饰的变量在内存…

2023最全的Java架构师面试120题解析(MySQL/Redis/架构/高并发等)

最全架构师题目将包含如下技术范围&#xff1a; 1.Java基础和高级: 集合框架: List&#xff1a;ArrayList、LinkedList&#xff1b;Set&#xff1a;HashSet、TreeSet Map:TreeMap/ConcurrentHashMap&#xff1b;Queue:ConcurrentLinkedQueue等 泛型、反射、并发编程、JVM、A…

基于Smb协议实现网络文件传输(Golang)

在前面章节已经展示了一些关于SMB的基本介绍&#xff0c;以及对应SMB相关操作的Java实现&#xff0c;这一章主要是前一章的补充&#xff0c;使用Golang来对 SMB共享文件夹进行操作。如果没有阅读过上一章节的同学&#xff0c;请跳转到 基于Smb协议实现网络文件传输&#xff0c;…