数据结构与算法基础-学习-15-二叉树之BST的前序遍历、后序遍历、中序遍历的递归和非递归方法实现

一、二叉树定义

二叉树是N(N>=0)个节点的有限集,它可能是空集或者由一个根节点及两棵互不相交的分别称作这个根的左子树和右子树的二叉树组成。

二、二叉树特点

1、每个节点最多两个孩子。(也就是二叉树的度小于等于2)

2、根有左右之分,不可颠倒。

3、二叉树可以是空集,根的左子树或右子树可以为空。

三、图示

四、二叉树性质

1、性质一

深度为k的二叉树至多有2的k次方再减一。

推导第一层有一个(2的0次方),第二层最多有两个(2的1次方),第三层最多有四个(2的2次方)。我们可以用等比求和公式:Sn=(a1-an*q)/(1-q)=(1-4*2)/(-1)=7。

2、性质二

在二叉树的第i层上至多有2的(i-1)次方个节点。

3、性质三

对任何一棵二叉树T,如果其叶子数为n0,度为2的节点数为n2,n0=n2+1。

五、特殊形式的二叉树

1、满二叉树

(1)定义和图示

满二叉树在相同深度的二叉树中结点数和叶子结点数是最多的。

2、完全二叉树

(1)定义和图示

深度为k的具有n个结点的二叉树,当且仅当其每一个结点都与深度为k的满二叉树中编号为1~n的结点一一对应时,称之为完全二叉树。

满二叉树是完全二叉树,完全二叉树不一定是满二叉树。

(2)特性一

具有n个结点的完全二叉树深度为log(2)(n)(向下取整)+1。

(3)特性二

如果对一棵有n个结点的完全二叉树(深度为log(2)(n)(向下取整)+1)的结点按照层序编号(从上到下,从左到右),则对于任一结点i(1<=i<=n),有:

(1)如果i=1,则结点i是二叉树的根,无双亲。如果是i>1,则双亲是结点i/2再向下取整。

(2)如果2i>n,则结点i为叶子节点,无左孩子;否则,其左孩子是结点2i。

(3)如果2i+1>n,则结点i无右孩子。否则,其右孩子是结点2i+1。

六、二叉搜索树

二叉搜索树(Binary Search Tree)简称BST,如果结点的左子树不为空,则左子树存储的数据需要小于结点存储的数据。如果结点的右子树不为空,则右子树存储的数据需要大于结点存储的数据。

二叉搜索树的中序遍历,最终会形成一个从小到大排列的数组。

将数组{6,3,8,2,5,1,7}变为一棵BST,BST如下图:

七、BST结构体

1、BinaryTreeNode

(1)描述

二叉树结点定义,Data数据域,LeftNodePtr左子树指针,RightNodePtr右子树指针,JudegeTreeUsedArray在非递归后续遍历时用到,其他并未用到,数组长度2,分别表示左右子树状态

,JUDGE_TREE_UNUSED为此树没遍历,JUDGE_TREE_USED为此树遍历。

(2)定义

#define JUDGE_TREE_UNUSED    0
#define JUDGE_TREE_USED      1
#define JUDGE_TREE_ARRAY_LEN 2

typedef int                ElemType;

typedef struct BinaryTreeNode
{
    ElemType               Data;
    struct BinaryTreeNode* LeftNodePtr;
    struct BinaryTreeNode* RightNodePtr;
    int                    JudegeTreeUsedArray[JUDGE_TREE_ARRAY_LEN];//为了实现非递归后序遍历使用的数据,其他遍历方法未使用。
}BinaryTreeNode, *BinaryTreeNodePtr;

2、BinaryTree

(1)描述

二叉树结点定义,NodePtr树的根节点,TreeNodeNum树的总结点数。

(2)定义

typedef struct BinaryTree
{
    BinaryTreeNodePtr  NodePtr;
    BinaryTreeSizeType TreeNodeNum;    
}BinaryTree;

八、BST函数

其中前中后序遍历非递归方法实现需要用到顺序栈,可以参考之前写的博客《数据结构与算法基础-学习-09-线性表之栈的理解、初始化顺序栈、判断顺序栈空、获取顺序栈长度的实现》和《数据结构与算法基础-学习-10-线性表之顺序栈的清理、销毁、压栈、弹栈》

