当前位置:   article > 正文

Python数据结构与算法-树_python 树

python 树

一、树的概念

详情见 https://blog.csdn.net/little_limin/article/details/129845592

Python数据结构与算法-堆排序(NB组)—— 一、树的基础知识

二、树的实例:模拟文件系统

1、树的存储

树结构也是链式存储的,与链表的结构相似,只是树存在多个子节点,不是线性的,存在一堆多的情况。与双链表相似,只不过链表节点对应的下一个节点只有一个,树节点对应的孩子节点很多,需要用列表[]存储。

(1)树节点代码实现

  1. # 树节点的类
  2. class Node(): # 创建文件节点的类,及其属性(父节点,孩子节点)
  3. def __init__(self, name, type = "dir"): # 节点初始属性,文件名,文件类型
  4. self.name = name # 文件名
  5. self.type = type # 文件类型
  6. # 文件相互间关系
  7. self.children = [] # 孩子节点,孩子节点可以有很多,所以是列表
  8. self.parent = None # 父节点,父节点只有一个的,不一定需要有这个指向
  9. # print测试
  10. n = Node("hello") #父节点
  11. n2 = Node("world") #孩子节点1
  12. n3 = Node("yoyo") # 孩子节点2
  13. # 孩子节点与父节点关联
  14. n.children.append(n2)
  15. n.children.append(n3)
  16. n2.parent = n
  17. n3.parent = n
  18. # 打印孩子节点的属性
  19. for nm in n.children:
  20. print(nm.name)

(2)输出结果

  1. world
  2. yoyo

2、模拟文件系统

(1)代码实现

  1. # 树的实例:模拟文件系统
  2. # 树是链式存储
  3. class Node(): # 创建文件节点的类,及其属性(父节点,孩子节点)
  4. def __init__(self, name, type = "dir"): # 节点初始属性,文件名,文件类型
  5. self.name = name # 文件名
  6. self.type = type # 文件类型
  7. # 文件相互间关系
  8. self.children = [] # 孩子节点,孩子节点可以有很多,所以是列表
  9. self.parent = None # 父节点,父节点只有一个的,不一定需要有这个指向
  10. def __repr__(self): # 内置函数,返回值
  11. return self.name # 返回名字
  12. class FileSystemTree(): # 创建文件根目录——数据结构(树)
  13. def __init__(self) -> None: # 树的属性
  14. self.root = Node("/") # 树的根节点,类似于链表的head结点
  15. self.now = self.root # now指针,当前目录
  16. def mkdir(self,name): # 当前目录创建文件
  17. # 保证name以/结尾
  18. if name[-1] != "/": # name这个字符串的最后一位不是斜杠
  19. name += "/" # 在name的最后加上斜杠
  20. new_dir = Node(name) # 创建文件节点
  21. # 创建与当前文件夹的连接
  22. self.now.children.append(new_dir)
  23. new_dir.parent = self.now
  24. def ls(self): # 展现当前目录下的所有子目录
  25. return self.now.children # 返回子目录列表
  26. def cd(self,name): # 切换目录(到子目录),支持向上返回
  27. # 判断是否为文件夹
  28. if name[-1] != "/":
  29. name += "/"
  30. if name == "../": #当前目录
  31. self.now = self.now.parent # 返回目录到上级
  32. return
  33. # 找到和name相同的文件
  34. for child in self.now.children:
  35. if child.name == name:
  36. self.now = child # 切换目录到child
  37. return # 输出
  38. # 子目录中无该文件夹,报错
  39. raise ValueError("invaild dir")
  40. tree = FileSystemTree() # 创建树
  41. # 新建文件夹
  42. tree.mkdir("Var/")
  43. tree.mkdir("bin/")
  44. tree.mkdir("usr/")
  45. print(tree.ls()) # 展示当前子目录
  46. # 切换到子目录
  47. tree.cd("bin/")
  48. tree.mkdir("python/") # 子目录中创建文件夹
  49. print(tree.ls()) # 展示当前子目录
  50. # 切换回上级目录
  51. tree.cd("../")
  52. print(tree.ls()) # 展示当前子目录

