赞
踩
对于树结构,不论是查找修改还是增加删除,效率都比较高,结合了链表和数组的优点,如以下的二叉树:
1、数组的第一个元素作为第一个节点
2、数组的第二个元素3比7小,放在7的左边
3、数组的第三个元素10比7大,放在7的右边
4、数组的第四个元素1比7小,也比3小,放在3的左边
5、数组的第五个元素5比7小,但比3大,放在3的右边
6、数组的第六个元素9比7大,但比10小,放在10的左边
7、数组的第七个元素12比7大,比10大,放在10的右边
- # 创建 HeroNode 节点
- class HeroNode:
- def __init__(self, no: int, name: str):
- self.no = no
- self.name = name
- self.left = None
- self.right = None
-
- def __str__(self):
- return f"no={self.no}, name={self.name}"
-
- # 前序遍历
- def pre_order(self):
- # 先输出父节点
- print(self, end=' => ')
- # 左子树不为空则递归左子树
- if self.left is not None:
- self.left.pre_order()
- # 右子树不为空则递归右子树
- if self.right is not None:
- self.right.pre_order()
-
- # 中序遍历
- def infix_order(self):
- # 左子树不为空则递归左子树
- if self.left is not None:
- self.left.infix_order()
- # 输出父节点
- print(self, end=' => ')
- # 右子树不为空则递归右子树
- if self.right is not None:
- self.right.infix_order()
-
- # 后序遍历
- def post_order(self):
- # 左子树不为空则递归左子树
- if self.left is not None:
- self.left.post_order()
- # 右子树不为空则递归右子树
- if self.right is not None:
- self.right.post_order()
- # 输出父节点
- print(self, end=' => ')
-
-
- # 建立 HeroNode 二叉树
- class BinaryTree:
- root: HeroNode = None
-
- # 前序遍历
- def pre_order(self):
- if self.root is not None:
- self.root.pre_order()
- else:
- print("二叉树为空...")
-
- # 前序遍历
- def infix_order(self):
- if self.root is not None:
- self.root.infix_order()
- else:
- print("二叉树为空...")
-
- # 前序遍历
- def post_order(self):
- if self.root is not None:
- self.root.post_order()
- else:
- print("二叉树为空...")
-
-
- def test_binary_tree():
- # 手动创建二叉树
- binary_tree = BinaryTree()
- root = HeroNode(1, '宋江')
- node2 = HeroNode(2, '吴用')
- node3 = HeroNode(3, '卢俊义')
- node4 = HeroNode(4, '林冲')
-
- root.left = node2
- root.right = node3
- node3.right = node4
- binary_tree.root = root
-
- # 前序
- print("前序遍历:", end=" ")
- binary_tree.pre_order()
- print()
-
- # 中序
- print("中序遍历:", end=" ")
- binary_tree.infix_order()
- print()
-
- # 后序
- print("后序遍历:", end=" ")
- binary_tree.post_order()
- print()
-
-
- test_binary_tree()
- """ 前中后序遍历查找 """
- # 创建 HeroNode 节点
- class HeroNode:
- def __init__(self, no: int, name: str):
- self.no = no
- self.name = name
- self.left = None
- self.right = None
-
- def __str__(self):
- return f"no={self.no}, name={self.name}"
-
- # 前序遍历查找
- def pre_order_search(self, no: int):
- """
- 前序遍历查找某个节点
- :param no: 要查找节点的 id
- :return: 找到的 HeroNode 节点或 None
- """
- print("进入前序遍历...")
- if self.no == no: # 如果当前节点是,直接返回
- return self
-
- find_node = None
- # 如果左子节点不为空,则向左子节点继续递归查找
- # 找到则返回,找不到则看右子节点
- if self.left is not None:
- find_node = self.left.pre_order_search(no)
-
- if find_node: # 说明在左子树上找到,直接返回
- return find_node
-
- # 否则判断右子节点,若不为空,向右子树递归查找
- if self.right is not None:
- find_node = self.right.pre_order_search(no)
-
- # 如果右子树找到,则find_node有值,否则find_node为空
- return find_node
-
- # 中序遍历查找
- def infix_order_search(self, no: int):
- """
- 中序遍历查找某个节点
- :param no: 要查找节点的 id
- :return: 找到的 HeroNode 节点或 None
- """
- find_node = None
- # 如果左子节点不为空,则向左子节点继续递归查找
- # 找到则返回,找不到则看右子节点
- if self.left is not None:
- find_node = self.left.infix_order_search(no)
-
- if find_node: # 说明在左子树上找到,直接返回
- return find_node
- print("进入中序遍历...")
- if self.no == no: # 如果当前节点是,直接返回
- return self
-
- # 否则判断右子节点,若不为空,向右子树递归查找
- if self.right is not None:
- find_node = self.right.infix_order_search(no)
-
- # 如果右子树找到,则find_node有值,否则find_node为空
- return find_node
-
- # 后序遍历查找
- def post_order_search(self, no: int):
- """
- 后序遍历查找某个节点
- :param no: 要查找节点的 id
- :return: 找到的 HeroNode 节点或 None
- """
- find_node = None
- # 如果左子节点不为空,则向左子节点继续递归查找
- # 找到则返回,找不到则看右子节点
- if self.left is not None:
- find_node = self.left.post_order_search(no)
-
- if find_node: # 说明在左子树上找到,直接返回
- return find_node
-
- # 否则判断右子节点,若不为空,向右子树递归查找
- if self.right is not None:
- find_node = self.right.post_order_search(no)
-
- # 如果右子树找到,则find_node有值,否则find_node为空
- if find_node:
- return find_node
- print("进入后序遍历...")
- if self.no == no: # 如果当前节点是,直接返回
- return self
- return None
-
-
- # 建立 HeroNode 二叉树
- class BinaryTree:
- root: HeroNode = None
-
- # 前序查找
- def pre_order_search(self, no):
- if self.root is not None:
- return self.root.pre_order_search(no)
- else:
- return None
-
- # 中序查找
- def infix_order_search(self, no):
- if self.root is not None:
- return self.root.infix_order_search(no)
- else:
- return None
-
- # 后序查找
- def post_order_search(self, no):
- if self.root is not None:
- return self.root.post_order_search(no)
- else:
- return None
-
-
- def test_binary_tree():
- # 手动创建二叉树
- binary_tree = BinaryTree()
- root = HeroNode(1, '宋江')
- node2 = HeroNode(2, '吴用')
- node3 = HeroNode(3, '卢俊义')
- node4 = HeroNode(4, '林冲')
- node5 = HeroNode(5, "关胜")
-
- root.left = node2
- root.right = node3
- node3.right = node4
- node3.left = node5
- binary_tree.root = root
-
- print("前序遍历查找:") # 比较了4次(看输出得到的结果)
- res = binary_tree.pre_order_search(5)
- if res:
- print("找到了,节点信息为:", res)
- else:
- print("找不到编号为5的节点")
- print()
-
- print("中序遍历查找:") # 比较了3次(看输出得到的结果)
- res = binary_tree.infix_order_search(5)
- if res:
- print("找到了,节点信息为:", res)
- else:
- print("找不到编号为5的节点")
- print()
-
- print("后序遍历查找:") # 比较了2次(看输出得到的结果)
- res = binary_tree.post_order_search(5)
- if res:
- print("找到了,节点信息为:", res)
- else:
- print("找不到编号为5的节点")
-
-
- test_binary_tree()
- """ 递归删除二叉树节点 """
- # HeroNode 节点
- class HeroNode:
- def __init__(self, no: int, name: str):
- self.no = no
- self.name = name
- self.left = None
- self.right = None
-
- def __str__(self):
- return f"no={self.no}, name={self.name}"
-
- # 前序遍历
- def pre_order(self):
- # 先输出父节点
- print(self, end=' => ')
- # 左子树不为空则递归左子树
- if self.left is not None:
- self.left.pre_order()
- # 右子树不为空则递归右子树
- if self.right is not None:
- self.right.pre_order()
-
- def delete_node(self, no: int):
- """
- 递归删除节点规则:
- 如果删除的节点是叶子节点,则直接删除
- 如果删除的节点不是叶子节点,则删除该节点及其左右子树
- :param no: 要删除的节点编号
- :return:
- """
- # 如果左子节点不为空,且左子节点是要删除的节点,则删除左子节点及其子树,并返回
- if self.left and self.left.no == no:
- self.left = None # 相当于删除左子节点及其子树
- return
- # 如果右子节点不为空,且右子节点是要删除的节点,则删除右子节点及其子树,并返回
- if self.right and self.right.no == no:
- self.right = None # 相当于删除右子节点及其子树
- return
- # 如果左右子节点都不是要删除的节点,则首先向左子节点递归删除
- if self.left:
- self.left.delete_node(no)
- # 如果递归完左子节点还没找到要删除的节点,则继续向右子节点递归删除
- if self.right:
- self.right.delete_node(no)
-
-
-
- # 建立 HeroNode 二叉树
- class BinaryTree:
- root: HeroNode = None
-
- # 前序遍历
- def pre_order(self):
- if self.root is not None:
- self.root.pre_order()
- else:
- print("二叉树为空...")
-
- # 删除树节点
- def delete_node(self, no: int):
- if self.root:
- if self.root.no == no: # 如果根节点是要删除的节点
- self.root = None # 则把根节点置空
- else:
- self.root.delete_node(no)
- else:
- print("树空,不能删除节点...")
-
-
- def test_binary_tree():
- # 手动创建二叉树
- binary_tree = BinaryTree()
- root = HeroNode(1, '宋江')
- node2 = HeroNode(2, '吴用')
- node3 = HeroNode(3, '卢俊义')
- node4 = HeroNode(4, '林冲')
- node5 = HeroNode(5, "关胜")
-
- root.left = node2
- root.right = node3
- node3.right = node4
- node3.left = node5
- binary_tree.root = root
-
- print("删除前:", end='')
- binary_tree.pre_order()
- print()
-
- binary_tree.delete_node(5)
- print("删除后:", end='')
- binary_tree.pre_order()
- print()
-
-
-
- test_binary_tree()
需求如下:
- """顺序存储二叉树"""
- # 顺序存储二叉树就是用数组结构存储二叉树节点数据,
- # 要求用数组存储后,可以对该数组进行前序遍历、中序遍历、后序遍历
- # 其实就是将二叉树从左到右,从上到下的节点依次存入数组中,如下:
- """
- 假设有如下一棵二叉树,它对应的顺序存储就是:arr = [1, 2, 3, 4, 5, 6, 7]
- 1
- 2 3
- 4 5 6 7
- """
- class ArrayBinaryTree:
- def __init__(self, arr):
- self.arr = arr
-
- def pre_order(self, index: int):
- """
- 以前序遍历方式访问数组元素
- :param index: 数组下标
- :return:
- """
- n = len(self.arr) # n为数组长度
- if self.arr and n > 0:
- # 输出当前元素
- print(f"arr[{index}]={self.arr[index]}", end=" ")
- # 向左子树递归
- if 2 * index + 1 < n:
- self.pre_order(2 * index + 1)
- # 向右子树递归
- if 2 * index + 2 < n:
- self.pre_order(2 * index + 2)
- else:
- print("数组为空!")
-
- def infix_order(self, index: int):
- """
- 以中序遍历方式访问数组元素
- :param index: 数组下标
- :return:
- """
- n = len(self.arr)
- if self.arr and n > 0:
- if 2 * index + 1 < n: # 向左子树递归
- self.infix_order(2 * index + 1)
- print(f"arr[{index}]={self.arr[index]}", end=" ")
- if 2 * index + 2 < n: # 向右子树递归
- self.infix_order(2 * index + 2)
- else:
- print("数组为空")
-
- def post_order(self, index: int):
- """
- 以后序遍历方式访问数组元素
- :param index: 数组下标
- :return:
- """
- n = len(self.arr)
- if self.arr and n > 0:
- if 2 * index + 1 < n: # 向左子树递归
- self.post_order(2 * index + 1)
- if 2 * index + 2 < n: # 向右子树递归
- self.post_order(2 * index + 2)
- print(f"arr[{index}]={self.arr[index]}", end=" ")
-
-
- arr_binary_tree = ArrayBinaryTree([1, 2, 3, 4, 5, 6, 7])
- print("前序遍历:")
- arr_binary_tree.pre_order(0)
- print()
- print("中序遍历:")
- arr_binary_tree.infix_order(0)
- print()
- print("后序遍历:")
- arr_binary_tree.post_order(0)
- print()
- """ 线索化二叉树 """
- # 创建 Node 节点
- class Node:
- no: int = None
- left = None
- right = None
- # left_type/right_type 表示指针类型
- # 值为0时表示指向的是左子树/右子树,为1时表示指向的是前驱节点/后继节点
- left_type: int = 0
- right_type: int = 0
-
- def __init__(self, no: int):
- self.no = no
- self.left = None
- self.right = None
-
- def __str__(self):
- return f"no={self.no}"
-
-
- # 建立线索化 Node 二叉树
- class ThreadedBinaryTree:
- root: Node = None
- # 为了实现线索化,需要一个指针(变量)指向当前节点的前驱节点
- # 如中序线索化中,需要一个指针(变量)指向当前节点在中序遍历结果中的前驱节点
- # 在递归进行线索化时, pre 总指向当前节点按某种遍历方式结果的前驱节点
- pre: Node = None
-
- # 建立中序线索化二叉树
- def threaded_infix_tree(self, node: Node):
- """
- 建立中序线索化二叉树
- :param node: 要线索化的节点
- :return:
- """
- if node is None: # 节点为空,不需要线索化
- return
- # 先线索化左子树
- self.threaded_infix_tree(node.left)
- # 线索化当前节点
- # 结合图形理解代码,第一个要线索化的节点是8
- # 先处理当前节点的左子节点
- if node.left is None: # 如果当前节点的左指针为空,则让左指针指向当前节点的前驱节点pre
- node.left = self.pre
- node.left_type = 1 # 设置指针类型为1,表示该指针指向的是前驱节点
- # 处理后继节点
- if self.pre and self.pre.right is None:
- self.pre.right = node
- self.pre.right_type = 1 # 设置指针类型为1,表示该指针指向的是后继节点
- # 每处理一个节点后,让当前节点成为下一个节点的前驱节点
- self.pre = node
- # 后线索化右子树
- self.threaded_infix_tree(node.right)
-
- # 遍历中序线索化二叉树
- def for_in_tree(self):
- node = self.root
- while node:
- # 循环找到 left_type = 1 的节点,该节点就是中序遍历的第一个节点,即图中的节点8
- while node.left_type == 0:
- node = node.left
- # 输出当前节点
- print(node, end=" ")
- # 如果当前节点的右指针指向的是后继节点,则一直输出
- while node.right_type == 1:
- node = node.right
- print(node, end=" ")
- # 替换要遍历的节点,具体过程通过debug和结合图来看会更容易理解
- node = node.right
-
-
- def test_binary_tree():
- # 手动创建二叉树
- binary_tree = BinaryTree()
- root = Node(1)
- node2 = Node(3)
- node3 = Node(6)
- node4 = Node(8)
- node5 = Node(10)
- node6 = Node(14)
-
- root.left = node2
- root.right = node3
- node2.left = node4
- node2.right = node5
- node3.left = node6
-
- threaded_binary_tree = ThreadedBinaryTree()
- threaded_binary_tree.root = root
- # 测试线索化
- print(f"线索化前:10的left={node5.left},right={node5.right}")
- threaded_binary_tree.threaded_infix_tree(root)
- # 以10号节点,即node5测试
- print(f"线索化后:10的前驱节点={node5.left},后继节点={node5.right}")
-
- # 测试遍历线索化二叉树
- threaded_binary_tree.for_in_tree()
-
-
- test_binary_tree()
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。