1、NewBinaryTreeNode

(1)描述

生成一个新节点,把数据放入结点中。

(2)定义

BinaryTreeNodePtr NewBinaryTreeNode(ElemType InputData)
{
    BinaryTreeNodePtr NewNodePtr = (BinaryTreeNodePtr)MyMalloc(sizeof(BinaryTreeNode));
    NewNodePtr->Data             = InputData;
    NewNodePtr->LeftNodePtr      = NULL;
    NewNodePtr->RightNodePtr     = NULL;
    memset(NewNodePtr->JudegeTreeUsedArray, JUDGE_TREE_UNUSED, sizeof(int) * JUDGE_TREE_ARRAY_LEN);//非递归前序遍历使用
    Log("New Binary Tree Node : OK\n",Debug);
    return NewNodePtr;
}

(3)参数介绍

参数名

描述

InputData

ElemType类型的数据。

2、GetBinaryTreeNodeNum

(1)描述

获取BST的总结点数。

(2)定义

BinaryTreeSizeType GetBinaryTreeNodeNum(BinaryTree* BT)
{
    JudgeAllNullPointer(BT);
    return BT->TreeNodeNum;
}

(3)参数介绍

参数名

描述

BT

BinaryTree*类型的BST指针。

3、CmpElemTypeData

(1)描述

对比ET1和ET2的大小。

(2)定义

#define LARGE_FLAG           0
#define LITTLE_FLAG          1
#define EQUAL_FLAG           2

Status CmpElemTypeData(ElemType ET1, ElemType ET2)
{
    if(ET1 > ET2)
    {
        return LARGE_FLAG;
    }
    else if(ET1 < ET2)
    {
        return LITTLE_FLAG;
    }
    else
    {
        return EQUAL_FLAG;
    }
}

(3)参数介绍

参数名

描述

ET1

ElemType类型数据。

ET2

ElemType类型数据。

4、AddBinarySearchTreeNode

(1)描述

将InputData数据放入BST中。

(2)定义

//假设二叉搜索树中没有相同元素,且数据都是正数,根节点大于左子树,小于右子树。
Status AddBinarySearchTreeNode(BinaryTree* BT, ElemType InputData)
{
    JudgeAllNullPointer(BT);
    if(BT->NodePtr == NULL)
    {
        BT->NodePtr = NewBinaryTreeNode(InputData);
        BT->TreeNodeNum++;
        Log("Add BST Node         : OK\n",Debug);
        return SuccessFlag;
    }
    BinaryTreeNodePtr TmpPtr = BT->NodePtr;
    while(TmpPtr)
    {
        if(CmpElemTypeData(TmpPtr->Data, InputData) == LARGE_FLAG)
        {
            if(TmpPtr->LeftNodePtr == NULL)
            {
                TmpPtr->LeftNodePtr = NewBinaryTreeNode(InputData);
                BT->TreeNodeNum++;
                Log("Add BST Node         : OK\n",Debug);
                return SuccessFlag;
            }
            TmpPtr = TmpPtr->LeftNodePtr;
        }
        else if(CmpElemTypeData(TmpPtr->Data, InputData) == LITTLE_FLAG)
        {
            if(TmpPtr->RightNodePtr == NULL)
            {
                TmpPtr->RightNodePtr = NewBinaryTreeNode(InputData);
                BT->TreeNodeNum++;
                Log("Add BST Node         : OK\n",Debug);
                return SuccessFlag;
            }
            TmpPtr = TmpPtr->RightNodePtr;
        }
        else
        {
            Log("AddBinarySearchTreeNode function not supported : same element.\n",Debug);
            Log("Add BST Node         : Fail\n",Debug);
            return FailFlag;
        }
    }
    return FailFlag; 
}

(3)参数介绍

参数名

描述

BT

BinaryTree*类型的BST。

InputData

ElemType类型的输入数据。

5、NewBinarySearchTree

(1)描述

给一个数组生成一棵BST。

(2)定义

Status NewBinarySearchTree(BinaryTree* BT, ElemType* Array)
{
    BinaryTreeSizeType i;   
    for(i = 0; i < InsertDataArrayLen; i++)
    {
        AddBinarySearchTreeNode(BT, Array[i]);
    }
    Log("New Binary Search Tree: OK\n",Info);
    return SuccessFlag;
}

