Python数据结构与算法篇(十五)-- 二叉树的遍历:深度优先搜索与广度优先搜索

news2024/11/23 8:30:46

        本篇开始总结二叉树的常用解题技巧,二叉树的顺序遍历和层序遍历刚好对应深度优先搜索和广度优先搜索。

1 顺序遍历

题目列表

  • 144. 前序遍历

  • 145. 二叉树的后序遍历

  • 94. 二叉树的中序遍历

144. 二叉树的前序遍历
        给你二叉树的根节点 root ,返回它节点值的 前序 遍历。

示例 1:
输入:root = [1,null,2,3]
输出:[1,2,3]

示例 2:
输入:root = []
输出:[]

1. 递归实现

        递归算法三要素:确定递归函数的参数和返回值、确定终止条件、确定单层递归的逻辑

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    def preorderTraversal(self, root: Optional[TreeNode]) -> List[int]:
        # 递归法
        if not root: return []
        result = []
        def traversal(root):
            if not root: return
            result.append(root.val)                 # 先将根节点值加入结果
            if root.left: traversal(root.left)      # 左
            if root.right: traversal(root.right)    # 右
        traversal(root)
        return result 

2. 迭代实现

        前序遍历是中左右,每次先处理的是中间节点,那么先将根节点放入栈中,然后将右孩子加入栈,再加入左孩子。

        为什么要先加入 右孩子,再加入左孩子呢? 因为这样出栈的时候才是中左右的顺序。

class Solution:
    def preorderTraversal(self, root: Optional[TreeNode]) -> List[int]:
        # 迭代法
        if not root: return []
        stack = [root]
        res = []
        while stack:
            node = stack.pop()
            res.append(node.val)
            if node.right: stack.append(node.right)
            if node.left: stack.append(node.left)
        return res

94. 二叉树的中序遍历

        给你二叉树的根节点 root ,返回它节点值的 中序 遍历。

示例 1:
输入:root = [1,null,2,3]
输出:[1,3,2]

示例 2:
输入:root = []
输出:[]

1. 递归实现

class Solution:
    def inorderTraversal(self, root: TreeNode) -> List[int]:
        result = []

        def traversal(root: TreeNode):
            if root == None:
                return
            traversal(root.left)    # 左
            result.append(root.val) # 中序
            traversal(root.right)   # 右

        traversal(root)
        return result

2. 迭代实现

        中序遍历是左中右,先访问的是二叉树顶部的节点,然后一层一层向下访问,直到到达树左面的最底部,再开始处理节点(也就是在把节点的数值放进result数组中),这就造成了处理顺序和访问顺序是不一致的。

        那么在使用迭代法写中序遍历,就需要借用指针的遍历来帮助访问节点,栈则用来处理节点上的元素。

class Solution:
    def inorderTraversal(self, root: Optional[TreeNode]) -> List[int]:
        if not root:    return []   # 空树
        stack = []                  # 不能提前将root结点加入stack中'
        res = []
        cur = root
        while cur or stack:
            if cur:                 # 先迭代访问最底层左子树结点
                stack.append(cur)
                cur = cur.left
            else:                   # 到达最左节点后处理栈顶结点
                cur = stack.pop()
                res.append(cur.val)
                cur = cur.right     # 取栈顶元素右结点
        return res

145. 二叉树的后序遍历
        给你二叉树的根节点 root ,返回它节点值的 后序 遍历。

示例 1:
输入:root = [1,null,2,3]
输出:[3,2,1]

示例 2:
输入:root = []
输出:[]

1. 递归实现

class Solution:
    def postorderTraversal(self, root: Optional[TreeNode]) -> List[int]:
        # 递归遍历
        if not root: return []
        result = []

        def traversal(root: Optional[TreeNode])-> List[int]:
            if not root: return
            self.traversal(root.left)               # 左
            self.traversal(root.right)              # 右
            self.result.append(root.val)            # 中
        traversal(root)
        return result

2. 迭代实现

        后序遍历,先序遍历是中左右,后续遍历是左右中,那么我们只需要调整一下先序遍历的代码顺序,就变成中右左的遍历顺序,然后在反转result数组,输出的结果顺序就是左右中了,如下图:

class Solution:
    def postorderTraversal(self, root: Optional[TreeNode]) -> List[int]:
        # 迭代遍历
        if not root: return []
        stack = [root]
        result = []
        while stack:
            node = stack.pop()
            result.append(node.val)
            if node.left: stack.append(node.left)
            if node.right: stack.append(node.right)
        return result[::-1]