(2)代码结果

  1. [Var/, bin/, usr/]
  2. [python/]
  3. [Var/, bin/, usr/]

3、模拟文件代码相关知识点

(1)__repr__ 和__str__ 内置函数的用法和示例

1)__repr__的作用

输出实例对象时,其内容由__repr__的返回值决定。

  1. class Test:
  2. def __repr__(self) -> str:
  3. return "hello"
  4. t = Test()
  5. print(t)

输出结果

hello

可以看到,当打印实例对象的时候,打印的结果就是__repr__的返回值。如果不加定义__repr__则会默认使用object__repr__函数,返回如下:

<__main__.Test object at 0x0000023573CF0700>

2)__str__作用

与__repe__作用相同,只不过__str__要更猛一点,当你的类中同时重写了__str____repr__后,那么当你打印实例对象的时候,python底层会优先执行实例对象.__str__()。

  1. class Test:
  2. def __repr__(self) -> str:
  3. return "repr"
  4. def __str__(self) -> str:
  5. return "str"
  6. t = Test()
  7. print(t)

输出结果

str

通过上面这个例子可以看到,输出的是__str__的返回值(__repr__没抢过__str__)。

(2)__str__和__repr__区别

在代码编辑器中执行print()函数,python优先调用print(实例对象.__str__());而当在运行终端直接敲实例对象的时候,python底层执行的其实是实例对象.__repr__()。

示例1:在终端直接打印

  1. >>> from text import Test
  2. >>> t = Test()
  3. >>> t
  4. repr
  5. >>> print(t)
  6. str

示例2:在编辑器print()

  1. class Test:
  2. def __repr__(self) -> str:
  3. return "repr"
  4. def __str__(self) -> str:
  5. return "str"
  6. t = Test()
  7. print(t)

输出结果:

str

(3)文件的相对路径和绝对路径

相对路径从当前目录到文件所在位置;

绝对路径从根目录开始到文件所在地。

(4)python的"./"、"../"和"/"路径

  • ./代表目前文件所在的目录。

  • . ./代表目前文件的上一层目录。

  • /代表根目录。

三、二叉树

1、概念

详情见 https://blog.csdn.net/little_limin/article/details/129845592

Python数据结构与算法-堆排序(NB组)—— 二、二叉树的基础知识

2、二叉树的存储

(1)二叉树的链式存储

将二叉树的节点定义为一个对象,节点之间通过类似链表的链接方式来连接。

(2)节点存储代码

  1. class BiTreeNode: # 二叉树
  2.     def __init__(self,data): # data:节点数据
  3.         self.data = data
  4.         self.lchild = None # 左孩子
  5.         self.rchild = None # 右孩子

3、二叉树代码实现

  1. # 二叉树的简单实现
  2. class BiTreeNode(): # 二叉树节点
  3. def __init__(self,data) -> None:
  4. self.data = data
  5. self.lchild = None
  6. self.rchild = None
  7. # 定位节点
  8. a = BiTreeNode("A")
  9. b = BiTreeNode("B")
  10. c = BiTreeNode("C")
  11. d = BiTreeNode("D")
  12. e = BiTreeNode("E")
  13. f = BiTreeNode("F")
  14. g = BiTreeNode("G")
  15. # 节点关系链接
  16. e.lchild = a
  17. e.rchild = g
  18. a.rchild = c
  19. c.lchild = b
  20. c.rchild = d
  21. g.rchild = f
  22. # 根节点
  23. root = e
  24. print(root.lchild.rchild.data)

结果输出

C

4、二叉树的遍历

以上图举例,树的遍历如何实现。