(3)参数介绍

参数名

描述

BT

BinaryTree*类型的BST。

Array

ElemType*类型的输入数据数据。

6、InitBinaryTree

(1)描述

初始化二叉树。

(2)定义

Status InitBinaryTree(BinaryTree* BT)
{
    JudgeAllNullPointer(BT);
    BT->TreeNodeNum = 0;
    Log("Init Binary Tree      : OK\n",Info);
    return SuccessFlag;
}

(3)参数介绍

参数名

描述

BT

BinaryTree*类型的BST。

7、InOrderTraverseNoRecursion

(1)描述

中序遍历非递归方法实现。

(2)定义

Status InOrderTraverseNoRecursion(BinaryTreeNodePtr RootPTR)
{
    if(RootPTR == NULL)
    {
        return SuccessFlag;
    }
    SqStack* S = (SqStack*)MyMalloc(sizeof(SqStack));
    BinaryTreeNodePtr TmpPtr  = RootPTR;

    InitSqStack(S);
    while(TmpPtr || JudgeSqStackIsEmpty(S) == FailFlag)//如果指针和栈为空退出循环
    {
        if(TmpPtr)//如果节点不为空,说明有数据,中序遍历:左根右。将根压入栈,指针指向左子树。
        {
            PushSqStack(S, *TmpPtr);
            TmpPtr = TmpPtr->LeftNodePtr;
        }
        else//如果节点为空,说明左子树没有数据,弹栈获取上一层节点指针,获取根节点数据,再将指针指向右子树。
        {
            BinaryTreeNodePtr TmpPtr1 = (BinaryTreeNodePtr)MyMalloc(sizeof(BinaryTreeNode));
            PopSqStack(S, TmpPtr1);
            Insert2GlobalArray(&GA,TmpPtr1->Data);
            TmpPtr = TmpPtr1->RightNodePtr;
            free(TmpPtr1);
            TmpPtr1 = NULL;
        }
    }

    DestroyStack(S);
    return SuccessFlag;    
}

(3)参数介绍

参数名

描述

RootPTR

BinaryTreeNodePtr类型根节点。

8、PreOrderTraverseNoRecursion

(1)描述

前序遍历非递归方法实现。

(2)定义

Status PreOrderTraverseNoRecursion(BinaryTreeNodePtr RootPTR)
{
    if(RootPTR == NULL)
    {
        return SuccessFlag;
    }
    SqStack* S = (SqStack*)MyMalloc(sizeof(SqStack));
    BinaryTreeNodePtr TmpPtr  = RootPTR;

    InitSqStack(S);
    while(TmpPtr || JudgeSqStackIsEmpty(S) == FailFlag)//如果指针和栈为空退出循环
    {
        if(TmpPtr)
        {
            PushSqStack(S, *TmpPtr);
            Insert2GlobalArray(&GA,TmpPtr->Data);
            TmpPtr = TmpPtr->LeftNodePtr;
        }
        else
        {
            BinaryTreeNodePtr TmpPtr1 = (BinaryTreeNodePtr)MyMalloc(sizeof(BinaryTreeNode));
            PopSqStack(S, TmpPtr1);
            TmpPtr = TmpPtr1->RightNodePtr;
            free(TmpPtr1);
            TmpPtr1 = NULL;
        }
    }

    DestroyStack(S);
    return SuccessFlag;
}

(3)参数介绍

参数名

描述

RootPTR

BinaryTreeNodePtr类型根节点。

9、PostOrderTraverseNoRecursion

(1)描述

后序遍历非递归方法实现。

(2)定义

