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] 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 | 106 ++++++- docs/chapter_tree/binary_tree.md | 80 ++++- 9 files changed, 968 insertions(+), 23 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"