3 层序遍历

  • 102. 二叉树的层序遍历

  • 107. 二叉树的层次遍历II

  • 199. 二叉树的右视图

  • 637.二叉树的层平均值

  • 429. N叉树的层序遍历/a>

  • 515. 在每个树行中找最大值

  • 116. 填充每个节点的下一个右侧节点指针

  • 117.填充每个节点的下一个右侧节点指针II

  • 104. 二叉树的最大深度

  • 111. 二叉树的最小深度

102. 二叉树的层序遍历

        给你二叉树的根节点 root ,返回其节点值的层序遍历。(即逐层地,从左到右访问所有节点)。

输入:root = [3,9,20,null,null,15,7]
输出:[[3],[9,20],[15,7]]

        层序遍历一个二叉树。就是从左到右一层一层的去遍历二叉树。这种遍历的方式和我们之前讲过的都不太一样。

        需要借用一个辅助数据结构即队列来实现,队列先进先出,符合一层一层遍历的逻辑,而用栈先进后出适合模拟深度优先遍历也就是递归的逻辑。

        而这种层序遍历方式就是图论中的广度优先遍历,只不过我们应用在二叉树上。

        使用队列实现二叉树广度优先遍历,动画如下:

方法一:广度优先搜索

class Solution:
    def levelOrder(self, root: Optional[TreeNode]) -> List[List[int]]:
        # 二叉树层序遍历迭代解法
        if not root: return []
        results = []
        que = deque([root])
        while que:
            size = len(que)
            result = []
            for _ in range(size):       # 这里一定要使用固定大小size,不要使用len(que),因为len(que)是不断变化的
                cur = que.popleft()
                result.append(cur.val)
                if cur.left:
                    que.append(cur.left)
                if cur.right:
                    que.append(cur.right)
            results.append(result)
        return results

方法二:深度优先搜索

        用广度优先处理是很直观的,可以想象成是一把刀横着切割了每一层,但是深度优先遍历就不那么直观了。

        我们开下脑洞,把这个二叉树的样子调整一下,摆成一个田字形的样子。田字形的每一层就对应一个 list。

        按照深度优先的处理顺序,会先访问节点 1,再访问节点 2,接着是节点 3。 之后是第二列的 4 和 5,最后是第三列的 6。

        每次递归的时候都需要带一个 index(表示当前的层数),也就对应那个田字格子中的第几行,如果当前行对应的 list 不存在,就加入一个空 list 进去。

        动态演示如下:

class Solution:
    def levelOrder(self, root: Optional[TreeNode]) -> List[List[int]]:
        # DFS
        def dfs(root, level):
            if not root: return
            # 假设 res 是 [[1], [2,3]], level 是 3,就再插入一个 [root.val] 放到 res 中
            if len(res) < level:
                res.append([root.val])
            else:
                # 将当前节点的值加入到res中,level 代表当前层,假设 level 是 3,节点值是 99
			    # res 是 [[1], [2,3], [4]],加入后 res 就变为 [[1], [2,3], [4,99]]
                res[level-1].append(root.val)
            # 递归的处理左子树,右子树,同时将层数 level+1
            dfs(root.left, level+1)
            dfs(root.right, level+1)

        res = []
        dfs(root, 1)
        return res

107. 二叉树的层次遍历II

        给你二叉树的根节点 root ,返回其节点值自底向上的层序遍历。 (即按从叶子节点所在层到根节点所在的层,逐层从左向右遍历)

输入:root = [3,9,20,null,null,15,7]
输出:[[15,7],[9,20],[3]]

方法一:广度优先搜索

from collections import deque
class Solution:
    def levelOrderBottom(self, root: Optional[TreeNode]) -> List[List[int]]:
        if not root: return []
        results = []
        que = deque([root])
        while que:
            size = len(que)
            result = []
            for _ in range(size):
                node = que.popleft()
                result.append(node.val)
                if node.left: que.append(node.left)
                if node.right: que.append(node.right)
            results.append(result)
        results.reverse()
        return results

方法二:深度优先搜索

class Solution:
    def levelOrderBottom(self, root: Optional[TreeNode]) -> List[List[int]]:
        # DFS
        def dfs(root, level):
            if not root: return
            if len(res) < level:
                res.append([root.val])
            else:
                res[level-1].append(root.val)
            dfs(root.left, level+1)
            dfs(root.right, level+1) 
        
        res = []
        dfs(root, 1)
        return res[::-1]