Status PostOrderTraverseNoRecursion(BinaryTreeNodePtr RootPTR)
{
    if(RootPTR == NULL)
    {
        return SuccessFlag;
    }
    SqStack* S = (SqStack*)MyMalloc(sizeof(SqStack));
    BinaryTreeNodePtr TmpPtr  = RootPTR;

    InitSqStack(S);
    while(TmpPtr || JudgeSqStackIsEmpty(S) == FailFlag)//如果指针和栈为空退出循环
    {
        if(TmpPtr && TmpPtr->JudegeTreeUsedArray[0] == JUDGE_TREE_UNUSED)
        {
            TmpPtr->JudegeTreeUsedArray[0] = JUDGE_TREE_USED;
            PushSqStack(S, *TmpPtr);
            TmpPtr = TmpPtr->LeftNodePtr;
        }
        else
        {
            BinaryTreeNodePtr TmpPtr1 = (BinaryTreeNodePtr)MyMalloc(sizeof(BinaryTreeNode));
            PopSqStack(S, TmpPtr1);
            if((TmpPtr1->JudegeTreeUsedArray)[JUDGE_TREE_ARRAY_LEN-1] == JUDGE_TREE_USED)
            {
                //printf("%d %d\n",TmpPtr1->JudegeTreeUsedArray[0],TmpPtr1->JudegeTreeUsedArray[JUDGE_TREE_ARRAY_LEN-1]);
                Insert2GlobalArray(&GA,TmpPtr1->Data);
                //PrintfGlobalArray(&GA,"tmp");
                if(PopSqStack(S, TmpPtr1) == FailFlag)//如果栈是空的,说明已经完成所有节点的遍历,跳出循环。
                {
                    free(TmpPtr1); 
                    TmpPtr1 = NULL;
                    break;
                }
            }
            TmpPtr = TmpPtr1->RightNodePtr;
            TmpPtr1->JudegeTreeUsedArray[JUDGE_TREE_ARRAY_LEN-1] = JUDGE_TREE_USED;
            PushSqStack(S, *TmpPtr1);
            free(TmpPtr1);
            TmpPtr1 = NULL;
        }
    }

    DestroyStack(S);
    return SuccessFlag;
}

(3)参数介绍

参数名

描述

RootPTR

BinaryTreeNodePtr类型根节点。

10、InOrderTraverse

(1)描述

中序遍历递归方法实现。

(2)定义

Status InOrderTraverse(BinaryTreeNodePtr RootPTR)
{
    if(RootPTR == NULL)
    {
        return SuccessFlag;
    }
    else
    {
        InOrderTraverse(RootPTR->LeftNodePtr);
        //printf("%d\n",RootPTR->Data);
        Insert2GlobalArray(&GA,RootPTR->Data);
        InOrderTraverse(RootPTR->RightNodePtr);
    }
    return SuccessFlag;
}

(3)参数介绍

参数名

描述

RootPTR

BinaryTreeNodePtr类型根节点。

11、PreOrderTraverse

(1)描述

前序遍历递归方法实现。

(2)定义

Status PreOrderTraverse(BinaryTreeNodePtr RootPTR)
{
    if(RootPTR == NULL)
    {
        return SuccessFlag;
    }
    else
    {
        Insert2GlobalArray(&GA,RootPTR->Data);
        PreOrderTraverse(RootPTR->LeftNodePtr);
        PreOrderTraverse(RootPTR->RightNodePtr);
    }
    return SuccessFlag;
}

(3)参数介绍

参数名

描述

RootPTR

BinaryTreeNodePtr类型根节点。

12、PostOrderTraverse

(1)描述

后序遍历递归方法实现。

(2)定义

Status PostOrderTraverse(BinaryTreeNodePtr RootPTR)
{
    if(RootPTR == NULL)
    {
        return SuccessFlag;
    }
    else
    {
        PostOrderTraverse(RootPTR->LeftNodePtr);
        PostOrderTraverse(RootPTR->RightNodePtr);
        Insert2GlobalArray(&GA,RootPTR->Data);
    }
    return SuccessFlag;
}

(3)参数介绍

参数名

描述

RootPTR

BinaryTreeNodePtr类型根节点。

九、LINUX环境测试

[gbase@czg2 Tree]$ make
gcc -Wall -g ../Log/Log.c BinaryTree.c main.c -o TestBinaryTree -I ../Log/

[gbase@czg2 Tree]$ ./TestBinaryTree 
2023-3--[Info]--Init Global Array      : OK
2023-3--[Info]--Init Binary Tree       : OK
2023-3--[Info]--New Binary Search Tree : OK
2023-3--[Info]--PreOrderTraverse       : [6 ,3 ,2 ,1 ,5 ,8 ,7 ], CurSize : 7
2023-3--[Info]--InOrderTraverse        : [1 ,2 ,3 ,5 ,6 ,7 ,8 ], CurSize : 7
2023-3--[Info]--PostOrderTraverse      : [1 ,2 ,5 ,3 ,7 ,8 ,6 ], CurSize : 7
2023-3--[Info]--PreOrderTraverseNoRcs  : [6 ,3 ,2 ,1 ,5 ,8 ,7 ], CurSize : 7
2023-3--[Info]--InOrderTraverseNoRcs   : [1 ,2 ,3 ,5 ,6 ,7 ,8 ], CurSize : 7
2023-3--[Info]--PostOrderTraverseNoRcs : [1 ,2 ,5 ,3 ,7 ,8 ,6 ], CurSize : 7

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

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

