递归与回溯2

news2024/9/22 3:35:26

一:递归分治

什么是递归?

  • 函数自己调用自己
  • 通过函数体来进行循环
  • 自相似的方法重复进行的过程

递归的过程:先自顶向下找到递归出口,在自底向上回到最初的递归位置

在这里插入图片描述

推导路径未知的题目只能用递归不能用循环

比如求多叉树的节点(每个节点的分支都不同)
在这里插入图片描述

推导路径未知的题目只能用递归不能用循环

比如求多叉树的节点(每个节点的分支都不同)

在这里插入图片描述

递归问题需要考虑

  • 确定递归的重叠子问题—数学归纳法
  • 确定递归边界,一定要有递归出口—避免死循环
  • 保护和还原现场—比如当前层的改变了全局参数回溯会影响结果

在这里插入图片描述

一般来说,涉及全局变量和静态变量或者类私有变量,不同层之间可能需要进行数据恢复

二:打印二进制回溯解法

下图是长度为2的二进制个数

  • 从左至右,依次加入0,回溯时放弃0,选择1

先添加元素,后进行递归

在这里插入图片描述

这种方法一定要传递供选项,就是每次进行的选择

  • 这里二进制的01选择是隐藏的,需要显式给出
vector<vector<int>> res;
void getAllBin(vector<int> nums,vector<int> ans,int n){
    for (int i = 0; i < nums.size();i++){
        ans.push_back(nums[i]);//先添加元素
        if(ans.size()==n){//满足存结果,不要return
            res.push_back(ans);
        }
        else{//不满足长度递归
            getAllBin(nums, ans, n);
        }
        ans.pop_back();
    }
}
vector<vector<int>> printAllbin(int n){
    vector<int> nums = {0, 1};//显式给出01供选项
    vector<int> ans;
    getAllBin(nums, ans, n);
    return res;
}

当然也可以把判断语句放在if外,需要return

void getAllBin(vector<int> nums,vector<int> ans,int n){
 if(ans.size()==n){//满足存结果
     res.push_back(ans);
     return;
 }
 for (int i = 0; i < nums.size();i++){
     ans.push_back(nums[i]);//先添加元素
     //递归
     getAllBin(nums, ans, n);
     ans.pop_back();
 }
}

一般选择这种,更清晰

先进行回溯,再添加元素

在这里插入图片描述

vector<vector<int>> res;
void getAllBin(vector<int> ans,int n){
    if(ans.size()==n){
        res.push_back(ans);
        return;
    }
    //加入0回溯
    vector<int> tmp1 = ans;
    tmp1.push_back(0);
    getAllBin(tmp1, n);
    //加入1回溯
    vector<int> tmp2 = ans;
    tmp2.push_back(1);
    getAllBin(tmp2, n);
}
vector<vector<int>> printAllbin(int n){
    vector<int> ans;
    getAllBin(ans, n);
    return res;
}

这里是传入新变量,当然也可以用ans,但是需要pop_back(),防止影响结果

void getAllBin(vector<int> ans,int n){
 if(ans.size()==n){
     res.push_back(ans);
     return;
 }
 //加入0回溯
 ans.push_back(0);
 getAllBin(ans, n);
 //别忘了pop_back()
 ans.pop_back();
 // 加入1回溯
 ans.push_back(1);
 getAllBin(ans, n);
 //pop与否都可以
 //ans.pop_back();
}

这里ans.size()是隐式递归结束变量,也可以单独用一个参数,但是要注意递归+1

vector<vector<int>> res;
void getAllBin(vector<int> ans,int n,int level){
    if(level==n){
        res.push_back(ans);
        return;
    }
    //加入0回溯
    ans.push_back(0);
    getAllBin(ans, n, level + 1);//+1
    ans.pop_back();
    // 加入1回溯
    ans.push_back(1);
    getAllBin(ans, n, level + 1);//+1
    //pop与否都可以
    return;
}
vector<vector<int>> printAllbin(int n){
    vector<int> ans;
    getAllBin(ans, n,0);//从0开始
    return res;
}

当然也可以用减法实现,size==0一样可以结束递归

vector<vector<int>> res;
void getAllBin(vector<int> ans,int n){
    if(n==0){
        res.push_back(ans);
        return;
    }
    //加入0回溯
    ans.push_back(0);
    getAllBin(ans, n-1);//+1
    ans.pop_back();
    // 加入1回溯
    ans.push_back(1);
    getAllBin(ans, n-1);//+1
    //pop与否都可以
    return;
}
vector<vector<int>> printAllbin(int n){
    vector<int> ans;
    getAllBin(ans, n);
    return res;
}

