基于Python的数据结构实验——二叉树的构建与遍历(先序、中序、后序、层次遍历,修改、添加节点)(附详细代码和注释)

创建名为 prac07.py 的文件,在文件中定义两个类,一个是二叉树的结点类,该类 包含结点的相关信息(如结点的值和左、右子树);另一个是二叉树的类,该类包含二叉树的定 义及其基本操作。请按以下步骤测试二叉树的基本操作的实现是否正确。

  1. 初始化一个节点。

  1. 以1中节点作为根节点并使用链式存储结构,递归创建一棵如下所示的二叉树。

  1. 对二叉树执行先序遍历,并将先序序列输出 。

  1. 对二叉树执行中序遍历,并将中序序列输出 。

  1. 对二叉树执行后序遍历,并将后序序列输出。

  1. 对二叉树执行层次遍历,并将所得序列输出 。

  1. 获取值为 F 的结点,并将其值修改为 Z。

  1. 为值为 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()
    
  • 8
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

山河之书Liu_Zixin

不要打赏

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值