199. 二叉树的右视图

        给定一个二叉树的 根节点 root,想象自己站在它的右侧,按照从顶部到底部的顺序,返回从右侧所能看到的节点值。

输入: [1,2,3,null,5,null,4]
输出: [1,3,4]

from collections import deque
class Solution:
    def rightSideView(self, root: Optional[TreeNode]) -> List[int]:
        if not root: return []
        res = []
        # deque 相比list的好处是,list的 pop(0) 是 O(n) 复杂度,deque 的 popleft() 是 O(1) 复杂度
        que = deque([root])
        while que:
            res.append(que[-1].val)         # 每次都取最后一个node就可以
            size = len(que)
            for _ in range(size):           # 执行这个遍历的目的是获取下一层所有的node
                node = que.popleft()
                if node.left: que.append(node.left)
                if node.right: que.append(node.right)
        return res

637. 二叉树的层平均值

        给定一个非空二叉树的根节点 root , 以数组的形式返回每一层节点的平均值。与实际答案相差 10-5 以内的答案可以被接受。

输入:root = [3,9,20,null,null,15,7]
输出:[3.00000,14.50000,11.00000]
解释:第 0 层的平均值为 3,第 1 层的平均值为 14.5,第 2 层的平均值为 11 。因此返回 [3, 14.5, 11] 。

方法一:广度优先搜索

        从根节点开始搜索,每一轮遍历同一层的全部节点,计算该层的节点数以及该层的节点值之和,然后计算该层的平均值。

        如何确保每一轮遍历的是同一层的全部节点呢?我们可以借鉴层次遍历的做法,广度优先搜索使用队列存储待访问节点,只要确保在每一轮遍历时,队列中的节点是同一层的全部节点即可。具体做法如下:

  • 初始时,将根节点加入队列;
  • 每一轮遍历时,将队列中的节点全部取出,计算这些节点的数量以及它们的节点值之和,并计算这些节点的平均值,然后将这些节点的全部非空子节点加入队列,重复上述操作直到队列为空,遍历结束。

        由于初始时队列中只有根节点,满足队列中的节点是同一层的全部节点,每一轮遍历时都会将队列中的当前层节点全部取出,并将下一层的全部节点加入队列,因此可以确保每一轮遍历的是同一层的全部节点。

        具体实现方面,可以在每一轮遍历之前获得队列中的节点数量 size \textit{size} size,遍历时只遍历 size \textit{size} size 个节点,即可满足每一轮遍历的是同一层的全部节点。

from collections import deque
class Solution:
    def averageOfLevels(self, root: Optional[TreeNode]) -> List[float]:
        result = []
        que = deque([root])
        while que:
            size = len(que)
            total = 0
            for _ in range(size):
                cur = que.popleft()
                total += cur.val
                if cur.left: que.append(cur.left)
                if cur.right: que.append(cur.right)
            result.append(total/size)
        return result

方法二:深度优先搜索

        使用深度优先搜索计算二叉树的层平均值,需要维护两个数组, counts \textit{counts} counts 用于存储二叉树的每一层的节点数, sums \textit{sums} sums 用于存储二叉树的每一层的节点值之和。搜索过程中需要记录当前节点所在层,如果访问到的节点在第 i i i 层,则将 counts [ i ] \textit{counts}[i] counts[i] 的值加 1,并将该节点的值加到 sums [ i ] \textit{sums}[i] sums[i]

        遍历结束之后,第 i i i 层的平均值即为 sums [ i ] / counts [ i ] \textit{sums}[i] / \textit{counts}[i] sums[i]/counts[i]

class Solution:
    def averageOfLevels(self, root: Optional[TreeNode]) -> List[float]:
        # DFS
        def dfs(root: Optional[TreeNode], level: int) -> List[float]:
            if not root: return
            if len(total) < level:          
                total.append(root.val)
                count.append(1)
            else:
                total[level-1] += root.val
                count[level-1] += 1
            dfs(root.left, level+1)
            dfs(root.right, level+1)

        count, total = [], []
        dfs(root, 1)
        return [t/c for t, c in zip(total, count)]

429. N叉树的层序遍历

        给定一个 N 叉树,返回其节点值的层序遍历。(即从左到右,逐层遍历)。树的序列化输入是用层序遍历,每组子节点都由 null 值分隔(参见示例)。