三:用数组初始化一个二叉搜索树

BST数据结构,中序遍历

  • bst数据结构
struct bst{
    //节点,左子树,右子树
    int val;
    bst *left;
    bst *right;
    //带有默认参数的构造函数
    bst(int v = 0,bst* l=NULL,bst* r=NULL):val(v),left(l),right(r){}
};
  • 中序遍历
void midTraverse(const bst* root){
    if(root==NULL)
        return;
    midTraverse(root->left);
    cout << root->val << " ";
    midTraverse(root->right);
}
  • 程序测试
int main(){
    bst *aa = new bst(100);
    bst *bb = new bst(500);
    bst *cc = new bst(200, aa, NULL);
    bst *dd = new bst(400, NULL, bb);
    bst *ee = new bst(300,cc,dd);
    midTraverse(ee);
    return 0;
}

运行结果:

100 200 300 400 500

迭代形式创建

先找后插
bst* createBST_loop(int a[],int n){
     //首先根节点设为第一个元素值
     bst *root = new bst(a[0]);
     //插入余下值
     bst *parent = NULL;
     for (int i = 1; i < n;i++){
         //定义指向root节点,防止断链
         bst *cur = root;//必须从root开始
         // 先找到插入值的父节点,再进行插值
         while (cur)
         {
             if (a[i] < cur->val)
             {
                 parent = cur;
                 cur = cur->left;
             }
             else if (a[i] > cur->val)
             {
                 parent = cur;
                 cur = cur->right;
             }
             else
             { // a[i]==root->val
                 return root;
             }
          }
          //判断当前值和父节点大小来将新节点插入到左右子树
          if(parent){//防止NULL->__
               if(a[i]<parent->val){
                   parent->left = new bst(a[i]);
               }
               else{
                   parent->right = new bst(a[i]);
               }
          }
     }//for
     return root;
}
  • 需要一个指针指向root,这样每次才能不断链
  • 这里是找到插入节点的父节点,单独标记

当然也可以把根节点作为参数,函数没有返回值

  1. 但是必须传入指针的引用

  2. 传引用,初始化必须有指向,比如NULL

void create_BST_loop(bst*& root,int a[],int n){
    root = new bst(a[0]);
    bst *parent = NULL;
    for (int i = 1; i < n;i++){
        bst *cur = root;
        while(cur){
            if(a[i]<cur->val){
                parent = cur;
                cur = cur->left;
            }
            else if(a[i]>cur->val){
                parent = cur;
                cur = cur->right;
            }
            else{
                return;
            }
        }
        //待插节点
        bst *tmp = new bst(a[i]);
        if(parent){
            if(a[i]<parent->val){
                parent->left = tmp;
            }
            else{
                parent->right = tmp;
            }
        }
    }//for
}

bst *newnode=NULL;

create_BST_loop(newnode, a, n);

midTraverse(newnode);

边找边插
bst* create_BST_loop(int a[],int n){
    bst* root = new bst(a[0]);
    for (int i = 1; i < n;i++){
        bst *cur = root;
        while(cur){
            if(a[i]<cur->val){
                if(cur->left){
                    cur = cur->left;
                }
                else{
                    cur->left = new bst(a[i]);
                    break;//插入后跳出
                }
            }
            else if(a[i]>cur->val){
               if(cur->right){
                   cur = cur->right;
               }
               else{
                   cur->right = new bst(a[i]);
                   break;
               }
            }
            else{
                return root;
            }
        }
    }//for
    return root;
}
  • 这里不需要父节点了,只要往左右子树遍历时判断一下存在性

    不存在说明该左子树就是要插值

  • 千万别忘了插入后的break

递归形式创建

由于每次插入需要找到插入位置,所以用递归找到插入位置,然后循环多次插入

void getRecursion(bst*& root,int x){
     if(root==NULL){
         root = new bst(x);
         return;
     }
     if(x<root->val){
         getRecursion(root->left, x);
     }
     else if(x>root->val){
         getRecursion(root->right, x);
     }
     else{//==
         return;
     } 
}
bst* create_BSTrecursion(int a[],int n){
    bst *root = new bst(a[0]);
    for (int i = 0; i < n;i++){
        int x = a[i];
        getRecursion(root, x);
    }
    return root;
} 
  • 父节点形式递归,返回类型bst*
