From 9eac1275f65f4f7f70e2d23bcc325ae9eed4f1fb Mon Sep 17 00:00:00 2001 From: a16su <33782391+a16su@users.noreply.github.com> Date: Tue, 20 Dec 2022 15:52:00 +0800 Subject: [PATCH 1/5] add binary_tree and avl_tree python code --- codes/python/chapter_tree/avl_tree.py | 281 ++++++++++++++++++ .../python/chapter_tree/binary_search_tree.py | 167 ++++++++++- codes/python/chapter_tree/binary_tree.py | 32 +- codes/python/chapter_tree/binary_tree_bfs.py | 39 ++- codes/python/chapter_tree/binary_tree_dfs.py | 74 ++++- codes/python/include/binary_tree.py | 2 +- docs/chapter_tree/avl_tree.md | 210 ++++++++++++- docs/chapter_tree/binary_search_tree.md | 104 +++++++ docs/chapter_tree/binary_tree.md | 80 ++++- 9 files changed, 967 insertions(+), 22 deletions(-) create mode 100644 codes/python/chapter_tree/avl_tree.py diff --git a/codes/python/chapter_tree/avl_tree.py b/codes/python/chapter_tree/avl_tree.py new file mode 100644 index 000000000..4e6e35727 --- /dev/null +++ b/codes/python/chapter_tree/avl_tree.py @@ -0,0 +1,281 @@ +import sys, os.path as osp +import typing + +sys.path.append(osp.dirname(osp.dirname(osp.abspath(__file__)))) +from include import * + + +class AVLTreeNode: + def __init__( + self, + val=None, + height: int = 0, + left: typing.Optional["AVLTreeNode"] = None, + right: typing.Optional["AVLTreeNode"] = None, + ): + self.val = val + self.height = height + self.left = left + self.right = right + + def __str__(self): + val = self.val + left_val = self.left.val if self.left else None + right_val = self.right.val if self.right else None + return "".format( + val, left_val, right_val + ) + + +class AVLTree: + def __init__(self, root: typing.Optional[AVLTreeNode] = None): + self.root = root + + @staticmethod + def height(node: typing.Optional[AVLTreeNode]) -> int: + """ + 获取结点高度 + Args: + node:起始结点 + + Returns: 高度 or -1 + + """ + # 空结点高度为 -1 ,叶结点高度为 0 + if node is not None: + return node.height + return -1 + + def __update_height(self, node: AVLTreeNode): + """ + 更新结点高度 + Args: + node: 要更新高度的结点 + + Returns: None + + """ + # 结点高度等于最高子树高度 + 1 + node.height = max([self.height(node.left), self.height(node.right)]) + 1 + + def balance_factor(self, node: AVLTreeNode) -> int: + """ + 获取结点平衡因子 + Args: + node: 要获取平衡因子的结点 + + Returns: 平衡因子 + + """ + # 空结点平衡因子为 0 + if node is None: + return 0 + # 结点平衡因子 = 左子树高度 - 右子树高度 + return self.height(node.left) - self.height(node.right) + + def __right_rotate(self, node: AVLTreeNode) -> AVLTreeNode: + child = node.left + grand_child = child.right + # 以 child 为原点,将 node 向右旋转 + child.right = node + node.left = grand_child + # 更新结点高度 + self.__update_height(node) + self.__update_height(child) + # 返回旋转后子树的根节点 + return child + + def __left_rotate(self, node: AVLTreeNode) -> AVLTreeNode: + child = node.right + grand_child = child.left + # 以 child 为原点,将 node 向左旋转 + child.left = node + node.right = grand_child + # 更新结点高度 + self.__update_height(node) + self.__update_height(child) + # 返回旋转后子树的根节点 + return child + + def rotate(self, node: AVLTreeNode): + """ + 执行旋转操作,使该子树重新恢复平衡 + Args: + node: 要旋转的根结点 + + Returns: 旋转后的根结点 + + """ + # 获取结点 node 的平衡因子 + balance_factor = self.balance_factor(node) + # 左偏树 + if balance_factor > 1: + if self.balance_factor(node.left) >= 0: + # 右旋 + return self.__right_rotate(node) + else: + # 先左旋后右旋 + node.left = self.__left_rotate(node.left) + return self.__right_rotate(node) + # 右偏树 + elif balance_factor < -1: + if self.balance_factor(node.right) <= 0: + # 左旋 + return self.__left_rotate(node) + else: + # 先右旋后左旋 + node.right = self.__right_rotate(node.right) + return self.__left_rotate(node) + # 平衡树,无需旋转,直接返回 + return node + + def insert(self, val) -> AVLTreeNode: + """ + 插入结点 + Args: + val: 结点的值 + + Returns: + node: 插入结点后的根结点 + """ + self.root = self.insert_helper(self.root, val) + return self.root + + def insert_helper( + self, node: typing.Optional[AVLTreeNode], val: int + ) -> AVLTreeNode: + """ + 递归插入结点(辅助函数) + Args: + node: 要插入的根结点 + val: 要插入的结点的值 + + Returns: 插入结点后的根结点 + + """ + if node is None: + return AVLTreeNode(val) + # 1. 查找插入位置,并插入结点 + if val < node.val: + node.left = self.insert_helper(node.left, val) + elif val > node.val: + node.right = self.insert_helper(node.right, val) + else: + # 重复结点不插入,直接返回 + return node + # 更新结点高度 + self.__update_height(node) + # 2. 执行旋转操作,使该子树重新恢复平衡 + return self.rotate(node) + + def remove(self, val: int): + """ + 删除结点 + Args: + val: 要删除的结点的值 + + Returns: + + """ + root = self.remove_helper(self.root, val) + return root + + def remove_helper( + self, node: typing.Optional[AVLTreeNode], val: int + ) -> typing.Optional[AVLTreeNode]: + """ + 递归删除结点(辅助函数) + Args: + node: 删除的起始结点 + val: 要删除的结点的值 + + Returns: 删除目标结点后的起始结点 + + """ + if node is None: + return None + # 1. 查找结点,并删除之 + if val < node.val: + node.left = self.remove_helper(node.left, val) + elif val > node.val: + node.right = self.remove_helper(node.right, val) + else: + if node.left is None or node.right is None: + child = node.left or node.right + # 子结点数量 = 0 ,直接删除 node 并返回 + if child is None: + return None + # 子结点数量 = 1 ,直接删除 node + else: + node = child + else: # 子结点数量 = 2 ,则将中序遍历的下个结点删除,并用该结点替换当前结点 + temp = self.min_node(node.right) + node.right = self.remove_helper(node.right, temp.val) + node.val = temp.val + # 更新结点高度 + self.__update_height(node) + # 2. 执行旋转操作,使该子树重新恢复平衡 + return self.rotate(node) + + def min_node( + self, node: typing.Optional[AVLTreeNode] + ) -> typing.Optional[AVLTreeNode]: + # 获取最小结点 + if node is None: + return None + # 循环访问左子结点,直到叶结点时为最小结点,跳出 + while node.left is not None: + node = node.left + return node + + def search(self, val: int): + cur = self.root + while cur is not None: + if cur.val < val: + cur = cur.right + elif cur.val > val: + cur = cur.left + else: + break + return cur + + +if __name__ == "__main__": + + def test_insert(tree: AVLTree, val: int): + tree.insert(val) + print("\n插入结点 {} 后,AVL 树为".format(val)) + print_tree(tree.root) + + def test_remove(tree: AVLTree, val: int): + tree.remove(val) + print("\n删除结点 {} 后,AVL 树为".format(val)) + print_tree(tree.root) + + # 初始化空 AVL 树 + avl_tree = AVLTree() + + # 插入结点 + # 请关注插入结点后,AVL 树是如何保持平衡的 + test_insert(avl_tree, 1) + test_insert(avl_tree, 2) + test_insert(avl_tree, 3) + test_insert(avl_tree, 4) + test_insert(avl_tree, 5) + test_insert(avl_tree, 8) + test_insert(avl_tree, 7) + test_insert(avl_tree, 9) + test_insert(avl_tree, 10) + test_insert(avl_tree, 6) + + # 插入重复结点 + test_insert(avl_tree, 7) + + # 删除结点 + # 请关注删除结点后,AVL 树是如何保持平衡的 + test_remove(avl_tree, 8) # 删除度为 0 的结点 + test_remove(avl_tree, 5) # 删除度为 1 的结点 + test_remove(avl_tree, 4) # 删除度为 2 的结点 + + result_node = avl_tree.search(7) + print("\n查找到的结点对象为 {},结点值 = {}".format(result_node, result_node.val)) diff --git a/codes/python/chapter_tree/binary_search_tree.py b/codes/python/chapter_tree/binary_search_tree.py index f9dd9ec95..211e7c0df 100644 --- a/codes/python/chapter_tree/binary_search_tree.py +++ b/codes/python/chapter_tree/binary_search_tree.py @@ -1,10 +1,173 @@ -''' +""" File: binary_search_tree.py Created Time: 2022-11-25 Author: Krahets (krahets@163.com) -''' +""" import sys, os.path as osp + sys.path.append(osp.dirname(osp.dirname(osp.abspath(__file__)))) from include import * + +class BinarySearchTree: + """ + 二叉搜索树 + """ + + def __init__(self, nums) -> None: + nums.sort() + self.__root = self.buildTree(nums, 0, len(nums) - 1) + + def buildTree(self, nums, start_index, end_index): + if start_index > end_index: + return None + mid = (start_index + end_index) // 2 + root = TreeNode(nums[mid]) + root.left = self.buildTree( + nums=nums, start_index=start_index, end_index=mid - 1 + ) + root.right = self.buildTree(nums=nums, start_index=mid + 1, end_index=end_index) + return root + + def get_root(self): + return self.__root + + def search(self, num): + """ + 查找结点 + """ + cur = self.get_root() + # 循环查找,越过叶结点后跳出 + while cur is not None: + # 目标结点在 root 的右子树中 + if cur.val < num: + cur = cur.right + # 目标结点在 root 的左子树中 + elif cur.val > num: + cur = cur.left + # 找到目标结点,跳出循环 + else: + break + return cur + + def insert(self, num): + """ + 插入结点 + """ + root = self.get_root() + # 若树为空,直接提前返回 + if root is None: + return None + + cur = root + pre = None + + # 循环查找,越过叶结点后跳出 + while cur is not None: + # 找到重复结点,直接返回 + if cur.val == num: + return None + pre = cur + + if cur.val < num: # 插入位置在 root 的右子树中 + cur = cur.right + else: # 插入位置在 root 的左子树中 + cur = cur.left + + # 插入结点 val + node = TreeNode(num) + if pre.val < num: + pre.right = node + else: + pre.left = node + return node + + def remove(self, num): + """ + 删除结点 + """ + root = self.get_root() + # 若树为空,直接提前返回 + if root is None: + return None + + cur = root + pre = None + + # 循环查找,越过叶结点后跳出 + while cur is not None: + # 找到待删除结点,跳出循环 + if cur.val == num: + break + pre = cur + if cur.val < num: # 待删除结点在 root 的右子树中 + cur = cur.right + else: # 待删除结点在 root 的左子树中 + cur = cur.left + + # 若无待删除结点,则直接返回 + if cur is None: + return None + + # 子结点数量 = 0 or 1 + if cur.left is None or cur.right is None: + # 当子结点数量 = 0 / 1 时, child = null / 该子结点 + child = cur.left or cur.right + # 删除结点 cur + if pre.left == cur: + pre.left = child + else: + pre.right = child + # 子结点数量 = 2 + else: + # 获取中序遍历中 cur 的下一个结点 + nex = self.min(cur.right) + tmp = nex.val + # 递归删除结点 nex + self.remove(nex.val) + # 将 nex 的值复制给 cur + cur.val = tmp + return cur + + def min(self, root): + """ + 获取最小结点 + """ + if root is None: + return root + + # 循环访问左子结点,直到叶结点时为最小结点,跳出 + while root.left is not None: + root = root.left + return root + + +if __name__ == "__main__": + # 初始化二叉搜索树 + nums = list(range(1, 16)) + bst = BinarySearchTree(nums=nums) + print("\n初始化的二叉树为\n") + print_tree(bst.get_root()) + + # 查找结点 + node = bst.search(5) + print("\n查找到的结点对象为: {},结点值 = {}".format(node, node.val)) + + # 插入结点 + ndoe = bst.insert(16) + print("\n插入结点 16 后,二叉树为\n") + print_tree(bst.get_root()) + + # 删除结点 + bst.remove(1) + print("\n删除结点 1 后,二叉树为\n") + print_tree(bst.get_root()) + + bst.remove(2) + print("\n删除结点 2 后,二叉树为\n") + print_tree(bst.get_root()) + + bst.remove(4) + print("\n删除结点 4 后,二叉树为\n") + print_tree(bst.get_root()) diff --git a/codes/python/chapter_tree/binary_tree.py b/codes/python/chapter_tree/binary_tree.py index 78afa868e..2a892fae8 100644 --- a/codes/python/chapter_tree/binary_tree.py +++ b/codes/python/chapter_tree/binary_tree.py @@ -1,10 +1,38 @@ -''' +""" File: binary_tree.py Created Time: 2022-11-25 Author: Krahets (krahets@163.com) -''' +""" import sys, os.path as osp + sys.path.append(osp.dirname(osp.dirname(osp.abspath(__file__)))) from include import * + +""" Driver Code """ +if __name__ == "__main__": + # 初始化二叉树 + # 初始化节点 + n1 = TreeNode(val=1) + n2 = TreeNode(val=2) + n3 = TreeNode(val=3) + n4 = TreeNode(val=4) + n5 = TreeNode(val=5) + n1.left = n2 + n1.right = n3 + n2.left = n4 + n2.right = n5 + print_tree(n1) + + # 插入与删除结点 + P = TreeNode(0) + + # 在 n1 -> n2 中间插入节点 P + n1.left = P + P.left = n2 + print_tree(n1) + + # 删除结点 + n1.left = n2 + print_tree(n1) diff --git a/codes/python/chapter_tree/binary_tree_bfs.py b/codes/python/chapter_tree/binary_tree_bfs.py index 43f192206..57d15f919 100644 --- a/codes/python/chapter_tree/binary_tree_bfs.py +++ b/codes/python/chapter_tree/binary_tree_bfs.py @@ -1,10 +1,45 @@ -''' +""" File: binary_tree_bfs.py Created Time: 2022-11-25 Author: Krahets (krahets@163.com) -''' +""" import sys, os.path as osp sys.path.append(osp.dirname(osp.dirname(osp.abspath(__file__)))) from include import * + +def hierOrder(root): + # 初始化队列,加入根结点 + queue = collections.deque() + queue.append(root) + # 初始化一个列表,用于保存遍历序列 + result = [] + while queue: + # 队列出队 + node = queue.popleft() + # 保存节点值 + result.append(node.val) + if node.left is not None: + # 左子结点入队 + queue.append(node.left) + if node.right is not None: + # 右子结点入队 + queue.append(node.right) + return result + + +""" Driver Code """ +if __name__ == "__main__": + # 初始化二叉树 + # 这里借助了一个从数组直接生成二叉树的函数 + root = list_to_tree( + arr=[1, 2, 3, 4, 5, 6, 7, None, None, None, None, None, None, None, None] + ) + print("\n初始化二叉树\n") + print_tree(root) + + # 层序遍历 + result = hierOrder(root) + print("\n层序遍历的结点打印序列 = ", result) + assert result == [1, 2, 3, 4, 5, 6, 7] \ No newline at end of file diff --git a/codes/python/chapter_tree/binary_tree_dfs.py b/codes/python/chapter_tree/binary_tree_dfs.py index f8415ef56..6c5b92a3f 100644 --- a/codes/python/chapter_tree/binary_tree_dfs.py +++ b/codes/python/chapter_tree/binary_tree_dfs.py @@ -1,10 +1,80 @@ -''' +""" File: binary_tree_dfs.py Created Time: 2022-11-25 Author: Krahets (krahets@163.com) -''' +""" import sys, os.path as osp sys.path.append(osp.dirname(osp.dirname(osp.abspath(__file__)))) from include import * + +result = [] + + +def preOrder(root): + """ + 前序遍历二叉树 + """ + if root is None: + return + + # 访问优先级:根结点 -> 左子树 -> 右子树 + result.append(root.val) + preOrder(root=root.left) + preOrder(root=root.right) + + +def inOrder(root): + """ + 中序遍历二叉树 + """ + if root is None: + return + + # 访问优先级:左子树 -> 根结点 -> 右子树 + inOrder(root=root.left) + result.append(root.val) + inOrder(root=root.right) + + +def postOrder(root): + """ + 后序遍历二叉树 + """ + if root is None: + return + + # 访问优先级:左子树 -> 右子树 -> 根结点 + postOrder(root=root.left) + postOrder(root=root.right) + result.append(root.val) + + +""" Driver Code """ +if __name__ == "__main__": + # 初始化二叉树 + # 这里借助了一个从数组直接生成二叉树的函数 + root = list_to_tree( + arr=[1, 2, 3, 4, 5, 6, 7, None, None, None, None, None, None, None, None] + ) + print("\n初始化二叉树\n") + print_tree(root) + + # 前序遍历 + result = [] + preOrder(root) + print("\n前序遍历的结点打印序列 = ", result) + assert result == [1, 2, 4, 5, 3, 6, 7] + + # 中序遍历 + result = [] + inOrder(root) + print("\n中序遍历的结点打印序列 = ", result) + assert result == [4, 2, 5, 1, 6, 3, 7] + + # 后序遍历 + result = [] + postOrder(root) + print("\n后序遍历的结点打印序列 = ", result) + assert result == [4, 5, 2, 6, 7, 3, 1] \ No newline at end of file diff --git a/codes/python/include/binary_tree.py b/codes/python/include/binary_tree.py index 24acb47d4..bfe5b5f27 100644 --- a/codes/python/include/binary_tree.py +++ b/codes/python/include/binary_tree.py @@ -9,7 +9,7 @@ import collections class TreeNode: """Definition for a binary tree node """ - def __init__(self, val=0, left=None, right=None): + def __init__(self, val=None, left=None, right=None): self.val = val self.left = left self.right = right diff --git a/docs/chapter_tree/avl_tree.md b/docs/chapter_tree/avl_tree.md index bfa2391de..ef88975b2 100644 --- a/docs/chapter_tree/avl_tree.md +++ b/docs/chapter_tree/avl_tree.md @@ -48,7 +48,24 @@ G. M. Adelson-Velsky 和 E. M. Landis 在其 1962 年发表的论文 "An algorit === "Python" ```python title="avl_tree.py" - + class AVLTreeNode: + def __init__( + self, + val=None, + height: int = 0, + left: typing.Optional["AVLTreeNode"] = None, + right: typing.Optional["AVLTreeNode"] = None + ): + self.val = val + self.height = height + self.left = left + self.right = right + + def __str__(self): + val = self.val + left_val = self.left.val if self.left else None + right_val = self.right.val if self.right else None + return "".format(val, left_val, right_val) ``` === "Go" @@ -108,7 +125,31 @@ G. M. Adelson-Velsky 和 E. M. Landis 在其 1962 年发表的论文 "An algorit === "Python" ```python title="avl_tree.py" - + def height(node: typing.Optional[AVLTreeNode]) -> int: + """ + 获取结点高度 + Args: + node:起始结点 + + Returns: 高度 or -1 + + """ + # 空结点高度为 -1 ,叶结点高度为 0 + if node is not None: + return node.height + return -1 + + def update_height(node: AVLTreeNode): + """ + 更新结点高度 + Args: + node: 要更新高度的结点 + + Returns: None + + """ + # 结点高度等于最高子树高度 + 1 + node.height = max([height(node.left), height(node.right)]) + 1 ``` === "Go" @@ -166,7 +207,20 @@ G. M. Adelson-Velsky 和 E. M. Landis 在其 1962 年发表的论文 "An algorit === "Python" ```python title="avl_tree.py" - + def balance_factor(node: AVLTreeNode) -> int: + """ + 获取结点平衡因子 + Args: + node: 要获取平衡因子的结点 + + Returns: 平衡因子 + + """ + # 空结点平衡因子为 0 + if node is None: + return 0 + # 结点平衡因子 = 左子树高度 - 右子树高度 + return height(node.left) - height(node.right) ``` === "Go" @@ -255,7 +309,17 @@ AVL 树的独特之处在于「旋转 Rotation」的操作,其可 **在不影 === "Python" ```python title="avl_tree.py" - + def rightRotate(node: AVLTreeNode): + child = node.left + grand_child = child.right + # 以 child 为原点,将 node 向右旋转 + child.right = node + node.left = grand_child + # 更新结点高度 + update_height(node) + update_height(child) + # 返回旋转后子树的根节点 + return child ``` === "Go" @@ -323,7 +387,17 @@ AVL 树的独特之处在于「旋转 Rotation」的操作,其可 **在不影 === "Python" ```python title="avl_tree.py" - + def leftRotate(node: AVLTreeNode): + child = node.right + grand_child = child.left + # 以 child 为原点,将 node 向左旋转 + child.left = node + node.right = grand_child + # 更新结点高度 + update_height(node) + update_height(child) + # 返回旋转后子树的根节点 + return child ``` === "Go" @@ -432,7 +506,37 @@ AVL 树的独特之处在于「旋转 Rotation」的操作,其可 **在不影 === "Python" ```python title="avl_tree.py" - + def rotate(node: AVLTreeNode): + """ + 执行旋转操作,使该子树重新恢复平衡 + Args: + node: 要旋转的根结点 + + Returns: 旋转后的根结点 + + """ + # 获取结点 node 的平衡因子 + factor = balance_factor(node) + # 左偏树 + if factor > 1: + if balance_factor(node.left) >= 0: + # 右旋 + return right_rotate(node) + else: + # 先左旋后右旋 + node.left = left_rotate(node.left) + return right_rotate(node) + # 右偏树 + elif factor < -1: + if balance_factor(node.right) <= 0: + # 左旋 + return left_rotate(node) + else: + # 先右旋后左旋 + node.right = right_rotate(node.right) + return left_rotate(node) + # 平衡树,无需旋转,直接返回 + return node ``` === "Go" @@ -507,7 +611,42 @@ AVL 树的独特之处在于「旋转 Rotation」的操作,其可 **在不影 === "Python" ```python title="avl_tree.py" - + def insert(val) -> AVLTreeNode: + """ + 插入结点 + Args: + val: 结点的值 + + Returns: + node: 插入结点后的根结点 + """ + root = insert_helper(root, val) + return root + + def insert_helper(node: typing.Optional[AVLTreeNode], val: int) -> AVLTreeNode: + """ + 递归插入结点(辅助函数) + Args: + node: 要插入的根结点 + val: 要插入的结点的值 + + Returns: 插入结点后的根结点 + + """ + if node is None: + return AVLTreeNode(val) + # 1. 查找插入位置,并插入结点 + if val < node.val: + node.left = insert_helper(node.left, val) + elif val > node.val: + node.right = insert_helper(node.right, val) + else: + # 重复结点不插入,直接返回 + return node + # 更新结点高度 + update_height(node) + # 2. 执行旋转操作,使该子树重新恢复平衡 + return rotate(node) ``` === "Go" @@ -604,7 +743,62 @@ AVL 树的独特之处在于「旋转 Rotation」的操作,其可 **在不影 === "Python" ```python title="avl_tree.py" - + def remove(val: int): + """ + 删除结点 + Args: + val: 要删除的结点的值 + + Returns: + + """ + root = remove_helper(root, val) + return root + + def remove_helper(node: typing.Optional[AVLTreeNode], val: int) -> typing.Optional[AVLTreeNode]: + """ + 递归删除结点(辅助函数) + Args: + node: 删除的起始结点 + val: 要删除的结点的值 + + Returns: 删除目标结点后的起始结点 + + """ + if node is None: + return None + # 1. 查找结点,并删除之 + if val < node.val: + node.left = remove_helper(node.left, val) + elif val > node.val: + node.right = remove_helper(node.right, val) + else: + if node.left is None or node.right is None: + child = node.left or node.right + # 子结点数量 = 0 ,直接删除 node 并返回 + if child is None: + return None + # 子结点数量 = 1 ,直接删除 node + else: + node = child + else: # 子结点数量 = 2 ,则将中序遍历的下个结点删除,并用该结点替换当前结点 + temp = min_node(node.right) + node.right = remove_helper(node.right, temp.val) + node.val = temp.val + # 更新结点高度 + update_height(node) + # 2. 执行旋转操作,使该子树重新恢复平衡 + return rotate(node) + + + def min_node(node: typing.Optional[AVLTreeNode]) -> typing.Optional[AVLTreeNode]: + # 获取最小结点 + if node is None: + return None + # 循环访问左子结点,直到叶结点时为最小结点,跳出 + while node.left is not None: + node = node.left + return node ``` === "Go" diff --git a/docs/chapter_tree/binary_search_tree.md b/docs/chapter_tree/binary_search_tree.md index 9ff364329..a9328ddc6 100644 --- a/docs/chapter_tree/binary_search_tree.md +++ b/docs/chapter_tree/binary_search_tree.md @@ -82,6 +82,23 @@ comments: true === "Python" ```python title="binary_search_tree.py" + def search(self, num): + """ + 查找结点 + """ + cur = self.get_root() + # 循环查找,越过叶结点后跳出 + while cur is not None: + # 目标结点在 root 的右子树中 + if cur.val < num: + cur = cur.right + # 目标结点在 root 的左子树中 + elif cur.val > num: + cur = cur.left + # 找到目标结点,跳出循环 + else: + break + return cur ``` @@ -228,7 +245,37 @@ comments: true === "Python" ```python title="binary_search_tree.py" + def insert(self, num): + """ + 插入结点 + """ + root = self.get_root() + # 若树为空,直接提前返回 + if root is None: + return None + cur = root + pre = None + + # 循环查找,越过叶结点后跳出 + while cur is not None: + # 找到重复结点,直接返回 + if cur.val == num: + return None + pre = cur + + if cur.val < num: # 插入位置在 root 的右子树中 + cur = cur.right + else: # 插入位置在 root 的左子树中 + cur = cur.left + + # 插入结点 val + node = TreeNode(num) + if pre.val < num: + pre.right = node + else: + pre.left = node + return node ``` === "Go" @@ -483,7 +530,64 @@ comments: true === "Python" ```python title="binary_search_tree.py" + def remove(self, num): + """ + 删除结点 + """ + root = self.get_root() + # 若树为空,直接提前返回 + if root is None: + return None + + cur = root + pre = None + # 循环查找,越过叶结点后跳出 + while cur is not None: + # 找到待删除结点,跳出循环 + if cur.val == num: + break + pre = cur + if cur.val < num: # 待删除结点在 root 的右子树中 + cur = cur.right + else: # 待删除结点在 root 的左子树中 + cur = cur.left + + # 若无待删除结点,则直接返回 + if cur is None: + return None + + # 子结点数量 = 0 or 1 + if cur.left is None or cur.right is None: + # 当子结点数量 = 0 / 1 时, child = null / 该子结点 + child = cur.left or cur.right + # 删除结点 cur + if pre.left == cur: + pre.left = child + else: + pre.right = child + # 子结点数量 = 2 + else: + # 获取中序遍历中 cur 的下一个结点 + nex = self.min(cur.right) + tmp = nex.val + # 递归删除结点 nex + self.remove(nex.val) + # 将 nex 的值复制给 cur + cur.val = tmp + return cur + + def min(self, root): + """ + 获取最小结点 + """ + if root is None: + return root + + # 循环访问左子结点,直到叶结点时为最小结点,跳出 + while root.left is not None: + root = root.left + return root ``` === "Go" diff --git a/docs/chapter_tree/binary_tree.md b/docs/chapter_tree/binary_tree.md index 243a0753f..ab67e6f80 100644 --- a/docs/chapter_tree/binary_tree.md +++ b/docs/chapter_tree/binary_tree.md @@ -33,9 +33,9 @@ comments: true === "Python" ```python title="" - """ 链表结点类 """ class TreeNode: - def __init__(self, val=0, left=None, right=None): + """ 链表结点类 """ + def __init__(self, val=None, left=None, right=None): self.val = val # 结点值 self.left = left # 左子结点指针 self.right = right # 右子结点指针 @@ -190,7 +190,18 @@ comments: true === "Python" ```python title="binary_tree.py" - + # 初始化二叉树 + # 初始化节点 + n1 = TreeNode(val=1) + n2 = TreeNode(val=2) + n3 = TreeNode(val=3) + n4 = TreeNode(val=4) + n5 = TreeNode(val=5) + # 构建引用指向(即指针) + n1.left = n2 + n1.right = n3 + n2.left = n4 + n2.right = n5 ``` === "Go" @@ -288,7 +299,13 @@ comments: true === "Python" ```python title="binary_tree.py" - + # 插入与删除结点 + p = TreeNode(0) + # 在 n1 -> n2 中间插入结点 P + n1.left = p + p.left = n2 + # 删除节点 P + n1.left = n2 ``` === "Go" @@ -406,7 +423,24 @@ comments: true === "Python" ```python title="binary_tree_bfs.py" - + def hierOrder(root): + # 初始化队列,加入根结点 + queue = collections.deque() + queue.append(root) + # 初始化一个列表,用于保存遍历序列 + result = [] + while queue: + # 队列出队 + node = queue.popleft() + # 保存节点值 + result.append(node.val) + if node.left is not None: + # 左子结点入队 + queue.append(node.left) + if node.right is not None: + # 右子结点入队 + queue.append(node.right) + return result ``` === "Go" @@ -578,7 +612,43 @@ comments: true === "Python" ```python title="binary_tree_dfs.py" + def preOrder(root): + """ + 前序遍历二叉树 + """ + if root is None: + return + + # 访问优先级:根结点 -> 左子树 -> 右子树 + result.append(root.val) + preOrder(root=root.left) + preOrder(root=root.right) + + def inOrder(root): + """ + 中序遍历二叉树 + """ + if root is None: + return + + # 访问优先级:左子树 -> 根结点 -> 右子树 + inOrder(root=root.left) + result.append(root.val) + inOrder(root=root.right) + + + def postOrder(root): + """ + 后序遍历二叉树 + """ + if root is None: + return + + # 访问优先级:左子树 -> 右子树 -> 根结点 + postOrder(root=root.left) + postOrder(root=root.right) + result.append(root.val) ``` === "Go" From 8b401c2acbd11b637fa0d413b64dc5b07c3b8882 Mon Sep 17 00:00:00 2001 From: a16su <33782391+a16su@users.noreply.github.com> Date: Tue, 27 Dec 2022 18:34:12 +0800 Subject: [PATCH 2/5] fix format error --- codes/python/chapter_tree/avl_tree.py | 159 +++++--------- .../python/chapter_tree/binary_search_tree.py | 76 +++---- codes/python/chapter_tree/binary_tree.py | 4 +- codes/python/chapter_tree/binary_tree_bfs.py | 21 +- codes/python/chapter_tree/binary_tree_dfs.py | 60 +++--- codes/python/include/binary_tree.py | 16 +- docs/chapter_tree/avl_tree.md | 194 ++++++------------ docs/chapter_tree/binary_search_tree.md | 35 ++-- docs/chapter_tree/binary_tree.md | 46 +++-- 9 files changed, 248 insertions(+), 363 deletions(-) diff --git a/codes/python/chapter_tree/avl_tree.py b/codes/python/chapter_tree/avl_tree.py index 4e6e35727..20cad94bc 100644 --- a/codes/python/chapter_tree/avl_tree.py +++ b/codes/python/chapter_tree/avl_tree.py @@ -1,3 +1,9 @@ +""" +File: avl_tree.py +Created Time: 2022-12-20 +Author: a16su (lpluls001@gmail.com) +""" + import sys, os.path as osp import typing @@ -5,75 +11,36 @@ sys.path.append(osp.dirname(osp.dirname(osp.abspath(__file__)))) from include import * -class AVLTreeNode: - def __init__( - self, - val=None, - height: int = 0, - left: typing.Optional["AVLTreeNode"] = None, - right: typing.Optional["AVLTreeNode"] = None, - ): - self.val = val - self.height = height - self.left = left - self.right = right - - def __str__(self): - val = self.val - left_val = self.left.val if self.left else None - right_val = self.right.val if self.right else None - return "".format( - val, left_val, right_val - ) - - class AVLTree: - def __init__(self, root: typing.Optional[AVLTreeNode] = None): + def __init__(self, root: typing.Optional[TreeNode] = None): self.root = root - @staticmethod - def height(node: typing.Optional[AVLTreeNode]) -> int: - """ - 获取结点高度 - Args: - node:起始结点 + """ 获取结点高度 """ - Returns: 高度 or -1 - - """ + def height(self, node: typing.Optional[TreeNode]) -> int: # 空结点高度为 -1 ,叶结点高度为 0 if node is not None: return node.height return -1 - def __update_height(self, node: AVLTreeNode): - """ - 更新结点高度 - Args: - node: 要更新高度的结点 + """ 更新结点高度 """ - Returns: None - - """ + def __update_height(self, node: TreeNode): # 结点高度等于最高子树高度 + 1 node.height = max([self.height(node.left), self.height(node.right)]) + 1 - def balance_factor(self, node: AVLTreeNode) -> int: - """ - 获取结点平衡因子 - Args: - node: 要获取平衡因子的结点 + """ 获取平衡因子 """ - Returns: 平衡因子 - - """ + def balance_factor(self, node: TreeNode) -> int: # 空结点平衡因子为 0 if node is None: return 0 # 结点平衡因子 = 左子树高度 - 右子树高度 return self.height(node.left) - self.height(node.right) - def __right_rotate(self, node: AVLTreeNode) -> AVLTreeNode: + """ 右旋操作 """ + + def __right_rotate(self, node: TreeNode) -> TreeNode: child = node.left grand_child = child.right # 以 child 为原点,将 node 向右旋转 @@ -85,7 +52,9 @@ class AVLTree: # 返回旋转后子树的根节点 return child - def __left_rotate(self, node: AVLTreeNode) -> AVLTreeNode: + """ 左旋操作 """ + + def __left_rotate(self, node: TreeNode) -> TreeNode: child = node.right grand_child = child.left # 以 child 为原点,将 node 向左旋转 @@ -97,15 +66,9 @@ class AVLTree: # 返回旋转后子树的根节点 return child - def rotate(self, node: AVLTreeNode): - """ - 执行旋转操作,使该子树重新恢复平衡 - Args: - node: 要旋转的根结点 + """ 执行旋转操作,使该子树重新恢复平衡 """ - Returns: 旋转后的根结点 - - """ + def __rotate(self, node: TreeNode) -> TreeNode: # 获取结点 node 的平衡因子 balance_factor = self.balance_factor(node) # 左偏树 @@ -129,76 +92,46 @@ class AVLTree: # 平衡树,无需旋转,直接返回 return node - def insert(self, val) -> AVLTreeNode: - """ - 插入结点 - Args: - val: 结点的值 + """ 插入结点 """ - Returns: - node: 插入结点后的根结点 - """ - self.root = self.insert_helper(self.root, val) + def insert(self, val) -> TreeNode: + self.root = self.__insert_helper(self.root, val) return self.root - def insert_helper( - self, node: typing.Optional[AVLTreeNode], val: int - ) -> AVLTreeNode: - """ - 递归插入结点(辅助函数) - Args: - node: 要插入的根结点 - val: 要插入的结点的值 + """ 递归插入结点(辅助函数)""" - Returns: 插入结点后的根结点 - - """ + def __insert_helper(self, node: typing.Optional[TreeNode], val: int) -> TreeNode: if node is None: - return AVLTreeNode(val) + return TreeNode(val) # 1. 查找插入位置,并插入结点 if val < node.val: - node.left = self.insert_helper(node.left, val) + node.left = self.__insert_helper(node.left, val) elif val > node.val: - node.right = self.insert_helper(node.right, val) + node.right = self.__insert_helper(node.right, val) else: # 重复结点不插入,直接返回 return node # 更新结点高度 self.__update_height(node) # 2. 执行旋转操作,使该子树重新恢复平衡 - return self.rotate(node) + return self.__rotate(node) + + """ 删除结点 """ def remove(self, val: int): - """ - 删除结点 - Args: - val: 要删除的结点的值 - - Returns: - - """ - root = self.remove_helper(self.root, val) + root = self.__remove_helper(self.root, val) return root - def remove_helper( - self, node: typing.Optional[AVLTreeNode], val: int - ) -> typing.Optional[AVLTreeNode]: - """ - 递归删除结点(辅助函数) - Args: - node: 删除的起始结点 - val: 要删除的结点的值 + """ 递归删除结点(辅助函数) """ - Returns: 删除目标结点后的起始结点 - - """ + def __remove_helper(self, node: typing.Optional[TreeNode], val: int) -> typing.Optional[TreeNode]: if node is None: return None # 1. 查找结点,并删除之 if val < node.val: - node.left = self.remove_helper(node.left, val) + node.left = self.__remove_helper(node.left, val) elif val > node.val: - node.right = self.remove_helper(node.right, val) + node.right = self.__remove_helper(node.right, val) else: if node.left is None or node.right is None: child = node.left or node.right @@ -210,17 +143,16 @@ class AVLTree: node = child else: # 子结点数量 = 2 ,则将中序遍历的下个结点删除,并用该结点替换当前结点 temp = self.min_node(node.right) - node.right = self.remove_helper(node.right, temp.val) + node.right = self.__remove_helper(node.right, temp.val) node.val = temp.val # 更新结点高度 self.__update_height(node) # 2. 执行旋转操作,使该子树重新恢复平衡 - return self.rotate(node) + return self.__rotate(node) - def min_node( - self, node: typing.Optional[AVLTreeNode] - ) -> typing.Optional[AVLTreeNode]: - # 获取最小结点 + """ 获取最小结点 """ + + def min_node(self, node: typing.Optional[TreeNode]) -> typing.Optional[TreeNode]: if node is None: return None # 循环访问左子结点,直到叶结点时为最小结点,跳出 @@ -228,15 +160,22 @@ class AVLTree: node = node.left return node + """ 查找结点 """ + def search(self, val: int): cur = self.root + # 循环查找,越过叶结点后跳出 while cur is not None: + # 目标结点在 root 的右子树中 if cur.val < val: cur = cur.right + # 目标结点在 root 的左子树中 elif cur.val > val: cur = cur.left + # 找到目标结点,跳出循环 else: break + # 返回目标结点 return cur diff --git a/codes/python/chapter_tree/binary_search_tree.py b/codes/python/chapter_tree/binary_search_tree.py index 211e7c0df..2123252c6 100644 --- a/codes/python/chapter_tree/binary_search_tree.py +++ b/codes/python/chapter_tree/binary_search_tree.py @@ -1,43 +1,46 @@ """ File: binary_search_tree.py -Created Time: 2022-11-25 -Author: Krahets (krahets@163.com) +Created Time: 2022-12-20 +Author: a16su (lpluls001@gmail.com) """ import sys, os.path as osp +import typing sys.path.append(osp.dirname(osp.dirname(osp.abspath(__file__)))) from include import * +""" 二叉搜索树 """ + + class BinarySearchTree: - """ - 二叉搜索树 - """ - - def __init__(self, nums) -> None: + def __init__(self, nums: typing.List[int]) -> None: nums.sort() - self.__root = self.buildTree(nums, 0, len(nums) - 1) + self.__root = self.build_tree(nums, 0, len(nums) - 1) - def buildTree(self, nums, start_index, end_index): + """ 构建二叉搜索树 """ + + def build_tree(self, nums: typing.List[int], start_index: int, end_index: int) -> typing.Optional[TreeNode]: if start_index > end_index: return None + + # 将数组中间结点作为根结点 mid = (start_index + end_index) // 2 root = TreeNode(nums[mid]) - root.left = self.buildTree( - nums=nums, start_index=start_index, end_index=mid - 1 - ) - root.right = self.buildTree(nums=nums, start_index=mid + 1, end_index=end_index) + # 递归建立左子树和右子树 + root.left = self.build_tree(nums=nums, start_index=start_index, end_index=mid - 1) + root.right = self.build_tree(nums=nums, start_index=mid + 1, end_index=end_index) return root - def get_root(self): + @property + def root(self) -> typing.Optional[TreeNode]: return self.__root - def search(self, num): - """ - 查找结点 - """ - cur = self.get_root() + """ 查找结点 """ + + def search(self, num: int) -> typing.Optional[TreeNode]: + cur = self.root # 循环查找,越过叶结点后跳出 while cur is not None: # 目标结点在 root 的右子树中 @@ -51,11 +54,10 @@ class BinarySearchTree: break return cur - def insert(self, num): - """ - 插入结点 - """ - root = self.get_root() + """ 插入结点 """ + + def insert(self, num: int) -> typing.Optional[TreeNode]: + root = self.root # 若树为空,直接提前返回 if root is None: return None @@ -83,11 +85,10 @@ class BinarySearchTree: pre.left = node return node - def remove(self, num): - """ - 删除结点 - """ - root = self.get_root() + """ 删除结点 """ + + def remove(self, num: int) -> typing.Optional[TreeNode]: + root = self.root # 若树为空,直接提前返回 if root is None: return None @@ -130,10 +131,9 @@ class BinarySearchTree: cur.val = tmp return cur - def min(self, root): - """ - 获取最小结点 - """ + """ 获取最小结点 """ + + def min(self, root: typing.Optional[TreeNode]) -> typing.Optional[TreeNode]: if root is None: return root @@ -148,7 +148,7 @@ if __name__ == "__main__": nums = list(range(1, 16)) bst = BinarySearchTree(nums=nums) print("\n初始化的二叉树为\n") - print_tree(bst.get_root()) + print_tree(bst.root) # 查找结点 node = bst.search(5) @@ -157,17 +157,17 @@ if __name__ == "__main__": # 插入结点 ndoe = bst.insert(16) print("\n插入结点 16 后,二叉树为\n") - print_tree(bst.get_root()) + print_tree(bst.root) # 删除结点 bst.remove(1) print("\n删除结点 1 后,二叉树为\n") - print_tree(bst.get_root()) + print_tree(bst.root) bst.remove(2) print("\n删除结点 2 后,二叉树为\n") - print_tree(bst.get_root()) + print_tree(bst.root) bst.remove(4) print("\n删除结点 4 后,二叉树为\n") - print_tree(bst.get_root()) + print_tree(bst.root) diff --git a/codes/python/chapter_tree/binary_tree.py b/codes/python/chapter_tree/binary_tree.py index 2a892fae8..b1d8a13e3 100644 --- a/codes/python/chapter_tree/binary_tree.py +++ b/codes/python/chapter_tree/binary_tree.py @@ -1,7 +1,7 @@ """ File: binary_tree.py -Created Time: 2022-11-25 -Author: Krahets (krahets@163.com) +Created Time: 2022-12-20 +Author: a16su (lpluls001@gmail.com) """ import sys, os.path as osp diff --git a/codes/python/chapter_tree/binary_tree_bfs.py b/codes/python/chapter_tree/binary_tree_bfs.py index 57d15f919..d7865b6f7 100644 --- a/codes/python/chapter_tree/binary_tree_bfs.py +++ b/codes/python/chapter_tree/binary_tree_bfs.py @@ -1,17 +1,22 @@ """ File: binary_tree_bfs.py -Created Time: 2022-11-25 -Author: Krahets (krahets@163.com) +Created Time: 2022-12-20 +Author: a16su (lpluls001@gmail.com) """ import sys, os.path as osp +import typing + sys.path.append(osp.dirname(osp.dirname(osp.abspath(__file__)))) from include import * -def hierOrder(root): +""" 层序遍历 """ + + +def hier_order(root: TreeNode): # 初始化队列,加入根结点 - queue = collections.deque() + queue: typing.Deque[TreeNode] = collections.deque() queue.append(root) # 初始化一个列表,用于保存遍历序列 result = [] @@ -33,13 +38,11 @@ def hierOrder(root): if __name__ == "__main__": # 初始化二叉树 # 这里借助了一个从数组直接生成二叉树的函数 - root = list_to_tree( - arr=[1, 2, 3, 4, 5, 6, 7, None, None, None, None, None, None, None, None] - ) + root = list_to_tree(arr=[1, 2, 3, 4, 5, 6, 7, None, None, None, None, None, None, None, None]) print("\n初始化二叉树\n") print_tree(root) # 层序遍历 - result = hierOrder(root) + result = hier_order(root) print("\n层序遍历的结点打印序列 = ", result) - assert result == [1, 2, 3, 4, 5, 6, 7] \ No newline at end of file + assert result == [1, 2, 3, 4, 5, 6, 7] diff --git a/codes/python/chapter_tree/binary_tree_dfs.py b/codes/python/chapter_tree/binary_tree_dfs.py index 6c5b92a3f..31b160552 100644 --- a/codes/python/chapter_tree/binary_tree_dfs.py +++ b/codes/python/chapter_tree/binary_tree_dfs.py @@ -1,10 +1,12 @@ """ File: binary_tree_dfs.py -Created Time: 2022-11-25 -Author: Krahets (krahets@163.com) +Created Time: 2022-12-20 +Author: a16su (lpluls001@gmail.com) """ import sys, os.path as osp +import typing + sys.path.append(osp.dirname(osp.dirname(osp.abspath(__file__)))) from include import * @@ -12,42 +14,42 @@ from include import * result = [] -def preOrder(root): - """ - 前序遍历二叉树 - """ +""" 前序遍历二叉树 """ + + +def pre_order(root: typing.Optional[TreeNode]): if root is None: return # 访问优先级:根结点 -> 左子树 -> 右子树 result.append(root.val) - preOrder(root=root.left) - preOrder(root=root.right) + pre_order(root=root.left) + pre_order(root=root.right) -def inOrder(root): - """ - 中序遍历二叉树 - """ +""" 中序遍历二叉树 """ + + +def in_order(root: typing.Optional[TreeNode]): if root is None: return # 访问优先级:左子树 -> 根结点 -> 右子树 - inOrder(root=root.left) + in_order(root=root.left) result.append(root.val) - inOrder(root=root.right) + in_order(root=root.right) -def postOrder(root): - """ - 后序遍历二叉树 - """ +""" 后序遍历二叉树 """ + + +def post_order(root: typing.Optional[TreeNode]): if root is None: return # 访问优先级:左子树 -> 右子树 -> 根结点 - postOrder(root=root.left) - postOrder(root=root.right) + post_order(root=root.left) + post_order(root=root.right) result.append(root.val) @@ -55,26 +57,24 @@ def postOrder(root): if __name__ == "__main__": # 初始化二叉树 # 这里借助了一个从数组直接生成二叉树的函数 - root = list_to_tree( - arr=[1, 2, 3, 4, 5, 6, 7, None, None, None, None, None, None, None, None] - ) + root = list_to_tree(arr=[1, 2, 3, 4, 5, 6, 7, None, None, None, None, None, None, None, None]) print("\n初始化二叉树\n") print_tree(root) # 前序遍历 - result = [] - preOrder(root) + result.clear() + pre_order(root) print("\n前序遍历的结点打印序列 = ", result) assert result == [1, 2, 4, 5, 3, 6, 7] # 中序遍历 - result = [] - inOrder(root) + result.clear() + in_order(root) print("\n中序遍历的结点打印序列 = ", result) assert result == [4, 2, 5, 1, 6, 3, 7] # 后序遍历 - result = [] - postOrder(root) + result.clear() + post_order(root) print("\n后序遍历的结点打印序列 = ", result) - assert result == [4, 5, 2, 6, 7, 3, 1] \ No newline at end of file + assert result == [4, 5, 2, 6, 7, 3, 1] diff --git a/codes/python/include/binary_tree.py b/codes/python/include/binary_tree.py index bfe5b5f27..fe96f5046 100644 --- a/codes/python/include/binary_tree.py +++ b/codes/python/include/binary_tree.py @@ -10,9 +10,19 @@ class TreeNode: """Definition for a binary tree node """ def __init__(self, val=None, left=None, right=None): - self.val = val - self.left = left - self.right = right + self.val = val # 结点值 + self.height = 0 # 结点高度, avl 树会用到 + self.left = left # 左子结点引用 + self.right = right # 右子结点引用 + + def __str__(self): # 直接print时会好看一点 + val = self.val + left_node_val = self.left.val if self.left else None + right_node_val = self.right.val if self.right else None + return "".format(val, left_node_val, right_node_val) + + __repr__ = __str__ + def list_to_tree(arr): """Generate a binary tree with a list diff --git a/docs/chapter_tree/avl_tree.md b/docs/chapter_tree/avl_tree.md index ef88975b2..5f2cfb185 100644 --- a/docs/chapter_tree/avl_tree.md +++ b/docs/chapter_tree/avl_tree.md @@ -48,24 +48,21 @@ G. M. Adelson-Velsky 和 E. M. Landis 在其 1962 年发表的论文 "An algorit === "Python" ```python title="avl_tree.py" - class AVLTreeNode: - def __init__( - self, - val=None, - height: int = 0, - left: typing.Optional["AVLTreeNode"] = None, - right: typing.Optional["AVLTreeNode"] = None - ): - self.val = val - self.height = height - self.left = left - self.right = right + """ AVL 树结点类 """ + class TreeNode: + def __init__(self, val=None, left=None, right=None): + self.val = val # 结点值 + self.height = 0 # 结点高度, avl 树会用到 + self.left = left # 左子结点引用 + self.right = right # 右子结点引用 - def __str__(self): + def __str__(self): # 直接print时会好看一点 val = self.val - left_val = self.left.val if self.left else None - right_val = self.right.val if self.right else None - return "".format(val, left_val, right_val) + left_node_val = self.left.val if self.left else None + right_node_val = self.right.val if self.right else None + return "".format(val, left_node_val, right_node_val) + + __repr__ = __str__ ``` === "Go" @@ -125,31 +122,17 @@ G. M. Adelson-Velsky 和 E. M. Landis 在其 1962 年发表的论文 "An algorit === "Python" ```python title="avl_tree.py" - def height(node: typing.Optional[AVLTreeNode]) -> int: - """ - 获取结点高度 - Args: - node:起始结点 - - Returns: 高度 or -1 - - """ + """ 获取结点高度 """ + def height(self, node: typing.Optional[TreeNode]) -> int: # 空结点高度为 -1 ,叶结点高度为 0 if node is not None: return node.height return -1 - def update_height(node: AVLTreeNode): - """ - 更新结点高度 - Args: - node: 要更新高度的结点 - - Returns: None - - """ + """ 更新结点高度 """ + def __update_height(self, node: TreeNode): # 结点高度等于最高子树高度 + 1 - node.height = max([height(node.left), height(node.right)]) + 1 + node.height = max([self.height(node.left), self.height(node.right)]) + 1 ``` === "Go" @@ -207,20 +190,13 @@ G. M. Adelson-Velsky 和 E. M. Landis 在其 1962 年发表的论文 "An algorit === "Python" ```python title="avl_tree.py" - def balance_factor(node: AVLTreeNode) -> int: - """ - 获取结点平衡因子 - Args: - node: 要获取平衡因子的结点 - - Returns: 平衡因子 - - """ + """ 获取平衡因子 """ + def balance_factor(self, node: TreeNode) -> int: # 空结点平衡因子为 0 if node is None: return 0 # 结点平衡因子 = 左子树高度 - 右子树高度 - return height(node.left) - height(node.right) + return self.height(node.left) - self.height(node.right) ``` === "Go" @@ -309,15 +285,16 @@ AVL 树的独特之处在于「旋转 Rotation」的操作,其可 **在不影 === "Python" ```python title="avl_tree.py" - def rightRotate(node: AVLTreeNode): + """ 右旋操作 """ + def __right_rotate(self, node: TreeNode) -> TreeNode: child = node.left grand_child = child.right # 以 child 为原点,将 node 向右旋转 child.right = node node.left = grand_child # 更新结点高度 - update_height(node) - update_height(child) + self.__update_height(node) + self.__update_height(child) # 返回旋转后子树的根节点 return child ``` @@ -387,15 +364,16 @@ AVL 树的独特之处在于「旋转 Rotation」的操作,其可 **在不影 === "Python" ```python title="avl_tree.py" - def leftRotate(node: AVLTreeNode): + """ 左旋操作 """ + def __left_rotate(self, node: TreeNode) -> TreeNode: child = node.right grand_child = child.left # 以 child 为原点,将 node 向左旋转 child.left = node node.right = grand_child # 更新结点高度 - update_height(node) - update_height(child) + self.__update_height(node) + self.__update_height(child) # 返回旋转后子树的根节点 return child ``` @@ -506,35 +484,28 @@ AVL 树的独特之处在于「旋转 Rotation」的操作,其可 **在不影 === "Python" ```python title="avl_tree.py" - def rotate(node: AVLTreeNode): - """ - 执行旋转操作,使该子树重新恢复平衡 - Args: - node: 要旋转的根结点 - - Returns: 旋转后的根结点 - - """ + """ 执行旋转操作,使该子树重新恢复平衡 """ + def __rotate(self, node: TreeNode) -> TreeNode: # 获取结点 node 的平衡因子 - factor = balance_factor(node) + balance_factor = self.balance_factor(node) # 左偏树 - if factor > 1: - if balance_factor(node.left) >= 0: + if balance_factor > 1: + if self.balance_factor(node.left) >= 0: # 右旋 - return right_rotate(node) + return self.__right_rotate(node) else: # 先左旋后右旋 - node.left = left_rotate(node.left) - return right_rotate(node) + node.left = self.__left_rotate(node.left) + return self.__right_rotate(node) # 右偏树 - elif factor < -1: - if balance_factor(node.right) <= 0: + elif balance_factor < -1: + if self.balance_factor(node.right) <= 0: # 左旋 - return left_rotate(node) + return self.__left_rotate(node) else: # 先右旋后左旋 - node.right = right_rotate(node.right) - return left_rotate(node) + node.right = self.__right_rotate(node.right) + return self.__left_rotate(node) # 平衡树,无需旋转,直接返回 return node ``` @@ -611,42 +582,27 @@ AVL 树的独特之处在于「旋转 Rotation」的操作,其可 **在不影 === "Python" ```python title="avl_tree.py" - def insert(val) -> AVLTreeNode: - """ - 插入结点 - Args: - val: 结点的值 + """ 插入结点 """ + def insert(self, val) -> TreeNode: + self.root = self.__insert_helper(self.root, val) + return self.root - Returns: - node: 插入结点后的根结点 - """ - root = insert_helper(root, val) - return root - - def insert_helper(node: typing.Optional[AVLTreeNode], val: int) -> AVLTreeNode: - """ - 递归插入结点(辅助函数) - Args: - node: 要插入的根结点 - val: 要插入的结点的值 - - Returns: 插入结点后的根结点 - - """ + """ 递归插入结点(辅助函数)""" + def __insert_helper(self, node: typing.Optional[TreeNode], val: int) -> TreeNode: if node is None: - return AVLTreeNode(val) + return TreeNode(val) # 1. 查找插入位置,并插入结点 if val < node.val: - node.left = insert_helper(node.left, val) + node.left = self.__insert_helper(node.left, val) elif val > node.val: - node.right = insert_helper(node.right, val) + node.right = self.__insert_helper(node.right, val) else: # 重复结点不插入,直接返回 return node # 更新结点高度 - update_height(node) + self.__update_height(node) # 2. 执行旋转操作,使该子树重新恢复平衡 - return rotate(node) + return self.__rotate(node) ``` === "Go" @@ -743,35 +699,20 @@ AVL 树的独特之处在于「旋转 Rotation」的操作,其可 **在不影 === "Python" ```python title="avl_tree.py" - def remove(val: int): - """ - 删除结点 - Args: - val: 要删除的结点的值 - - Returns: - - """ - root = remove_helper(root, val) + """ 删除结点 """ + def remove(self, val: int): + root = self.__remove_helper(self.root, val) return root - def remove_helper(node: typing.Optional[AVLTreeNode], val: int) -> typing.Optional[AVLTreeNode]: - """ - 递归删除结点(辅助函数) - Args: - node: 删除的起始结点 - val: 要删除的结点的值 - - Returns: 删除目标结点后的起始结点 - - """ + """ 递归删除结点(辅助函数) """ + def __remove_helper(self, node: typing.Optional[TreeNode], val: int) -> typing.Optional[TreeNode]: if node is None: return None # 1. 查找结点,并删除之 if val < node.val: - node.left = remove_helper(node.left, val) + node.left = self.__remove_helper(node.left, val) elif val > node.val: - node.right = remove_helper(node.right, val) + node.right = self.__remove_helper(node.right, val) else: if node.left is None or node.right is None: child = node.left or node.right @@ -781,18 +722,17 @@ AVL 树的独特之处在于「旋转 Rotation」的操作,其可 **在不影 # 子结点数量 = 1 ,直接删除 node else: node = child - else: # 子结点数量 = 2 ,则将中序遍历的下个结点删除,并用该结点替换当前结点 - temp = min_node(node.right) - node.right = remove_helper(node.right, temp.val) + else: # 子结点数量 = 2 ,则将中序遍历的下个结点删除,并用该结点替换当前结点 + temp = self.min_node(node.right) + node.right = self.__remove_helper(node.right, temp.val) node.val = temp.val # 更新结点高度 - update_height(node) + self.__update_height(node) # 2. 执行旋转操作,使该子树重新恢复平衡 - return rotate(node) + return self.__rotate(node) - - def min_node(node: typing.Optional[AVLTreeNode]) -> typing.Optional[AVLTreeNode]: - # 获取最小结点 + """ 获取最小结点 """ + def min_node(self, node: typing.Optional[TreeNode]) -> typing.Optional[TreeNode]: if node is None: return None # 循环访问左子结点,直到叶结点时为最小结点,跳出 diff --git a/docs/chapter_tree/binary_search_tree.md b/docs/chapter_tree/binary_search_tree.md index a9328ddc6..08d16e4e4 100644 --- a/docs/chapter_tree/binary_search_tree.md +++ b/docs/chapter_tree/binary_search_tree.md @@ -82,11 +82,9 @@ comments: true === "Python" ```python title="binary_search_tree.py" - def search(self, num): - """ - 查找结点 - """ - cur = self.get_root() + """ 查找结点 """ + def search(self, num: int) -> typing.Optional[TreeNode]: + cur = self.root # 循环查找,越过叶结点后跳出 while cur is not None: # 目标结点在 root 的右子树中 @@ -99,7 +97,6 @@ comments: true else: break return cur - ``` === "Go" @@ -245,11 +242,9 @@ comments: true === "Python" ```python title="binary_search_tree.py" - def insert(self, num): - """ - 插入结点 - """ - root = self.get_root() + """ 插入结点 """ + def insert(self, num: int) -> typing.Optional[TreeNode]: + root = self.root # 若树为空,直接提前返回 if root is None: return None @@ -530,15 +525,13 @@ comments: true === "Python" ```python title="binary_search_tree.py" - def remove(self, num): - """ - 删除结点 - """ - root = self.get_root() + """ 删除结点 """ + def remove(self, num: int) -> typing.Optional[TreeNode]: + root = self.root # 若树为空,直接提前返回 if root is None: return None - + cur = root pre = None @@ -574,13 +567,11 @@ comments: true # 递归删除结点 nex self.remove(nex.val) # 将 nex 的值复制给 cur - cur.val = tmp + cur.val = tmp return cur - def min(self, root): - """ - 获取最小结点 - """ + """ 获取最小结点 """ + def min(self, root: typing.Optional[TreeNode]) -> typing.Optional[TreeNode]: if root is None: return root diff --git a/docs/chapter_tree/binary_tree.md b/docs/chapter_tree/binary_tree.md index ab67e6f80..d1e7774ad 100644 --- a/docs/chapter_tree/binary_tree.md +++ b/docs/chapter_tree/binary_tree.md @@ -33,12 +33,19 @@ comments: true === "Python" ```python title="" + """ 链表结点类 """ class TreeNode: - """ 链表结点类 """ def __init__(self, val=None, left=None, right=None): self.val = val # 结点值 self.left = left # 左子结点指针 self.right = right # 右子结点指针 + + def __str__(self): + val = self.val + left_node_val = self.left.val if self.left else None + right_node_val = self.right.val if self.right else None + return "".format(val, left_node_val, right_node_val) + ``` === "Go" @@ -423,7 +430,8 @@ comments: true === "Python" ```python title="binary_tree_bfs.py" - def hierOrder(root): + """ 层序遍历 """ + def hier_order(root): # 初始化队列,加入根结点 queue = collections.deque() queue.append(root) @@ -612,42 +620,36 @@ comments: true === "Python" ```python title="binary_tree_dfs.py" - def preOrder(root): - """ - 前序遍历二叉树 - """ + """ 前序遍历二叉树 """ + def pre_order(root: typing.Optional[TreeNode]): if root is None: return - + # 访问优先级:根结点 -> 左子树 -> 右子树 result.append(root.val) - preOrder(root=root.left) - preOrder(root=root.right) + pre_order(root=root.left) + pre_order(root=root.right) - def inOrder(root): - """ - 中序遍历二叉树 - """ + """ 中序遍历二叉树 """ + def in_order(root: typing.Optional[TreeNode]): if root is None: return # 访问优先级:左子树 -> 根结点 -> 右子树 - inOrder(root=root.left) + in_order(root=root.left) result.append(root.val) - inOrder(root=root.right) + in_order(root=root.right) - def postOrder(root): - """ - 后序遍历二叉树 - """ + """ 后序遍历二叉树 """ + def post_order(root: typing.Optional[TreeNode]): if root is None: return - + # 访问优先级:左子树 -> 右子树 -> 根结点 - postOrder(root=root.left) - postOrder(root=root.right) + post_order(root=root.left) + post_order(root=root.right) result.append(root.val) ``` From dbb25003ec9fec74e015a9019be0588df67523db Mon Sep 17 00:00:00 2001 From: Yudong Jin Date: Tue, 27 Dec 2022 19:24:43 +0800 Subject: [PATCH 3/5] Fine tune --- codes/python/chapter_tree/avl_tree.py | 18 +++--------------- .../python/chapter_tree/binary_search_tree.py | 8 +------- codes/python/chapter_tree/binary_tree.py | 3 +++ codes/python/chapter_tree/binary_tree_bfs.py | 2 -- codes/python/chapter_tree/binary_tree_dfs.py | 6 ------ 5 files changed, 7 insertions(+), 30 deletions(-) diff --git a/codes/python/chapter_tree/avl_tree.py b/codes/python/chapter_tree/avl_tree.py index 20cad94bc..d0ff48cba 100644 --- a/codes/python/chapter_tree/avl_tree.py +++ b/codes/python/chapter_tree/avl_tree.py @@ -16,7 +16,6 @@ class AVLTree: self.root = root """ 获取结点高度 """ - def height(self, node: typing.Optional[TreeNode]) -> int: # 空结点高度为 -1 ,叶结点高度为 0 if node is not None: @@ -24,13 +23,11 @@ class AVLTree: return -1 """ 更新结点高度 """ - def __update_height(self, node: TreeNode): # 结点高度等于最高子树高度 + 1 node.height = max([self.height(node.left), self.height(node.right)]) + 1 """ 获取平衡因子 """ - def balance_factor(self, node: TreeNode) -> int: # 空结点平衡因子为 0 if node is None: @@ -39,7 +36,6 @@ class AVLTree: return self.height(node.left) - self.height(node.right) """ 右旋操作 """ - def __right_rotate(self, node: TreeNode) -> TreeNode: child = node.left grand_child = child.right @@ -53,7 +49,6 @@ class AVLTree: return child """ 左旋操作 """ - def __left_rotate(self, node: TreeNode) -> TreeNode: child = node.right grand_child = child.left @@ -67,7 +62,6 @@ class AVLTree: return child """ 执行旋转操作,使该子树重新恢复平衡 """ - def __rotate(self, node: TreeNode) -> TreeNode: # 获取结点 node 的平衡因子 balance_factor = self.balance_factor(node) @@ -93,13 +87,11 @@ class AVLTree: return node """ 插入结点 """ - def insert(self, val) -> TreeNode: self.root = self.__insert_helper(self.root, val) return self.root """ 递归插入结点(辅助函数)""" - def __insert_helper(self, node: typing.Optional[TreeNode], val: int) -> TreeNode: if node is None: return TreeNode(val) @@ -117,13 +109,11 @@ class AVLTree: return self.__rotate(node) """ 删除结点 """ - def remove(self, val: int): root = self.__remove_helper(self.root, val) return root """ 递归删除结点(辅助函数) """ - def __remove_helper(self, node: typing.Optional[TreeNode], val: int) -> typing.Optional[TreeNode]: if node is None: return None @@ -142,7 +132,7 @@ class AVLTree: else: node = child else: # 子结点数量 = 2 ,则将中序遍历的下个结点删除,并用该结点替换当前结点 - temp = self.min_node(node.right) + temp = self.__min_node(node.right) node.right = self.__remove_helper(node.right, temp.val) node.val = temp.val # 更新结点高度 @@ -151,8 +141,7 @@ class AVLTree: return self.__rotate(node) """ 获取最小结点 """ - - def min_node(self, node: typing.Optional[TreeNode]) -> typing.Optional[TreeNode]: + def __min_node(self, node: typing.Optional[TreeNode]) -> typing.Optional[TreeNode]: if node is None: return None # 循环访问左子结点,直到叶结点时为最小结点,跳出 @@ -161,7 +150,6 @@ class AVLTree: return node """ 查找结点 """ - def search(self, val: int): cur = self.root # 循环查找,越过叶结点后跳出 @@ -179,8 +167,8 @@ class AVLTree: return cur +""" Driver Code """ if __name__ == "__main__": - def test_insert(tree: AVLTree, val: int): tree.insert(val) print("\n插入结点 {} 后,AVL 树为".format(val)) diff --git a/codes/python/chapter_tree/binary_search_tree.py b/codes/python/chapter_tree/binary_search_tree.py index 2123252c6..23e341854 100644 --- a/codes/python/chapter_tree/binary_search_tree.py +++ b/codes/python/chapter_tree/binary_search_tree.py @@ -12,15 +12,12 @@ from include import * """ 二叉搜索树 """ - - class BinarySearchTree: def __init__(self, nums: typing.List[int]) -> None: nums.sort() self.__root = self.build_tree(nums, 0, len(nums) - 1) """ 构建二叉搜索树 """ - def build_tree(self, nums: typing.List[int], start_index: int, end_index: int) -> typing.Optional[TreeNode]: if start_index > end_index: return None @@ -38,7 +35,6 @@ class BinarySearchTree: return self.__root """ 查找结点 """ - def search(self, num: int) -> typing.Optional[TreeNode]: cur = self.root # 循环查找,越过叶结点后跳出 @@ -55,7 +51,6 @@ class BinarySearchTree: return cur """ 插入结点 """ - def insert(self, num: int) -> typing.Optional[TreeNode]: root = self.root # 若树为空,直接提前返回 @@ -86,7 +81,6 @@ class BinarySearchTree: return node """ 删除结点 """ - def remove(self, num: int) -> typing.Optional[TreeNode]: root = self.root # 若树为空,直接提前返回 @@ -132,7 +126,6 @@ class BinarySearchTree: return cur """ 获取最小结点 """ - def min(self, root: typing.Optional[TreeNode]) -> typing.Optional[TreeNode]: if root is None: return root @@ -143,6 +136,7 @@ class BinarySearchTree: return root +""" Driver Code """ if __name__ == "__main__": # 初始化二叉搜索树 nums = list(range(1, 16)) diff --git a/codes/python/chapter_tree/binary_tree.py b/codes/python/chapter_tree/binary_tree.py index b1d8a13e3..2b25e4724 100644 --- a/codes/python/chapter_tree/binary_tree.py +++ b/codes/python/chapter_tree/binary_tree.py @@ -23,6 +23,7 @@ if __name__ == "__main__": n1.right = n3 n2.left = n4 n2.right = n5 + print("\n初始化二叉树\n") print_tree(n1) # 插入与删除结点 @@ -31,8 +32,10 @@ if __name__ == "__main__": # 在 n1 -> n2 中间插入节点 P n1.left = P P.left = n2 + print("\n插入结点 P 后\n") print_tree(n1) # 删除结点 n1.left = n2 + print("\n删除结点 P 后\n"); print_tree(n1) diff --git a/codes/python/chapter_tree/binary_tree_bfs.py b/codes/python/chapter_tree/binary_tree_bfs.py index d7865b6f7..c6a73013b 100644 --- a/codes/python/chapter_tree/binary_tree_bfs.py +++ b/codes/python/chapter_tree/binary_tree_bfs.py @@ -12,8 +12,6 @@ from include import * """ 层序遍历 """ - - def hier_order(root: TreeNode): # 初始化队列,加入根结点 queue: typing.Deque[TreeNode] = collections.deque() diff --git a/codes/python/chapter_tree/binary_tree_dfs.py b/codes/python/chapter_tree/binary_tree_dfs.py index 31b160552..b5dc9c9f3 100644 --- a/codes/python/chapter_tree/binary_tree_dfs.py +++ b/codes/python/chapter_tree/binary_tree_dfs.py @@ -15,8 +15,6 @@ result = [] """ 前序遍历二叉树 """ - - def pre_order(root: typing.Optional[TreeNode]): if root is None: return @@ -28,8 +26,6 @@ def pre_order(root: typing.Optional[TreeNode]): """ 中序遍历二叉树 """ - - def in_order(root: typing.Optional[TreeNode]): if root is None: return @@ -41,8 +37,6 @@ def in_order(root: typing.Optional[TreeNode]): """ 后序遍历二叉树 """ - - def post_order(root: typing.Optional[TreeNode]): if root is None: return From 449258f0b06fcb666f73bf4d6488f0de9be46942 Mon Sep 17 00:00:00 2001 From: Yudong Jin Date: Tue, 27 Dec 2022 19:33:58 +0800 Subject: [PATCH 4/5] Add the code to the docs. --- codes/cpp/chapter_tree/binary_tree_bfs.cpp | 8 +-- codes/python/chapter_tree/binary_tree.py | 7 ++- codes/python/chapter_tree/binary_tree_bfs.py | 24 ++++----- codes/python/chapter_tree/binary_tree_dfs.py | 38 ++++++-------- docs/chapter_tree/binary_tree.md | 6 +-- docs/chapter_tree/binary_tree_traversal.md | 52 +++++++++++++++++--- 6 files changed, 81 insertions(+), 54 deletions(-) diff --git a/codes/cpp/chapter_tree/binary_tree_bfs.cpp b/codes/cpp/chapter_tree/binary_tree_bfs.cpp index eeec2a18e..30c2d6007 100644 --- a/codes/cpp/chapter_tree/binary_tree_bfs.cpp +++ b/codes/cpp/chapter_tree/binary_tree_bfs.cpp @@ -15,12 +15,12 @@ vector hierOrder(TreeNode* root) { vector vec; while (!queue.empty()) { TreeNode* node = queue.front(); - queue.pop(); // 队列出队 - vec.push_back(node->val); // 保存结点 + queue.pop(); // 队列出队 + vec.push_back(node->val); // 保存结点 if (node->left != nullptr) - queue.push(node->left); // 左子结点入队 + queue.push(node->left); // 左子结点入队 if (node->right != nullptr) - queue.push(node->right); // 右子结点入队 + queue.push(node->right); // 右子结点入队 } return vec; } diff --git a/codes/python/chapter_tree/binary_tree.py b/codes/python/chapter_tree/binary_tree.py index 2b25e4724..d99026352 100644 --- a/codes/python/chapter_tree/binary_tree.py +++ b/codes/python/chapter_tree/binary_tree.py @@ -12,13 +12,14 @@ from include import * """ Driver Code """ if __name__ == "__main__": - # 初始化二叉树 + """ 初始化二叉树 """ # 初始化节点 n1 = TreeNode(val=1) n2 = TreeNode(val=2) n3 = TreeNode(val=3) n4 = TreeNode(val=4) n5 = TreeNode(val=5) + # 构建引用指向(即指针) n1.left = n2 n1.right = n3 n2.left = n4 @@ -26,15 +27,13 @@ if __name__ == "__main__": print("\n初始化二叉树\n") print_tree(n1) - # 插入与删除结点 + """ 插入与删除结点 """ P = TreeNode(0) - # 在 n1 -> n2 中间插入节点 P n1.left = P P.left = n2 print("\n插入结点 P 后\n") print_tree(n1) - # 删除结点 n1.left = n2 print("\n删除结点 P 后\n"); diff --git a/codes/python/chapter_tree/binary_tree_bfs.py b/codes/python/chapter_tree/binary_tree_bfs.py index c6a73013b..0320a08dd 100644 --- a/codes/python/chapter_tree/binary_tree_bfs.py +++ b/codes/python/chapter_tree/binary_tree_bfs.py @@ -14,22 +14,18 @@ from include import * """ 层序遍历 """ def hier_order(root: TreeNode): # 初始化队列,加入根结点 - queue: typing.Deque[TreeNode] = collections.deque() + queue = collections.deque() queue.append(root) # 初始化一个列表,用于保存遍历序列 - result = [] + res = [] while queue: - # 队列出队 - node = queue.popleft() - # 保存节点值 - result.append(node.val) + node = queue.popleft() # 队列出队 + res.append(node.val) # 保存节点值 if node.left is not None: - # 左子结点入队 - queue.append(node.left) + queue.append(node.left) # 左子结点入队 if node.right is not None: - # 右子结点入队 - queue.append(node.right) - return result + queue.append(node.right) # 右子结点入队 + return res """ Driver Code """ @@ -41,6 +37,6 @@ if __name__ == "__main__": print_tree(root) # 层序遍历 - result = hier_order(root) - print("\n层序遍历的结点打印序列 = ", result) - assert result == [1, 2, 3, 4, 5, 6, 7] + res = hier_order(root) + print("\n层序遍历的结点打印序列 = ", res) + assert res == [1, 2, 3, 4, 5, 6, 7] diff --git a/codes/python/chapter_tree/binary_tree_dfs.py b/codes/python/chapter_tree/binary_tree_dfs.py index b5dc9c9f3..11ee8339c 100644 --- a/codes/python/chapter_tree/binary_tree_dfs.py +++ b/codes/python/chapter_tree/binary_tree_dfs.py @@ -11,40 +11,34 @@ sys.path.append(osp.dirname(osp.dirname(osp.abspath(__file__)))) from include import * -result = [] +res = [] - -""" 前序遍历二叉树 """ +""" 前序遍历 """ def pre_order(root: typing.Optional[TreeNode]): if root is None: return - # 访问优先级:根结点 -> 左子树 -> 右子树 - result.append(root.val) + res.append(root.val) pre_order(root=root.left) pre_order(root=root.right) - -""" 中序遍历二叉树 """ +""" 中序遍历 """ def in_order(root: typing.Optional[TreeNode]): if root is None: return - # 访问优先级:左子树 -> 根结点 -> 右子树 in_order(root=root.left) - result.append(root.val) + res.append(root.val) in_order(root=root.right) - -""" 后序遍历二叉树 """ +""" 后序遍历 """ def post_order(root: typing.Optional[TreeNode]): if root is None: return - # 访问优先级:左子树 -> 右子树 -> 根结点 post_order(root=root.left) post_order(root=root.right) - result.append(root.val) + res.append(root.val) """ Driver Code """ @@ -56,19 +50,19 @@ if __name__ == "__main__": print_tree(root) # 前序遍历 - result.clear() + res.clear() pre_order(root) - print("\n前序遍历的结点打印序列 = ", result) - assert result == [1, 2, 4, 5, 3, 6, 7] + print("\n前序遍历的结点打印序列 = ", res) + assert res == [1, 2, 4, 5, 3, 6, 7] # 中序遍历 - result.clear() + res.clear() in_order(root) - print("\n中序遍历的结点打印序列 = ", result) - assert result == [4, 2, 5, 1, 6, 3, 7] + print("\n中序遍历的结点打印序列 = ", res) + assert res == [4, 2, 5, 1, 6, 3, 7] # 后序遍历 - result.clear() + res.clear() post_order(root) - print("\n后序遍历的结点打印序列 = ", result) - assert result == [4, 5, 2, 6, 7, 3, 1] + print("\n后序遍历的结点打印序列 = ", res) + assert res == [4, 5, 2, 6, 7, 3, 1] diff --git a/docs/chapter_tree/binary_tree.md b/docs/chapter_tree/binary_tree.md index 92539cc80..262b170be 100644 --- a/docs/chapter_tree/binary_tree.md +++ b/docs/chapter_tree/binary_tree.md @@ -182,7 +182,7 @@ comments: true === "Python" ```python title="binary_tree.py" - # 初始化二叉树 + """ 初始化二叉树 """ # 初始化节点 n1 = TreeNode(val=1) n2 = TreeNode(val=2) @@ -302,7 +302,7 @@ comments: true === "Python" ```python title="binary_tree.py" - # 插入与删除结点 + """ 插入与删除结点 """ p = TreeNode(0) # 在 n1 -> n2 中间插入结点 P n1.left = p @@ -461,7 +461,7 @@ comments: true === "Python" ```python title="" - “”“ 二叉树的数组表示 ”“” + """ 二叉树的数组表示 """ # 直接使用 None 来表示空位 tree = [1, 2, 3, 4, None, 6, 7, 8, 9, None, None, 12, None, None, 15] ``` diff --git a/docs/chapter_tree/binary_tree_traversal.md b/docs/chapter_tree/binary_tree_traversal.md index 971d24cc5..f46348412 100644 --- a/docs/chapter_tree/binary_tree_traversal.md +++ b/docs/chapter_tree/binary_tree_traversal.md @@ -51,12 +51,12 @@ comments: true vector vec; while (!queue.empty()) { TreeNode* node = queue.front(); - queue.pop(); // 队列出队 - vec.push_back(node->val); // 保存结点 + queue.pop(); // 队列出队 + vec.push_back(node->val); // 保存结点 if (node->left != nullptr) - queue.push(node->left); // 左子结点入队 + queue.push(node->left); // 左子结点入队 if (node->right != nullptr) - queue.push(node->right); // 右子结点入队 + queue.push(node->right); // 右子结点入队 } return vec; } @@ -65,7 +65,21 @@ comments: true === "Python" ```python title="binary_tree_bfs.py" - + """ 层序遍历 """ + def hier_order(root: TreeNode): + # 初始化队列,加入根结点 + queue = collections.deque() + queue.append(root) + # 初始化一个列表,用于保存遍历序列 + res = [] + while queue: + node = queue.popleft() # 队列出队 + res.append(node.val) # 保存节点值 + if node.left is not None: + queue.append(node.left) # 左子结点入队 + if node.right is not None: + queue.append(node.right) # 右子结点入队 + return res ``` === "Go" @@ -256,7 +270,32 @@ comments: true === "Python" ```python title="binary_tree_dfs.py" - + """ 前序遍历 """ + def pre_order(root: typing.Optional[TreeNode]): + if root is None: + return + # 访问优先级:根结点 -> 左子树 -> 右子树 + res.append(root.val) + pre_order(root=root.left) + pre_order(root=root.right) + + """ 中序遍历 """ + def in_order(root: typing.Optional[TreeNode]): + if root is None: + return + # 访问优先级:左子树 -> 根结点 -> 右子树 + in_order(root=root.left) + res.append(root.val) + in_order(root=root.right) + + """ 后序遍历 """ + def post_order(root: typing.Optional[TreeNode]): + if root is None: + return + # 访问优先级:左子树 -> 右子树 -> 根结点 + post_order(root=root.left) + post_order(root=root.right) + res.append(root.val) ``` === "Go" @@ -402,7 +441,6 @@ comments: true postOrder(root.right); list.Add(root.val); } - ``` !!! note From f9cc3a50cff45451eea9b973f4ffe06f232ce4a1 Mon Sep 17 00:00:00 2001 From: Yudong Jin Date: Tue, 27 Dec 2022 19:38:14 +0800 Subject: [PATCH 5/5] Fine tune --- codes/python/include/binary_tree.py | 10 +++++----- docs/chapter_tree/binary_tree.md | 7 ------- 2 files changed, 5 insertions(+), 12 deletions(-) diff --git a/codes/python/include/binary_tree.py b/codes/python/include/binary_tree.py index 1e2eb0346..670fd18ce 100644 --- a/codes/python/include/binary_tree.py +++ b/codes/python/include/binary_tree.py @@ -9,13 +9,13 @@ import collections class TreeNode: """Definition for a binary tree node """ - def __init__(self, val=None, left=None, right=None): - self.val = val # 结点值 - self.height = 0 # 结点高度, avl 树会用到 - self.left = left # 左子结点引用 + def __init__(self, val=0, left=None, right=None): + self.val = val # 结点值 + self.height = 0 # 结点高度 + self.left = left # 左子结点引用 self.right = right # 右子结点引用 - def __str__(self): # 直接print时会好看一点 + def __str__(self): val = self.val left_node_val = self.left.val if self.left else None right_node_val = self.right.val if self.right else None diff --git a/docs/chapter_tree/binary_tree.md b/docs/chapter_tree/binary_tree.md index 262b170be..4de1e4c1b 100644 --- a/docs/chapter_tree/binary_tree.md +++ b/docs/chapter_tree/binary_tree.md @@ -39,13 +39,6 @@ comments: true self.val = val # 结点值 self.left = left # 左子结点指针 self.right = right # 右子结点指针 - - def __str__(self): - val = self.val - left_node_val = self.left.val if self.left else None - right_node_val = self.right.val if self.right else None - return "".format(val, left_node_val, right_node_val) - ``` === "Go"