(1)二叉树遍历方式

  • 前序遍历:EACBDGF 从根节点开始,先左孩子再右孩子。

  • 中序遍历:ABCDEFG

  • 后序遍历:BDCAFGE

  • 层次遍历:EAGCFBD

(2)前序遍历代码实现

在二叉树代码实现的基础代码上,增加以下代码,以下代码为前序遍历主代码。

  1. # 根节点
  2. root = e
  3. # 前序遍历
  4. def pre_order(root):
  5. if root: # root不为空
  6. print(root.data, end = ',')
  7. pre_order(root.lchild) # 访问左孩子
  8. pre_order(root.rchild) # 访问右孩子
  9. pre_order(e) # 从e开始前序遍历

输出结果

E,A,C,B,D,G,F,

(3)中序遍历代码实现

中序遍历可以理解为将树结构“拍扁”,与前序遍历的区别仅在print打印的位置不同。

  1. # 中序遍历
  2. def in_order(root):
  3. if root: # root不为空,递归结束条件
  4. in_order(root.lchild) # 访问左孩子
  5. print(root.data, end = ',') # 打印本身
  6. in_order(root.rchild) # 访问右孩子
  7. in_order(root) # 从e开始前序遍历

输出结果

A,B,C,D,E,G,F,

递归原理

s1.首先,运行E的左孩子所在的子树,打印E,再运行E的右孩子所在的子树。

s2.进入E的左孩子的子树,A没有左孩子,打印A,运行A的右孩子。

s3.进入A的右孩子的子树,先运行C的左孩子,打印C,运行C的右孩子。

s4.进入C的左孩子的子树,打印了B;进入C的右孩子的子树,打印了D。

s5,进入E的右孩子的子树,依旧同以上步骤,得到G和F。

(4)后序遍历

  1. # 后序遍历
  2. def post_order(root):
  3. if root: # root不为空,递归结束条件
  4. post_order(root.lchild) # 访问左孩子
  5. post_order(root.rchild) # 访问右孩子
  6. print(root.data, end = ',') # 打印本身
  7. post_order(root) # 从e开始前序遍历

输出结果

B,D,C,A,F,G,E,

递归原理

运行的顺序从左往右,与中序遍历的原理类似。先运行左孩子所在子树,再运行右孩子所在子树,最后才打印本身。

(5)层次遍历

  1. # 层次遍历——广度优先搜索
  2. from collections import deque # 队列模块
  3. def level_order(root):
  4. queue = deque() # 新建队列
  5. queue.append(root) # 根节点入队
  6. while len(queue) > 0: # 队列不空
  7. node = queue.popleft() # 节点出队
  8. print(node.data, end = ',') # 得到节点的值
  9. if node.lchild: # 节点的左孩子存在
  10. queue.append(node.lchild) # 左孩子进入队列
  11. if node.rchild: # 节点的右孩子存在
  12. queue.append(node.rchild) # 右孩子入队
  13. level_order(root)

输出结果

E,A,G,C,F,B,D,

代码实现原理

使用单向队列的性质,节点出队时,其对应的孩子节点入队。例如(以本节遍历二叉树为例):

  • [E]:根节点入队

  • E,[A,G]:E出队,对应的左孩子A和右孩子入队

  • E,A,[G,C]:A出队,A的右孩子C入队

  • E,A,G,[C,F]:G出队,G的右孩子F入队

  • E,A,G,C,[F,B,D]:C出队,C的左孩子B,右孩子D出队

  • E,A,G,C,F,[B,D]:F出队,F没有孩子节点

  • E,A,G,C,F,B,[D]:B出队,B没有孩子节点

  • E,A,G,C,F,B,D,[]:D出队,D没有孩子节点,队列为空,结束循环。

三、二叉搜索树

1、概念

二叉搜索树是一棵二叉树且满足性质:设x是二叉树的一个节点。如果y是x左子树的一个节点,那么y.key x.key;如果y是x右子树的一个节点,那么y.key x.key。