bst* getRecursion(bst* root,int x){
    if(root==NULL){
        root = new bst(x);
        return root;
    }
    if(x<root->val){//自己建立链条
        root->left = getRecursion(root->left, x);
    }
    else if(x>root->val){
        root->right = getRecursion(root->right, x);
    }
    return root;
}
bst* create_BSTrecursion(int a[],int n){
    bst *root = new bst(a[0]);
   // bst* tmp;
    for (int i = 0; i < n;i++){
        int x = a[i];
        getRecursion(root, x);
        //tmp=getRecursion(root, x);
    }
    return root;
    //return tmp
} 
bst* create_BSTrecursion(int a[],int n){
 bst *root = new bst(a[0]);
 bst* tmp;
 for (int i = 0; i < n;i++){
     int x = a[i];
     tmp=getRecursion(root, x);
 }
 return tmp
} 

可以定义新变量接受返回值,因为root在函数内部,可以不写root=getRecyrsion();

  • 如果想变成void,就需要把父节点作为参数
void getRecursion(bst* root,bst* parent,int x){
    if(root==NULL){
        /*建立parent与root联系*/
        if(x<parent->val){
            parent->left = new bst(x);
        }
        else{
            parent->right = new bst(x);
        }
        return;//递归结束
    }
    //传递父节点
    if(x<root->val){
        getRecursion(root->left,root, x);
    }
    else if(x>root->val){
        getRecursion(root->right,root,x);
    }
    return;
}
bst* create_BSTrecursion(int a[],int n){
    bst *root = new bst(a[0]);
    for (int i = 0; i < n;i++){
        int x = a[i];
        getRecursion(root,NULL, x);
    }
    return root;
} 

主函数形式

bst不可以有重复值,所以生成随机数时候需要去重

int n = 10;
    int *a = new int[10];
    for (int i = 0; i < 10;i++){
        //生成[a,b)的随机数---(rand()%(b-a))+a
        a[i] = (rand() % 90)+10;
        //bst不能有重复值,相等去除
        for (int j = 0; j < i;j++){
            if(a[j]==a[i]){
                i-=1;//重新生成a[i]
                break;
            }
        }
    }
   // bst *root = create_BSTrecursion(a, n);

四:换一种思路求全排列

在这里插入图片描述

也就是变动原数组,选择一个就把自己的选择去掉,然后递归,回溯的时候补上元素

​ 把数组恢复需要用到insert()函数,需要传递插入位置和插入值:

​ 所以在删除的时候提前记录删除元素值和删除的iter位置

vector<vector<int>> res;
void getLine(vector<int> nums ,vector<int> ans,int n){
    if(n==0){
        res.push_back(ans);
        return;
    }
    for (int i = 0; i < nums.size();i++){
        //记录删除元素x
        int x = nums[i];
        ans.push_back(nums[i]);
        //记录删除元素位置的下一个迭代器it
        auto it=nums.erase(nums.begin()+i);
        getLine(nums, ans, n - 1);
        //别忘了回溯撤销ans的选择
        ans.pop_back();
        //恢复原数组,在it前加入x
        nums.insert(it,x);
    }
}
vector<vector<int>> fullLine(vector<int> nums){
    vector<int> tmp;
    getLine(nums, tmp,nums.size());
    return res;
}

五:求{1,2,3}子集图示

先选元素,再回溯

在这里插入图片描述

由于子集中元素可选可不选,每次循环的开始值是上一次的值+1

class Solution {
public:
    vector<vector<int>> subsets(vector<int>& nums) {
        vector<int> mm;
        findSub(nums, mm, 0);
        res.push_back({});
        return res;
    }

private:
    vector<vector<int>> res;
    void findSub(vector<int> nums, vector<int> ans, int index) {
        for (int i = index; i < nums.size(); i++) {
            ans.push_back(nums[i]);
            // res.push_back(ans);
            findSub(nums, ans, i + 1); // 当前i的下一个
            res.push_back(ans);        // 在递归前记录也行
            ans.pop_back();
        }
    }
};

运行结果:

在这里插入图片描述

在这里插入图片描述

六:组合问题

77. 组合
C n k : 从 n 个元素中选 k 个 C_n^k:\text{从}n\text{个元素中选}k\text{个} Cnk:n个元素中选k

其实思路类似子集:

比如{1,2,3}中{1,3}和{3,1}是重复的,所以元素只能以该元素为起点,向后递归,不能往前选

但是组合规定了个数,只要在结果处存储正确的符合条件的结果即可,在所有路径提前剪去不符合要求的

