创建名为 prac07.py 的文件,在文件中定义两个类,一个是二叉树的结点类,该类 包含结点的相关信息(如结点的值和左、右子树);另一个是二叉树的类,该类包含二叉树的定 义及其基本操作。请按以下步骤测试二叉树的基本操作的实现是否正确。
初始化一个节点。
以1中节点作为根节点并使用链式存储结构,递归创建一棵如下所示的二叉树。
对二叉树执行先序遍历,并将先序序列输出 。
对二叉树执行中序遍历,并将中序序列输出 。
对二叉树执行后序遍历,并将后序序列输出。
对二叉树执行层次遍历,并将所得序列输出 。
获取值为 F 的结点,并将其值修改为 Z。
为值为 G 的结点添加右孩子,令其值为 K。
(注:我使用的二叉树写入的方法是,一层一层写,有两个规矩,一是确保每一个节点的孩子都必须是写入了数据的节点或#节点,二是确保最后一个#之前不能存在空节点,即对于上述二叉树,其应该表示为ABCDEFGH##IJ#############,分层后是A|BC|DEFG|H##IJ###|##########)
class BinaryTreeNode(object): # 定义二叉树的节点类
def __init__(self, element):
self.element = element
self.left_child = None # 左孩子
self.right_child = None # 右孩子
class LinkedListNode(object): # 定义链表的节点类
def __init__(self, data): # 设置节点
self.data = data # 节点中的数据
self.next = None # 节点存储的下一个的信息
class LinkedList(object): # 定义链表类
def __init__(self):
self.head = LinkedListNode(None) # 头结点
def EmptyJudgement(self): # 空链表判断函数
if self.Length() == 0: # 检查链表长度,如果为0
return False # 返回False
else:
return True # 不然返回True
def Append(self, data): # 写入数据(追加数据)函数
node = LinkedListNode(data) # 新建数据节点
if not self.EmptyJudgement(): # 判断链表是否为空
self.head.next = node # 为空则将头结点的下一个赋为数据节点
else: # 如果不是
cnode = self.head # 赋为头结点,作为游标使用
while cnode.next != None: # 如果还没到空节点就循环
cnode = cnode.next # 不断向后移动游标
cnode.next = node # 退出循环后就将下一个直接将数据节点赋值过去
def Length(self): # 链表长度判断函数
cnode = self.head # 赋为头结点,作为类似使用
counter = 0 # 长度计数器
while cnode.next != None: # 如果还没到空节点就循环
cnode = cnode.next # 不断向后移动游标
counter = counter + 1 # 计数器计数
return counter # 返回计数结果,即链表元素数量,链表元素
def Pop(self): # 删除头部元素并返回值的函数
cnode = self.head # 赋为头结点(头结点是空的)
cnode = cnode.next # 移到第一个有实际意义的节点
pnode = self.head # 赋为头结点
pnode.next = cnode.next # 将头结点指向下一个节点所指向的对象
return cnode.data # 返回删除的值
class BinaryTree():
def __init__(self):
self.root = None # 设置根节点为None(但是这个不会一直为None,这个会在后面被替换掉)
def Add(self, element):
node = BinaryTreeNode(element) # 新建节点
if self.root == None: # 如果头结点是空节点,则将新节点赋上去
self.root = node
else: # 如果不是,开启层次遍历
linked_list = LinkedList() # 新建用于存储便利信息的链表
linked_list.Append(self.root) # 把头结点写入
while linked_list.EmptyJudgement(): # 判断链表是否为空
cursor = linked_list.Pop() # 取出链表首部元素(其实就是个队列,整个操作都是队列的操作)
if cursor.element != "#": # 这个是判定边界的(也就是每个实际的节点边缘不能为None,可以使#或其他节点)
if cursor.left_child == None: # 左孩子为空就优先填入左孩子
cursor.left_child = node
return
else:
linked_list.Append(cursor.left_child) # 将之前的左孩子添加入列表,一会处理完右孩子之后再去看左孩子的下一层
if cursor.right_child == None: # 为空填入右孩子
cursor.right_child = node
return
else:
linked_list.Append(cursor.right_child) # 把右孩子也填入,等处理完左孩子的下一层之后在处理右孩子的下一层
else:
continue
def PreorderTraversal(self, node): # 先序遍历函数
if self.root != None:
if node.element != "#":
print(node.element, end=" ")
self.PreorderTraversal(node.left_child) # 递归,从根节点开始
self.PreorderTraversal(node.right_child)
else:
print("请先创建一个二叉树")
def InorderTraversal(self, node): # 中序遍历函数
if self.root != None:
if node.element != "#":
self.InorderTraversal(node.left_child) # 递归,从左子树最末端开始
print(node.element, end=" ")
self.InorderTraversal(node.right_child)
else:
print("请先创建一个二叉树")
def PostorderTraversal(self, node): # 后序遍历
if self.root != None:
if node.element != "#":
self.PostorderTraversal(node.left_child) # 递归,最后遍历节点
self.PostorderTraversal(node.right_child)
print(node.element, end=" ")
else:
print("请先创建一个二叉树")
def LevelTraversal(self): # 层次遍历,和之前写入数有点像,但不完全一样
if self.root != None:
linked_list = LinkedList()
linked_list.Append(self.root)
while linked_list.EmptyJudgement():
cursor = linked_list.Pop()
if cursor.element != "#":
print(cursor.element, end=" ") # 打印出目前正在经过的节点
if cursor.left_child.element != "#": # 检查其左孩子,如果是有效节点的话就加入遍历的队列
linked_list.Append(cursor.left_child)
if cursor.right_child.element != "#": # 检查其右孩子,如果是有效节点的话就加入遍历的队列
linked_list.Append(cursor.right_child)
else:
return
else:
print("请先创建一个二叉树")
def Change(self, element, new_element): # 这个的思路就是通过层次遍历,找到目标节点,然后修改其element属性,不再详述
if self.root != None:
linked_list = LinkedList()
linked_list.Append(self.root)
while linked_list.EmptyJudgement():
cursor = linked_list.Pop()
if cursor.element != "#":
if cursor.element == element:
cursor.element = new_element
print("修改成功")
return element # 返回特定值以便于后续鉴别要替换的节点是否存在
if cursor.left_child.element != "#":
linked_list.Append(cursor.left_child)
if cursor.right_child.element != "#":
linked_list.Append(cursor.right_child)
else:
print("请先创建一个二叉树")
return element
def Append(self, element, direction, new_element): # 这个的思路就是通过层次遍历,找到目标节点,然后根据其左右子树的情况写入值,不再详述
node = BinaryTreeNode("#") # 后续包裹有效节点用的
if self.root != None:
linked_list = LinkedList()
linked_list.Append(self.root)
while linked_list.EmptyJudgement():
cursor = linked_list.Pop()
if cursor.element != "#":
if cursor.element == element:
if direction == "left" and cursor.left_child.element == "#": # 必须同时满足两个条件才可以
cursor.left_child.element = new_element
flag = cursor.left_child
flag.left_child = node
flag.right_child = node # 用新的“#”包裹新建的节点,以保证遍历的时候不会出BUG
print("写入成功")
elif direction == "right" and cursor.right_child.element == "#":
cursor.right_child.element = new_element
flag = cursor.right_child
flag.left_child = node
flag.right_child = node
print("写入成功")
elif direction != "left" or direction != "right":
print("指令错误,请输入left或right以确定方向")
else:
print("该位置已有元素")
return element # 同样是为了鉴别要查找的节点是否存在
if cursor.left_child.element != "#":
linked_list.Append(cursor.left_child)
if cursor.right_child.element != "#":
linked_list.Append(cursor.right_child)
else:
print("请先创建一个二叉树")
return element
def Choice(self):
self.__init__()
while True:
info = input("请选择操作(写入树,先序遍历,中序遍历,后序遍历,层次遍历,修改节点,定点写入)或输入“终止”以结束:")
if info == "写入树":
element = input("输入数据,输入#以占位(需将每一层补齐):")
for i in element: # 循环遍历字符串
self.Add(i)
elif info == "先序遍历":
print("先序遍历的结果是", end=":")
self.PreorderTraversal(self.root)
print()
elif info == "中序遍历":
print("中序遍历的结果是", end=":")
self.InorderTraversal(self.root)
print()
elif info == "后序遍历":
print("后序遍历的结果是", end=":")
self.PostorderTraversal(self.root)
print()
elif info == "层次遍历":
print("层次遍历的结果是", end=":")
self.LevelTraversal()
print()
elif info == "修改节点":
element = input("请输入要修改的节点:")
new_element = input("请输入修改后的节点值:")
flag = self.Change(element, new_element)
if flag != element:
print("该节点不存在")
elif info == "定点写入":
element = input("请输入目标节点:")
direction = input("请输入方向(right 或 left)")
new_element = input("请输入要写入的节点:")
flag = self.Append(element, direction, new_element)
if flag != element:
print("该节点不存在")
elif info == "终止":
print("程序已终止")
break
else:
print("无效指令")
if __name__ == "__main__":
tree = BinaryTree()
tree.Choice()