如下图为一棵二叉搜索树:

二叉搜索树的操作:查询、插入、删除

查询和插入的时间复杂度都为O(logn),删除操作较为复杂后面会具体分析。

2、二叉搜索树:插入

(1)递归实现插入

当插入值小于当前节点的值,当前节点的左孩子(左孩子子树)是插入值的节点;当插入值大于当前节点的值,当前节点的右孩子(右孩子子树)是插入值的节点;若该值插入的位置不存在节点或该值与当前节点值相同,则创建新的节点或覆盖该节点。

  1. # 二叉搜索树的用递归写插入函数
  2. class BiTreeNode(): # 二叉树节点
  3. def __init__(self, data) -> None: # 属性
  4. self.data = data # 树的值
  5. self.lchild = None # 左孩子
  6. self.rchild = None # 右孩子
  7. self.parent = None # 父节点
  8. # 二叉搜索树 binary search tree
  9. class BST():
  10. def __init__(self): # 创建空树
  11. self.root = None # 根节点为空
  12. # 递归插入
  13. def insert(self, node, val): # node是指二叉树中当前指向的节点,初始一般为根节点,val是指插入的值
  14. if not node or node.data == val: # 空树或节点的值与插入的值相同
  15. node = BiTreeNode(val) # 创建一个节点插入到树中(最后一步)或者是插入的值的节点直接与原节点相重合
  16. elif val < node.data: # 插入的值小于当前节点的值
  17. # 往当前节点的左边插,当前节点的也就往左孩子找
  18. node.lchild = self.insert(node.lchild,val) # 左孩子为根节点的子树上,node.lchild(当前点的左孩子) = node(插入的节点)
  19. node.lchild.parent = node # 与父节点的连接
  20. else: # val > node.data
  21. node.rchild = self.insert(node.rchild,val) # 当前节点的右孩子是插入的节点
  22. node.rchild.parent = node
  23. return node # 返回
  24. # 前序遍历
  25. def pre_order(self, root):
  26. if root: # root不为空
  27. print(root.data, end = ',')
  28. self.pre_order(root.lchild) # 访问左孩子
  29. self.pre_order(root.rchild) # 访问右孩子
  30. tree = BST()
  31. node = BiTreeNode(10) # 树的根节点
  32. # 插入数值
  33. tree.insert(node,5)
  34. tree.insert(node,19)
  35. tree.insert(node,8)
  36. tree.insert(node,3)
  37. tree.pre_order(node)

输出结果

10,5,3,8,19,