注意:从i开始的,必须要求[i,...,n]的个数n-i+1加上ans当前的数量大于k

即:n-i+1+ans.size()>k----数量小于k一点不符合题意,提前剪枝

class Solution {
public:
    vector<vector<int>> combine(int n, int k) {
        this->n=n;
        this->k=k;
        vector<int> mm;
        findCombine(mm,0);
        return res;
    }
private:
    int n;
    int k;
    vector<vector<int>> res;
    void findCombine(vector<int> ans,int index){
        if(ans.size()==k){
            res.push_back(ans);
            return;//递归结束
        }
        //[i,...,n]个数:n-i+1+ans.size()<k
         for(int i=index;i<(n-k+1)+ans.size();i++){
             ans.push_back(i+1);
             findCombine(ans,i+1);
             ans.pop_back();
         }
    }
};

也可以按照选不选元素去回溯,但是要提前结束

  • 当前ans的大小超过k了
  • 当前ans的大小把后面全选了也不足k
class Solution {
public:
    vector<vector<int>> combine(int n, int k) {
        this->n = n;
        this->k = k;
        vector<int> mm;
        findCombine(mm, 1);
        return res;
    }

private:
    int n;
    int k;
    vector<vector<int>> res;
    void findCombine(vector<int> ans, int index) {
        // ans.size()+(n-index+1)<k
        if (ans.size() > k || ans.size() + (n - index + 1) < k) {
            return; // 提前回溯
        }
        if (ans.size() == k) {
            res.push_back(ans);
            return;
        }
        // 选该元素
        ans.push_back(index);
        findCombine(ans, index + 1);
        // 不选该元素
        ans.pop_back();
        findCombine(ans, index + 1);
    }
};
      // 不选该元素
     findCombine(ans, index + 1);
      // 选该元素
     ans.push_back(index);
     findCombine(ans, index + 1);

从不选到选,不需要pop_back(),加上也正确

三种基本类型回溯

分为排列,子集,组合,后一种分别是前一种的子集

在这里插入图片描述

类似问题只需在该基础上进行剪枝

七:递归与分治

104. 二叉树的最大深度

自底向上求法

分治求法:

  • 求出左子树的最大深度
  • 求出右子树的最大深度
  • 然后最大深度=max(左子树,右子树)+1(根节点)
int maxDepth(TreeNode* root) {
        if(root==NULL) return 0;
        int l=maxDepth(root->left);
        int r=maxDepth(root->right);
        return max(l,r)+1;
    }

在这里插入图片描述

联系在一起的关键是:函数体内求左子树和求右子树的对应一个root

这是典型的自底向上,也就是相当于从下面向前面追溯得到结果

自顶向下求法

在这里插入图片描述

class Solution {
public:
    int maxDepth(TreeNode* root) {
        res = 0;
        dfs(root, 1);//根节点为1
        return res;
    }

private:
    int res;
    void dfs(TreeNode* root, int depth) {
        if (root == NULL)
            return;
       
        dfs(root->left, depth + 1);
        dfs(root->right, depth + 1);
         res = max(res, depth); // 更新结果
    }
};

每次递归依次就更新依次结果

递归前或递归后递归不影响

res = max(res, depth); // 更新结果
dfs(root->left, depth + 1);
dfs(root->right, depth + 1);  

当然也可以把depth设为全局变量,但是要清理现场

class Solution {
public:
    int maxDepth(TreeNode* root) {
        res = 0;
        depth=0;
        dfs(root);
        return res;
    }

private:
    int res;
    int depth;
    void dfs(TreeNode* root) {
        if (root == NULL)
            return;
        depth++;//当前层+1
        res = max(res, depth); // 更新结果
        dfs(root->left);
        //depth--;
        //depth++;
        dfs(root->right);
        depth--;//回到上一层,depth-1
    }
};

bfs—广度优先遍历

队列存储二元组,每次都记录层次大小

  using pr=pair<TreeNode*,int>;
    int maxDepth(TreeNode* root) {
        int res=0;
        /*广度优先遍历*/
        queue<pr> que;
        int level=1;//记录层次
        if(root==NULL) return 0;
        que.push(make_pair(root,level));
        while(!que.empty()){
            TreeNode* tmp=que.front().first;
            int level=que.front().second;
            que.pop();
            res=max(res,level);//更新res
            if(tmp->left) que.push(make_pair(tmp->left,level+1));
            if(tmp->right) que.push(make_pair(tmp->right,level+1));
        }
        return res;
    }

当然也可以利用队列每次存的都是当前层的所有元素