相关文章

【Linux学习】进程间通信——匿名管道 | 命名管道

&#x1f431;作者&#xff1a;一只大喵咪1201 &#x1f431;专栏&#xff1a;《Linux学习》 &#x1f525;格言&#xff1a;你只管努力&#xff0c;剩下的交给时间&#xff01; 从今天开始&#xff0c;Linux的代码就切换在VScode上写了&#xff0c;总算告别VIM了&#xff0c;…

DDOS攻击

注&#xff1a;本博客只是为了自己的学习&#xff0c;记录自己的学习&#xff0c;请勿用于其他途径、1、winR-->cmd2、ping 网站3、替换IP1 import java.io.BufferedInputStream;2 import java.io.IOException;3 import java.net.MalformedURLException;4 import java.net.U…

SpringBoot+WebSocket实时监控异常

# 写在前面此异常非彼异常&#xff0c;标题所说的异常是业务上的异常。最近做了一个需求&#xff0c;消防的设备巡检&#xff0c;如果巡检发现异常&#xff0c;通过手机端提交&#xff0c;后台的实时监控页面实时获取到该设备的信息及位置&#xff0c;然后安排员工去处理。因为…

Java每日一练(20230312)

目录 1. 两数之和 II ★ 2. 反转链表 ★★ 3. 二叉树的层序遍历 II ★★★ &#x1f31f; 每日一练刷题专栏 C/C 每日一练 ​专栏 Python 每日一练 专栏 Java 每日一练 专栏 1. 两数之和 II 给定一个已按照 非递减顺序排列 的整数数组 numbers &#xff0c;请你从数…

Proximal Policy Optimization (PPO) 算法理解:从策略梯度开始

近端策略优化&#xff08;PPO&#xff09;算法是OpenAI在2017提出的一种强化学习算法&#xff0c;被认为是目前强化学习领域的SOTA方法&#xff0c;也是适用性最广的算法之一。本文将从PPO算法的基础入手&#xff0c;理解从传统策略梯度算法&#xff08;例如REIFORCE算法&#…

JAVA进阶 —— Steam流

目录 一、 引言 二、 Stream流概述 三、Stream流的使用步骤 1. 获取Stream流 1.1 单列集合 1.2 双列集合 1.3 数组 1.4 零散数据 2. Stream流的中间方法 3. Stream流的终结方法 四、 练习 1. 数据过滤 2. 数据操作 - 按年龄筛选 3. 数据操作 - 演员信息要求…

全国程序员薪酬大曝光!看完我酸了····

2023年&#xff0c;随着互联网产业的蓬勃发展&#xff0c;程序员作为一个自带“高薪多金”标签的热门群体&#xff0c;被越来越多的人所关注。在过去充满未知的一年中&#xff0c;他们的职场现状发生了一定的改变。那么&#xff0c;程序员岗位的整体薪资水平、婚恋现状、职业方…

docker 安装 mysql:5.7 并进行数据库测试

安装mysql 5.7 容器执行安装命令$ docker run -itd --name mysql-test -p 3306:3306 -e MYSQL_ROOT_PASSWORDroot mysql查看执行结果使用navicat等数据库连接工具&#xff0c;连接mysql容器&#xff0c;默认用户名为root&#xff0c;密码即root创建数据库person&#xff0c;创建…

单片机怎么实现真正的多线程?

所谓多线程都是模拟的&#xff0c;本质都是单线程&#xff0c;因为cpu同一时刻只能执行一段代码。模拟的多线程就是任务之间快速切换&#xff0c;看起来像同时执行的样子。据说最近有多核的单片机&#xff0c;不过成本应该会高很多。对于模拟的多线程&#xff0c;我知道的有两种…

蓝桥刷题总结1