(2)普通方式实现插入

  1. # 二叉搜索树普通办法写插入函数
  2. class BiTreeNode(): # 二叉树节点
  3. def __init__(self, data) -> None: # 属性
  4. self.data = data # 树的值
  5. self.lchild = None # 左孩子
  6. self.rchild = None # 右孩子
  7. self.parent = None # 父节点
  8. # 二叉搜索树 binary search tree
  9. class BST():
  10. def __init__(self, li=None): # 创建树
  11. self.root = None # 根节点为空
  12. # 创建二叉搜索树
  13. if li:
  14. for val in li:
  15. self.insert_no_dec(val) # 循环插入值
  16. def insert_no_dec(self,val): # 非递归
  17. p = self.root # 创建指针p,p起始指向根节点
  18. if not p: # p指向节点为空,空树,
  19. self.root = BiTreeNode(val) # 创建根节点
  20. return
  21. while True: # 循环
  22. if val < p.data: # 插入值小于p指向节点的值
  23. if p.lchild: # 左孩子节点存在
  24. p = p.lchild # 指针移动至新的节点
  25. else: # 左孩子不存在
  26. p.lchild = BiTreeNode(val) # 插入值
  27. p.lchild.parent = p # 连接父节点
  28. return # 结束循环,返回
  29. elif val > p.data: # 插入值大于p指向节点的值
  30. if p.rchild: # 右孩子存在
  31. p = p.rchild # 指针移动至新节点
  32. else: # 右孩子不存在
  33. p.rchild = BiTreeNode(val) # 插入值
  34. p.rchild.parent = p # 连接父节点
  35. return # 结束循环,返回
  36. else: # val == p.data
  37. return # 不用插入
  38. # 前序遍历
  39. def pre_order(self,root):
  40. if root: # root不为空
  41. print(root.data, end = ',')
  42. self.pre_order(root.lchild) # 访问左孩子
  43. self.pre_order(root.rchild) # 访问右孩子
  44. # 中序遍历
  45. def in_order(self, root):
  46. if root: # root不为空,递归结束条件
  47. self.in_order(root.lchild) # 访问左孩子
  48. print(root.data, end = ',') # 打印本身
  49. self.in_order(root.rchild) # 访问右孩子
  50. # 后序遍历
  51. def post_order(self, root):
  52. if root: # root不为空,递归结束条件
  53. self.post_order(root.lchild) # 访问左孩子
  54. self.post_order(root.rchild) # 访问右孩子
  55. print(root.data, end = ',') # 打印本身
  56. tree = BST([4,6,7,9,2,1,3,5,8]) # 对象实例化
  57. # 遍历二叉树
  58. tree.pre_order(tree.root)
  59. print("")
  60. tree.in_order(tree.root)
  61. print("")
  62. tree.post_order(tree.root)

输出结果:

  1. 4,2,1,3,6,5,7,9,8,
  2. 1,2,3,4,5,6,7,8,9,
  3. 1,3,2,5,8,9,7,6,4,

说明:中序遍历的二叉搜索树一定是升序输出

3、二叉搜索树:查询

查询函数的原理与插入函数的原理基本一致。

  1. import random
  2. class BiTreeNode(): # 二叉树节点
  3. def __init__(self, data) -> None: # 属性
  4. self.data = data # 树的值
  5. self.lchild = None # 左孩子
  6. self.rchild = None # 右孩子
  7. self.parent = None # 父节点
  8. # 二叉搜索树 binary search tree
  9. class BST():
  10. def __init__(self, li=None): # 创建树
  11. self.root = None # 根节点为空
  12. # 创建二叉搜索树
  13. if li:
  14. for val in li:
  15. self.insert_no_dec(val) # 循环插入值
  16. def insert_no_dec(self,val): # 非递归插入
  17. p = self.root # 创建指针p,p起始指向根节点
  18. if not p: # p指向节点为空,空树,
  19. self.root = BiTreeNode(val) # 创建根节点
  20. return
  21. while True: # 循环
  22. if val < p.data: # 插入值小于p指向节点的值
  23. if p.lchild: # 左孩子节点存在
  24. p = p.lchild # 指针移动至新的节点
  25. else: # 左孩子不存在
  26. p.lchild = BiTreeNode(val) # 插入值
  27. p.lchild.parent = p # 连接父节点
  28. return # 结束循环,返回
  29. elif val > p.data: # 插入值大于p指向节点的值
  30. if p.rchild: # 右孩子存在
  31. p = p.rchild # 指针移动至新节点
  32. else: # 右孩子不存在
  33. p.rchild = BiTreeNode(val) # 插入值
  34. p.rchild.parent = p # 连接父节点
  35. return # 结束循环,返回
  36. else: # val == p.data
  37. return # 不用插入
  38. def query(self, node, val): # 递归写查询
  39. if not node: # 节点不存在
  40. return None # 返回none
  41. elif val > node.data: # 值大于当前节点的值,往右子树找
  42. node = self.query(node.rchild, val) # 变量node是返回的node的赋值
  43. elif val < node.data: # 值小于当前节点的值,往左子树找
  44. node = self.query(node.lchild, val)
  45. else: # val == node.data
  46. node = node # 值相等时返回节点
  47. return node
  48. def query_no_rec(self, val): # 非递归查询
  49. p = self.root # p指针初始指向根节点
  50. while p: # 不是空树
  51. if val < p.data: # 值小于当前节点,往左找
  52. p = p.lchild # p指针下移
  53. elif val > p.data: # 值大于当前节点,往右找
  54. p = p.rchild # p指针往右下移
  55. else: # val == p.data
  56. return p # 退出循环
  57. return None
  58. li = list(range(0,10,2)) # 0-9的偶数
  59. random.shuffle(li)
  60. tree = BST(li) # 创建树
  61. node = tree.root
  62. # print(node.data)
  63. print(tree.query(node, 5)) # 递归
  64. print(tree.query_no_rec(4)) # 非递归