输入:root = [1,null,3,2,4,null,5,6]
输出:[[1],[3,2,4],[5,6]]

方法一:广度优先搜索

class Solution:
    def levelOrder(self, root: 'Node') -> List[List[int]]:
        if not root: return []
        results = []
        que = deque([root])
        while que:
            size = len(que)
            result = []
            for _ in range(size):
                node = que.popleft()
                result.append(node.val)
                # cur.children 是 Node 对象组成的列表,也可能为 None
                if node.children:
                    que.extend(node.children)
            results.append(result)
        return results

方法二:深度优先搜索

class Solution:
    def levelOrder(self, root: 'Node') -> List[List[int]]:
        # DFS
        def dfs(root, level):
            if not root: return
            if len(res) < level:
                res.append([root.val])
            else:
                res[level-1].append(root.val)
            for child in root.children:
                dfs(child, level+1)

        res = []
        dfs(root, 1)
        return res

515. 在每个树行中找最大值

        给定一棵二叉树的根节点 root ,请找出该二叉树中每一层的最大值。

输入: root = [1,3,2,5,3,null,9]
输出: [1,3,9]

方法一:广度优先搜索

class Solution:
    def largestValues(self, root: Optional[TreeNode]) -> List[int]:
        # BFS
        if not root: return []
        que = deque([root])
        res = []
        while que:
             size = len(que)
             max_value = float('-inf')
             for _ in range(size):
                 node = que.popleft()
                 max_value = max(max_value, node.val)
                 if node.left: que.append(node.left)
                 if node.right: que.append(node.right)
             res.append(max_value)
        return res

方法二:深度优先搜索

class Solution:
    def largestValues(self, root: Optional[TreeNode]) -> List[int]:
        # DFS
        def dfs(root, level):
            if not root: return 
            if len(res) < level:
                res.append(root.val)
            else:
                res[level-1] = (max(root.val, res[level-1]))
            dfs(root.left, level+1)
            dfs(root.right, level+1)
        res = []
        dfs(root, 1)
        return res

116. 填充每个节点的下一个右侧节点指针

方法一:层序遍历

from collections import deque
class Solution:
    def connect(self, root: 'Optional[Node]') -> 'Optional[Node]':
        if not root: return None        # 这里空树,直接返回None
        que = deque([root])
        while que:
            n = len(que)
            for i in range(n):
                cur = que.popleft()
                if cur.left: que.append(cur.left)
                if cur.right: que.append(cur.right)
                if i == n-1: break          # 遍历到最右边,结束本行循环
                cur.next = que[0]           # 指向同一行的右边节点
        return root

117. 填充每个节点的下一个右侧节点指针 II

from collections import deque
class Solution:
    def connect(self, root: 'Node') -> 'Node':
        if not root: return root
        que = deque([root])
        while que:
            size =  len(que)
            for i in range(size):
                cur = que.popleft()
                if cur.left: que.append(cur.left)
                if cur.right: que.append(cur.right)
                if i == size-1: break
                cur.next = que[0]
        return root

104. 二叉树的最大深度

        给定一个二叉树,找出其最大深度。二叉树的深度为根节点到最远叶子节点的最长路径上的节点数。

  • 说明: 叶子节点是指没有子节点的节点。
  • 示例:给定二叉树 [3,9,20,null,null,15,7]
   3
   / \
  9  20
    /  \
   15   7

        返回它的最大深度 3。

方法一:深度优先搜索

from collections import deque
class Solution:
    def maxDepth(self, root: Optional[TreeNode]) -> int:
        if not root: return 0
        que = deque([root])
        depth = 0
        while que:
            size = len(que)
            depth += 1
            for _ in range(size):
                node = que.popleft()
                if node.left: que.append(node.left)
                if node.right: que.append(node.right)

        return depth

方法二:广度优先搜索

class Solution:
    def maxDepth(self, root: Optional[TreeNode]) -> int:
        # DFS 自底向上
        if not root: return 0
        # 感受一下这里是将最底层的结果往上抛
        # 因为这里的递归边界条件是叶子节点
        left_height = self.maxDepth(root.left)
        right_height = self.maxDepth(root.right)
        return max(left_height, right_height) + 1
        
        # DFS 自顶向下
        res = 0
        def dfs(root, depth):
            nonlocal res
            if not root: return
            if not root.left and not root.right:
                res = max(res, depth)
            dfs(root.left, depth+1)
            dfs(root.right, depth+1)
        dfs(root, 1)
        return res
  • 自顶向下:直接return 函数调用自身下一级实现,比如 return Fibonacci(n-1) + Fibonacci(n-2);
  • 自底向上:先递归到最小单位(叶子节点),再从最小单位往上抛结果,传递结果