数组三角形 题目描述 上图给出了一个数字三角形。从三角形的顶部到底部有很多条不同的路径。对于每条路径&#xff0c;把路径上面的数加起来可以得到一个和&#xff0c;你的任务就是找到最大的和。 路径上的每一步只能从一个数走到下一层和它最近的左边的那个数或者右 边的那个…

【C++】红黑树

文章目录红黑树的概念红黑树的性质特征红黑树结点的定义红黑树的插入操作情况1情况2情况3特殊情况代码实现红黑树的验证红黑树的删除红黑树和AVL树的比较红黑树的应用红黑树的概念 红黑树&#xff0c;是一种二叉搜索树&#xff0c;但是每一个结点都增加一个存储位表示结点的颜…

订单30分钟未支付自动取消怎么实现?

目录了解需求方案 1&#xff1a;数据库轮询方案 2&#xff1a;JDK 的延迟队列方案 3&#xff1a;时间轮算法方案 4&#xff1a;redis 缓存方案 5&#xff1a;使用消息队列了解需求在开发中&#xff0c;往往会遇到一些关于延时任务的需求。例如生成订单 30 分钟未支付&#xff0…

保姆级使用PyTorch训练与评估自己的MobileViT网络教程

文章目录前言0. 环境搭建&快速开始1. 数据集制作1.1 标签文件制作1.2 数据集划分1.3 数据集信息文件制作2. 修改参数文件3. 训练4. 评估5. 其他教程前言 项目地址&#xff1a;https://github.com/Fafa-DL/Awesome-Backbones 操作教程&#xff1a;https://www.bilibili.co…

ARM 学习(一)

ARM 处理器的运行模式ARM处理器共有7种运行模式&#xff0c;如下表所示&#xff1a;处理器模式描述用户模式&#xff08;User&#xff09;正常程序运行模式中断模式&#xff08;IRQ&#xff09;用于通常的中断处理快速中断模式&#xff08;FIQ&#xff09;用于高速传输和通道处…

第十四届蓝桥杯三月真题刷题训练——第 11 天

目录 第 1 题&#xff1a;卡片 题目描述 运行限制 第 2 题&#xff1a;路径_dpgcd 运行限制 第 3 题&#xff1a;字符统计 问题描述 输入格式 输出格式 样例输入 样例输出 评测用例规模与约定 运行限制 第 4 题&#xff1a;费用报销 第 1 题&#xff1a;卡片 题…

vue基础面试题day(2)

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录Vue2.0 和 Vue3.0 有什么区别&#xff1f;Vue3带来了什么改变&#xff1f;reactive与ref的区别&#xff1f;计算属性computed和watch以及methods的区别&#xff1f;$…

我,30岁程序员被裁了,千万别干全栈

大家好&#xff0c;这里是程序员晚枫&#xff0c;今天是读者投稿。下面开始我们的正文。&#x1f447; 关注博主&#x1f449;程序员晚枫 很久了&#xff0c;今天给大家分享一下我从事程序员后&#xff0c;30岁被裁的经历&#xff0c;希望帮到有需要的人。 1、我被裁了 大家好…

28岁小公司程序员,无车无房不敢结婚,要不要转行?

大家好&#xff0c;这里是程序员晚枫&#xff0c;又来分享程序员的职场故事了~ 今天分享的这位朋友叫小青&#xff0c;我认识他2年多了。以前从事的是土木行业&#xff0c;2年前找我咨询转行程序员的学习路线和职业规划后&#xff0c;通过自学加入了一家创业公司&#xff0c;成…

LeetCode - 198 打家劫舍

目录 题目来源 题目描述 示例 提示 题目解析 算法源码 题目来源 198. 打家劫舍 - 力扣&#xff08;LeetCode&#xff09; 题目描述 你是一个专业的小偷&#xff0c;计划偷窃沿街的房屋。每间房内都藏有一定的现金&#xff0c;影响你偷窃的唯一制约因素就是相邻的房屋装…

Linux常用命令

个人简介&#xff1a;云计算网络运维专业人员&#xff0c;了解运维知识&#xff0c;掌握TCP/IP协议&#xff0c;每天分享网络运维知识与技能。座右铭&#xff1a;海不辞水&#xff0c;故能成其大&#xff1b;山不辞石&#xff0c;故能成其高。个人主页&#xff1a;小李会科技的…
最新文章