输出结果

  1. None
  2. <__main__.BiTreeNode object at 0x00000170A1C1C6A0>

4、二叉搜索树:删除

(1)删除操作原理

二叉搜索树的删除与双向链表的删除极为相似。

1)要删除的节点是叶子节点:直接删除。node.parent.lchild 或者 node.parent,rchild = None

2)要删除的节点只有一个孩子:将此节点的父亲与孩子连接,然后删除该节点。如果删除的节点是根节点,则需要调整子树节点的位置。

3)要删除的节点有两个孩子:将其右子树的值最小的节点(该节点最多有一个右孩子,也可能就是叶子节点),该点一定为右子树的各节点的最后一个左孩子,找到该节点并替换当前节点的值,再删除该接节点

(2)删除操作代码实现

  1. # 二叉搜索树——删除
  2. class BiTreeNode(): # 二叉树节点
  3. def __init__(self, data) -> None: # 属性
  4. self.data = data # 树的值
  5. self.lchild = None # 左孩子
  6. self.rchild = None # 右孩子
  7. self.parent = None # 父节点
  8. # 二叉搜索树 binary search tree
  9. class BST():
  10. def __init__(self, li=None): # 创建树
  11. self.root = None # 根节点为空
  12. # 创建二叉搜索树
  13. if li:
  14. for val in li:
  15. self.insert_no_dec(val) # 循环插入值
  16. def insert_no_dec(self,val): # 非递归插入
  17. p = self.root # 创建指针p,p起始指向根节点
  18. if not p: # p指向节点为空,空树,
  19. self.root = BiTreeNode(val) # 创建根节点
  20. return
  21. while True: # 循环
  22. if val < p.data: # 插入值小于p指向节点的值
  23. if p.lchild: # 左孩子节点存在
  24. p = p.lchild # 指针移动至新的节点
  25. else: # 左孩子不存在
  26. p.lchild = BiTreeNode(val) # 插入值
  27. p.lchild.parent = p # 连接父节点
  28. return # 结束循环,返回
  29. elif val > p.data: # 插入值大于p指向节点的值
  30. if p.rchild: # 右孩子存在
  31. p = p.rchild # 指针移动至新节点
  32. else: # 右孩子不存在
  33. p.rchild = BiTreeNode(val) # 插入值
  34. p.rchild.parent = p # 连接父节点
  35. return # 结束循环,返回
  36. else: # val == p.data
  37. return # 不用插入
  38. def query(self, node, val): # 递归写查询
  39. if not node: # 节点不存在
  40. return None # 返回none
  41. elif val > node.data: # 值大于当前节点的值,往右子树找
  42. node = self.query(node.rchild, val) # 变量node是返回的node的赋值
  43. elif val < node.data: # 值小于当前节点的值,往左子树找
  44. node = self.query(node.lchild, val)
  45. else: # val == node.data
  46. node = node # 值相等时返回节点
  47. return node
  48. def query_no_rec(self, val): # 非递归查询
  49. p = self.root # p指针初始指向根节点
  50. while p: # 不是空树
  51. if val < p.data: # 值小于当前节点,往左找
  52. p = p.lchild # p指针下移
  53. elif val > p.data: # 值大于当前节点,往右找
  54. p = p.rchild # p指针往右下移
  55. else: # val == p.data
  56. return p # 退出循环
  57. return None
  58. # 中序遍历
  59. def in_order(self,root):
  60. if root: # root不为空,递归结束条件
  61. self.in_order(root.lchild) # 访问左孩子
  62. print(root.data, end = ',') # 打印本身
  63. self.in_order(root.rchild) # 访问右孩子
  64. def __remove_node_1(self, node): # 情况1:叶子节点
  65. # 判断是否为根节点
  66. if not node.parent:
  67. self.root = None # 根节点为None,即删除根节点
  68. if node == node.parent.lchild: # node为左孩子
  69. node.parent.lchild = None
  70. else: # node为右孩子
  71. node.parent.rchild = None
  72. def __remove_node_21(self,node): # 情况2.1:只有一个左孩子
  73. if not node.parent: # 根节点
  74. self.root = node.lchild # 根节点为node的左孩子
  75. node.lchild.parent = None # 左孩子的父亲为空
  76. elif node == node.parent.lchild: # node是父亲的左孩子
  77. node.parent.lchild = node.lchild # node父亲的左孩子变为node的左孩子
  78. node.lchild.parent = node.parent # node左孩子的父亲变为node的父亲
  79. else: # node是父亲的右孩子
  80. node.parent.rchild = node.lchild # node父亲的右孩子变为node的左孩子
  81. node.lchild.parent = node.parent # node左孩子的父亲变为node的父亲
  82. def __remove_node_22(self,node): # 情况2.2:只有一个右孩子
  83. if not node.parent: # 根节点
  84. self.root = node.rchild # 根节点为node的右孩子
  85. node.rchild.parent = None # 根节点没有父节点
  86. elif node == node.parent.lchild: # node是父亲的左孩子
  87. node.parent.lchild = node.rchild # node父亲的左孩子变为node的右孩子
  88. node.rchild.parent = node.parent # node右孩子的父亲变为node的父亲
  89. else: # node为父亲的右孩子
  90. node.parent.rchild = node.rchild # node父亲的右孩子变为node的右孩子
  91. node.rchild.parent = node.parent # node右孩子的父亲变为node的父亲
  92. def delete(self,val): # 删除操作(合并)
  93. if self.root: # 不是空树
  94. node = self.query_no_rec(val) # 找到该节点 这步错了
  95. if not node: # node不存在
  96. return False
  97. if not node.lchild and not node.rchild: # 叶子节点
  98. self.__remove_node_1(node) # 情况1
  99. elif not node.rchild: # node只有左孩子
  100. self.__remove_node_21(node) # 情况2.1
  101. elif not node.lchild: # node只有右孩子
  102. self.__remove_node_22(node) # 情况2.2
  103. else: # 情况3 即有左孩子又有右孩子
  104. # 找min_node,右子树的最小节点
  105. min_node = node.rchild # min_node在右子树上
  106. while min_node.lchild: # 直到没有左孩子
  107. min_node = min_node.lchild # min_node一直往左孩子移动,寻找
  108. node.data = min_node.data # 互换两者的值
  109. # 删除min_node
  110. if min_node.rchild: # 只有右孩子
  111. self.__remove_node_22(min_node)
  112. else: # min_node为叶子节点
  113. self.__remove_node_1(min_node)
  114. tree = BST([1,4,2,5,3,8,6,9,7])
  115. tree.in_order(tree.root)
  116. print("")
  117. # 删除值
  118. tree.delete(4)
  119. tree.delete(8)
  120. tree.in_order(tree.root)

结果输出

  1. 1,2,3,4,5,6,7,8,9,
  2. 1,2,3,5,6,7,9,

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Monodyee/article/detail/169511
推荐阅读
相关标签
  

闽ICP备14008679号