111. 二叉树的最小深度

        给定一个二叉树,找出其最小深度。最小深度是从根节点到最近叶子节点的最短路径上的节点数量。

  • 说明:叶子节点是指没有子节点的节点。
  • 示例 1:

输入:root = [3,9,20,null,null,15,7]
输出:2

方法一:深度优先搜索

class Solution:
    def minDepth(self, root: TreeNode) -> int:
        if not root:
            return 0
        
        if not root.left and not root.right:
            return 1
        
        min_depth = 10**9
        if root.left:
            min_depth = min(self.minDepth(root.left), min_depth)
        if root.right:
            min_depth = min(self.minDepth(root.right), min_depth)
        
        return min_depth + 1

方法二:广度优先搜索

class Solution:
    def minDepth(self, root: TreeNode) -> int:
        if not root:
            return 0

        que = collections.deque([(root, 1)])
        while que:
            node, depth = que.popleft()
            if not node.left and not node.right:
                return depth
            if node.left:
                que.append((node.left, depth + 1))
            if node.right:
                que.append((node.right, depth + 1))
        
        return 0

二叉树遍历暂时告一段落,但还有很多自己不满意的地方,后面在学习中持续补充,谢谢大家的鼓励和支持!

_____

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

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

相关文章

程序员开发之“留一手“

很多乙方公司为了顺利获得项目的尾款&#xff0c;或者有些项目的封装整合的逻辑比较多&#xff0c;通常会把项目的业务逻辑代码及架构进行打包成线上NuGet包。 一、 NuGet包 其实就是线上的.dll文件 &#xff0c;在本地编译后上传是NuGet 1、首先注册NuGet 2、记住API Key …

chatgpt赋能python:Python*a:提高代码效率的利器

Python *a&#xff1a;提高代码效率的利器 Python是一种高层次、通用性编程语言。Python的简洁语法和宽松语义&#xff0c;让它成为了软件开发、数据分析、科学计算等领域的首选语言之一。Python也因其易学、易读、易部署的特点而被全球越来越多的开发者所喜爱。在这篇文章中&…

Redis事务及网络处理

一 Redis事务 redis开启事务后&#xff0c;会把接下来的所有命令缓存到一个单独的队列中&#xff0c;在提交事务时&#xff0c;使这些命令不可被分割的一起执行完成。 如果使用了watch命令监视某一个key&#xff0c;如果在开启事务之后&#xff0c;提交事务之前&#xff0c;有…

超级牛散也踩雷!这A股宣布大消息

公司被债权人申请重整一事被法院正式立案7个多月后&#xff0c;5月24日&#xff0c;*ST搜特收到了法院的终结预重整程序通知书和不予受理重整申请裁定书。 消息曝出后&#xff0c;*ST搜特股吧则瞬间炸锅&#xff0c;投资者纷纷留言“完了”、“没盼头了”、“最后的希望终究还…

浅谈IAM——OAuth2.0攻击方法总结

一、OAuth协议介绍 OAuth是一种标准授权协议&#xff0c;它允许用户在不需要向第三方网站或应用提供密码的情况下向第三方网站或应用授予对存储于其他网站或应用上的信息的委托访问权限。OAuth通过访问令牌来实现这一功能。 1.发展历史 OAuth协议始于2006年Twitter公司OpenI…

车载以太网 - SomeIP - 协议用例 - BehaviorBasic

目录 Service Discovery Communication Behavior 1、验证DUT启动后的重复报文阶段,2帧offer报文之间的时间间隔为上次的2倍<