int maxDepth(TreeNode* root) {
        int res = 0;
        /*广度优先遍历*/
        queue<TreeNode*> que;
        int level = 1; // 记录层次
        if (root == NULL)
            return 0;
        que.push(root);
        while (!que.empty()) {
            int sz = que.size(); // 当前队列元素,当前层个数
            while (sz > 0) {//当前层所有元素出队
                TreeNode* tmp = que.front();
                que.pop();
                if (tmp->left)
                    que.push(tmp->left);
                if (tmp->right)
                    que.push(tmp->right);
                sz--;
            }
            res+=1;//层次+1
        }
        return res
    }

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

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

相关文章

NOC2023软件创意编程(学而思赛道)python小高组初赛真题

软件创意编程 一、参赛范围 1.参赛组别:小学低年级组(1-3 年级)、小学高年级组(4-6 年级)、初中组。 2.参赛人数:1 人。 3.指导教师:1 人(可空缺)。 4.每人限参加 1 个赛项。 组别确定:以地方教育行政主管部门(教委、教育厅、教育局) 认定的选手所属学段为准。 二、…

基于原子变量的内存模型优化

概述 线程间同步通常的实现方法通常为互斥锁&#xff0c;但互斥锁对性能造成了影响&#xff0c;C11引入了内存模型&#xff0c;定义了STD::memory_order枚举&#xff0c;结合原子性操作&#xff0c;实现无锁线程数据同步。 关于memory_order memory_order_relaxed&#xff1…

电子电气架构——车载以太网协议栈

电子电气架构——车载以太网协议栈 我是穿拖鞋的汉子&#xff0c;魔都中坚持长期主义的汽车电子工程师。 老规矩&#xff0c;分享一段喜欢的文字&#xff0c;避免自己成为高知识低文化的工程师&#xff1a; 没有人关注你。也无需有人关注你。你必须承认自己的价值&#xff0c…

【Java文件报错】Cannot resolve symbol ‘println‘ 【及解决】

一、问题描述 在Java源代码文件中&#xff0c;使用 System.out.println() 语句进行输出&#xff0c;编译器提示“Cannot resolve symbol ‘println’&#xff08;无法解释关键字&#xff09;”, println飘红。报错代码及报错截图如下所示。 import java.io.*;public class St…

【JavaSE】时间类相关API以及使用

目录 时间类相关API 1.Date类 2.SimpleDateFormat类 3.Calendar类 4.JDK8-时区&#xff0c;时间和格式化 5.JDK8-日历和工具类 时间类相关API 以下内容是通过观看黑马java的常见API视频总结加笔记&#xff0c;其中有JDK7以及以前的时间类&#xff0c;包括&#xff1a;Date&…

前后端分离Vue+nodejs酒店公寓客房预订管理系统udr7l-java-php-django-springboot

本系统的设计与实现共包含13个表:分别是关于我们信息表&#xff0c;配置文件信息表&#xff0c;公寓信息评论表信息表&#xff0c;公寓入住信息表&#xff0c;公寓退房信息表&#xff0c;公寓信息信息表&#xff0c;公寓预订信息表&#xff0c;系统公告信息表&#xff0c;收藏表…

pdf电子准考证查询下载系统(实证效果可照片)V1.0

CSDNpdf电子准考证查询下载系统(实证效果可照片)V1.0 使用场景: 教育机构比如学校用pdf准考证查询下载系统(实证效果可照片,最适合准考证打印); 也可自定义图片及坐标用于各种优秀党员三好学生等荣誉证书、聘书授权代理pdf电子证书查询与下载。 推荐Linux PHP5.5-7.3使用使…

utniy urp shinyssrr插件使用

文章目录 前言步骤1首先在URP的配置文件里添加SSR后处理2 修改RenderingPath为延迟渲染3 启用深度纹理4 为物体添加脚本 注意事项插件下载 前言 用来实现屏幕空间反射效果 unity 版本为2021.3.8LTS&#xff0c;低版本的untiy URP的参数设置位置z可能会不同 步骤 1首先在URP的…

Spring对IoC的实现

个人名片&#xff1a; &#x1f43c;作者简介&#xff1a;一名大三在校生&#xff0c;喜欢AI编程&#x1f38b; &#x1f43b;‍❄️个人主页&#x1f947;&#xff1a;落798. &#x1f43c;个人WeChat&#xff1a;hmmwx53 &#x1f54a;️系列专栏&#xff1a;&#x1f5bc;️…

多态——细致讲解

&#x1f536;多态基础概念  &#x1f536;概念   &#x1f531;多态性   &#x1f531;多态——重新(覆盖)  &#x1f536;示例   &#x1f536;基本使用方法   &#x1f536;特例    &#x1f531;协变    &#x1f531;析构函数重写  &#x1f531;多态原理…

链表OJ刷题(二)

制作不易&#xff0c;三连支持一下呗&#xff01;&#xff01;&#xff01; 文章目录 前言一、链表的回文结构二、相交链表三、链表中倒数第k个节点四、环形链表Ⅰ和Ⅱ总结 前言 一、链表的回文结构 链表的回文结构_牛客题霸_牛客网 这里我们需要先了解一下什么叫做回文&#…

测开新手:pytest+requests+allure自动化测试接入Jenkins学习

最近在这整理知识&#xff0c;发现在pytest的知识文档缺少系统性&#xff0c;这里整理一下&#xff0c;方便后续回忆。 在python中&#xff0c;大家比较熟悉的两个框架是unittest和pytest&#xff1a; Unittest是Python标准库中自带的单元测试框架&#xff0c;Unittest有时候…

基于python+django+mysql在线点餐订餐外卖系统设计与实现 开题报告参考

博主介绍&#xff1a;黄菊华老师《Vue.js入门与商城开发实战》《微信小程序商城开发》图书作者&#xff0c;CSDN博客专家&#xff0c;在线教育专家&#xff0c;CSDN钻石讲师&#xff1b;专注大学生毕业设计教育和辅导。 所有项目都配有从入门到精通的基础知识视频课程&#xff…

排序(3)——直接选择排序

目录 直接选择排序 基本思想 整体思路&#xff08;升序&#xff09; 单趟 多趟 代码实现 特性总结 直接选择排序 基本思想 每一次从待排序的数据元素中选出最小&#xff08;或最大&#xff09;的一个元素&#xff0c;存放在序列的起始位置&#xff0c;直到全部待排序的…

Python程序打包成exe可执行文件的常用方法

在Python中,您可以使用一些工具将您的Python程序打包成可执行文件(.exe)。以下是一些常用的工具: PyInstaller: PyInstaller是一个流行的工具,它可以将Python脚本打包成独立的可执行文件,支持Windows、Linux和Mac。您可以使用以下命令安装PyInstaller: pip install pyin…

Matlab:元胞自动机

元胞自动机是一种基于离散空间的动态系统&#xff0c;由许多简单单元按照某些规则进行相互作用和演化而形成的复杂结构。元胞自动机可以用于模拟物理、生物、社会等领域的现象&#xff0c;以及进行优化、图像处理、噪声生成等方面的应用。 例1&#xff1a;生命游戏 nextState…

每日一类:QLabel深入解析

QLabel是Qt中用于显示文本或图像的控件&#xff0c;属于Qt Widgets模块。它是展示静态内容的理想选择&#xff0c;支持富文本格式&#xff0c;使得文本可以包含不同的字体、颜色和链接。QLabel也可以用来显示图像&#xff0c;包括动态图像。此外&#xff0c;它还支持文本和图像…

【硬件相关】IB网/以太网基础介绍及部署实践

文章目录 一、前言1、Infiniband网络1.1、网络类型1.2、网络拓扑1.3、硬件设备1.3.1、网卡1.3.2、连接线缆a、光模块b、线缆 1.3.4、交换机 2、Ethernet网络 二、部署实践&#xff08;以太网&#xff09;1、Intel E810-XXVDA21.1、网卡信息1.2、检查命令1.2、驱动编译 2、Mella…

MySQL进阶:全局锁、表级锁、行级锁总结

&#x1f468;‍&#x1f393;作者简介&#xff1a;一位大四、研0学生&#xff0c;正在努力准备大四暑假的实习 &#x1f30c;上期文章&#xff1a;MySQL进阶&#xff1a;MySQL事务、并发事务问题及隔离级别 &#x1f4da;订阅专栏&#xff1a;MySQL进阶 希望文章对你们有所帮助…

如何根据玩家数量和游戏需求选择最合适的服务器配置?

根据玩家数量和游戏需求选择最合适的服务器配置&#xff0c;首先需要考虑游戏的类型、玩家数量、预计的在线时间以及对内存和CPU性能的需求综合考虑。对于大型多人在线游戏&#xff0c;如MMORPG或MOBA等&#xff0c;由于需要更多的CPU核心数来支持更复杂的游戏逻辑和处理大量数…