【模型预测】A-4D战斗机姿态控制的模型预测控制方法(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

Java中的类加载机制

Java中的类加载机制 类的生命周期 ​ 一个类型从被加载到虚拟机内存中开始&#xff0c;到卸载出内存为止&#xff0c;它的整个生命周期将会经历加载&#xff08;Loading&#xff09;、验证&#xff08;Verification&#xff09;、准备&#xff08;Preparation&#xff09;、解…

C++ thread编程(Linux系统为例)—thread成员函数与thread的创建方法

c 11 之后有了标准的线程库&#xff1a;std::thread。 参考thread库的使用 成员函数 构造函数 thread的构造函数有下面四个重载 默认构造函数 thread() noexcept初始化构造函数 template <class Fn, class... Args> explicit thread (Fn&& fn, Args&&a…

Linux命令(21)之usermod

Linux命令之usermod 1.usermod介绍 usermod命令用来更改/etc/passwd或/etc/shadow文件下用户属性&#xff0c;包括但不限于shell类型、用户id&#xff0c;用户gid、家目录、锁定及解锁用户等等。 2.usermod用法 usermod [参数] [用户名] usermod常用参数 参数说明-u修改UID…

淘宝/天猫商品评论数据采集

淘宝商品评论API接口是指允许开发者通过API接口获取淘宝商品的评价信息的一种技术手段。通过使用这个接口&#xff0c;开发者可以快速获取淘宝商品的评价信息&#xff0c;以实现自己的商业用途。 淘宝商品评论API接口需要开发者提供相应的数据访问权限&#xff0c;包括授权和Ap…

Linux命令(22)之chage

Linux命令之chage 1.chage介绍 usermod命令用来更改linux用户密码到期信息&#xff0c;包括密码修改间隔最短、最长日期、密码失效时间等等。 2.chage用法 chage常用参数 参数说明-m密码可更改的最小天数&#xff0c;为0表示可以随时更改-M密码有效期最大天数-W密码到期前提…

代理模式 静态代理 JDK动态代理 Cglib动态代理

1.静态代理 总共只有两个类&#xff0c;代理类和被代理类。其中代理类是被代理类的增强和扩展 被代理的类C和代理类B都要实现同一个接口 代理类B中调用代理类C中相同的方法 interface D {public void function1(); }class C implements D {Overridepublic void function1(…

PyQt5桌面应用开发(18):自定义控件界面设计与实现

本文目录 PyQt5桌面应用系列定制控件-界面设计本文目标功能分析 功能设计绘制方形图案鼠标交互事件和属性 完整代码总结 PyQt5桌面应用系列 PyQt5桌面应用开发&#xff08;1&#xff09;&#xff1a;需求分析 PyQt5桌面应用开发&#xff08;2&#xff09;&#xff1a;事件循环 …

chatgpt赋能python:PythonTile:一种强大的界面构建工具

Python Tile&#xff1a;一种强大的界面构建工具 Python Tile是一种基于Python编程语言的界面构建工具&#xff0c;其目的是帮助开发者快速创建精美的用户界面&#xff0c;从而提高应用程序的用户体验。本文将介绍Python Tile的功能和优势&#xff0c;并讨论其在实际开发中的应…

Doris数据库BE——LoadChannelMgr原理解析

数据在经过清洗过滤后&#xff0c;会通过Open/AddBatch请求分批量将数据发送给存储层的BE节点上。在一个BE上支持多个LoadJob任务同时并发写入执行。LoadChannelMgr负责管理这些任务&#xff0c;并对数据进行分发。 internal service Open/AddBatch请求接口使用BRPC&#xff…

STP 生成树协议

STP&#xff08;Spanning-Tree Protocol&#xff09;的来源 在网络三层架构中&#xff0c;我们会使用冗余这一技术&#xff0c;也就是对三层架构中的这些东西进行备份。冗余包含了设备冗余、网关冗余、线路冗余、电源冗余。 在二层交换网络中进行线路冗余&#xff0c;如图&am…

Linux :: 【基础指令篇 :: 用户管理:(2)】::设置用户密码(及本地Xshell 登录云服务器操作演示) :: passwd

前言&#xff1a;本篇是 Linux 基本操作篇章的内容&#xff01; 笔者使用的环境是基于腾讯云服务器&#xff1a;CentOS 7.6 64bit。 目录索引&#xff1a; 1. 基本语法 2. 基本用法 3. 注意点 4. 补充&#xff1a;指定用户设置密码操作实例测试及登录本地 Xshell 登录演…

Linux命令(18)之file

Linux命令之file 1.file介绍 file命令用来识别文件类型。 2.file用法 file [参数] [文件或目录] file常用参数 参数说明-L显示符号廉洁所指向文件的类别-i显示MIME类别-b显示结果时&#xff0c;不显示文件名称 3.实例 3.1显示ztj.sh文件类型 3.2显示ztj.sh文件类型(不显示…