IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 数据结构与算法 -> <数据结构与算法>-Python二叉搜索树 -> 正文阅读

[数据结构与算法]<数据结构与算法>-Python二叉搜索树

在这里插入图片描述

1 二叉树遍历

二叉树遍历分为四种方式,分别是前序遍历,中序遍历,后序遍历和层序遍历

  • 前序遍历顺序 根->左->右
  • 中序遍历顺序 左->根->右
  • 后序遍历顺序 右->左->根
  • 层序遍历顺序 按层遍历

遍历二叉树最好的方式是使用递归的方式

如上图所示的二叉树,可以使用如下方式:

class Node:
    def __init__(self,data):
        self.data = data 
        self.lchild = None 
        self.rchild = None 
        self.parent = None 


a = Node('A')
b = Node('B')
c = Node('C')
d = Node('D')
e = Node('E')
f = Node('F')
g = Node('G')


e.lchild = a 
e.rchild = g
a.rchild = c 
c.lchild = b 
c.rchild = d
g.rchild = f 


def pre_order(root):
    if root:
        print(root.data,end=',')
        pre_order(root.lchild)
        pre_order(root.rchild)


def in_order(root):
    if root:
        in_order(root.lchild)
        print(root.data,end=',')
        in_order(root.rchild)


def post_order(root):
    if root:
        post_order(root.rchild)
        post_order(root.lchild)
        print(root.data,end=',')


def level_order(root):
    from collections import deque
    q = deque()
    q.append(root)
    while len(q):
        node = q.popleft()
        print(node.data,end=',')
        if node.lchild:
            q.append(node.lchild)
        if node.rchild:
            q.append(node.rchild)

if __name__ == "__main__":
    pre_order(e)
    print("")
    in_order(e)
    print("")
    post_order(e)
    print("")
    level_order(e)

"""
OUT
前序遍历:E,A,C,B,D,G,F,
中序遍历:A,B,C,D,E,G,F,
后序遍历:F,G,D,B,C,A,E,
层序遍历:E,A,G,C,F,B,D,
"""

已知任意两种遍历结果,可以还原一颗树

  • 知道前序和中序遍历结果

前序遍历:E,A,C,B,D,G,F,
中序遍历:A,B,C,D,E,G,F,

step1:前序遍历第一个结点肯定是根节点,得E是根节点
step2:中序遍历E左边的位置ABCD是左子树群,GF是右子树群
step3:前序遍历第二个结点是A,中序遍历第一个结点是A,说明A是E的左子树,G是E的右子树,第二层还原完成
step4:中序遍历第一个结点就是A,说明A没有左子树,C是A的右子树
step5:前序遍历CBD,中序遍历BCD,说明C的左子树是B,右子树是D
step6: F是G的右节点
根据不同遍历执行的顺序是可以还原整颗树的

2 二叉树搜索树

2.1 插入

新建一个结点

class BiTreeNode:
    def __init__(self,data):
        self.data = data 
        self.lchild = None 
        self.rchild = None 
        self.parent = None 

递归方式插入

class BiTree:
    def __init__(self,li=None):
        self.root = None 
        if li:
            for i in li:
                self.insert_no_rec(i)

    def insert(self,node,val):
        if not node: # 如果是一个空树
            node = BiTreeNode(val) # 新建结点,并且返回结点,这是一个递归终止条件
        elif val < node.data: # 如果插入的值小于node的值,那么往node的左子树方向找
            node.lchild = self.insert(node.lchild,val) # 递归
            node.lchild.parent = node  
        elif val > node.data: # 要插入的值大于node的值,那么往node的右子树方向找
            node.rchild = self.insert(node.rchild,val)
            node.rchild.parent = node 
        return node  
        

在这里插入图片描述

非递归方式插入

# class BiTree:
def insert_no_rec(self,val):
        curent = self.root #设置根结点为当前结点
        if not curent: # 如果是一颗空树
            self.root = BiTreeNode(val) # 设置根节点
            return # 退出函数
        while True: # 进入循环
            if val > curent.data: # 如果当前值大于node的值
                if curent.rchild: # 往当前结点的右孩子找
                    curent = curent.rchild 
                else: # 如果结点没有右孩子
                    curent.rchild = BiTreeNode(val) # 将值作为结点的右孩子插入
                    curent.rchild.parent = curent # 设置这个右孩子的结点
                    return  # 退出本函数
            elif val<curent.data: # 往左孩子找
                if curent.lchild:
                    curent = curent.lchild
                else:
                    curent.lchild = BiTreeNode(val)
                    curent.lchild.parent = curent
                    return 
            else: # 如果相等,直接退出,不进行任何操作
                return 

2.2 查询

#class BiTree:
    def select(self,val):
        p = self.root # 设置一个指针初始化为根结点
        if not p: # 空树没有任何值 
            return False #直接返回False 
        while True: 
            if val<p.data: #如果要查找的值小于结点的值
                if p.lchild: 
                    p = p.lchild # p结点往左一直到叶子结点还没找到就没有了,返回None 
                else:
                    return None
            elif val>p.data:
                if p.rchild:
                    p = p.rchild
                else:
                    return None
            else:
                return p

2.3 删除

二叉搜索树的删除时比较复杂的,可以分为三种不同的情况

删除的结点时叶子结点,没有任何子节点,这种情况就直接删除掉
在这里插入图片描述

#class BiTree:
    def __remove_node_1(self,node):# 方式1:叶子结点
        if not node.parent:
            self.root = None 
        if node == node.parent.lchild: # 如果node是左孩子
            node.parent.lchild = None 
            node.parent = None # 这步可以省略
        else: #右孩子
            node.parent.rchild = None 
            node.parent = None 

删除的结点有一个孩子,结点的父结点直接链接这个要删除结点的孩子结点
在这里插入图片描述

#class BiTree:
		def __remove_node_2_1(self,node): # 方式2-1:被删除的结点有一个左孩子
        if node == node.parent.lchild: # 被删除的结点是它父节点的左孩子
            node.parent.lchild = node.lchild
            node.lchild.parent = node.parent 
        else: # 被删除的结点时它父结点的右孩子
            node.parent.rchild = node.lchild 
            node.lchild.parent = node.parent
    

    def __remove_node_2_2(self,node): # 方式2-2:被删除的结点有一个右孩子
        if node == node.parent.lchild: # 被删除的结点是它父节点的左孩子
            node.parent.lchild = node.rchild
            node.rchild.parent = node.parent 
        else: # 被删除的结点时它父结点的右孩子
            node.parent.rchild = node.rchild 
            node.rchild.parent = node.parent

删除的结点是根节点,找到这个根节点右节点的最小子节点,与这个根节点替换掉,然后删除这个子节点
在这里插入图片描述

#class BiTree:
    def delete(self,val):
        node = self.select(val)
        if node:
            if not node.lchild and not node.rchild: # node没有左孩子也没有右孩子
                self.__remove_node_1(node)
            elif not node.rchild:#只有左孩子
                self.__remove_node_2_1(node)
            elif not node.lchild:
                self.__remove_node_2_2(node)
            else:
                min_node = node.rchild # 获取根的右节点作为最下结点
                while min_node.lchild: # 如果跟的右节点有左节点
                    min_node = min_node.lchild # 遍历一直到底
                node.data = min_node.data  # 使用右节点下面最小的子节点替换掉node的值
                self.__remove_node_1(min_node) # 移除掉最小子节点

3 附完整代码

class BiTreeNode:
    def __init__(self,data):
        self.data = data 
        self.lchild = None 
        self.rchild = None 
        self.parent = None 
    
class BiTree:
    def __init__(self,li=None):
        self.root = None 
        if li:
            for i in li:
                self.insert_no_rec(i)

    def insert(self,node,val):
        if not node:
            node = BiTreeNode(val)
        elif val < node.data:
            node.lchild = self.insert(node.lchild,val)
            node.lchild.parent = node 
        elif val > node.data:
            node.rchild = self.insert(node.rchild,val)
            node.rchild.parent = node 
        return node  
        
        

    def insert_no_rec(self,val):
        curent = self.root
        if not curent: # 如果是一颗空树
            self.root = BiTreeNode(val)
            return
        while True:
            if val > curent.data:
                if curent.rchild:
                    curent = curent.rchild
                else:
                    curent.rchild = BiTreeNode(val)
                    curent.rchild.parent = curent
                    return 
            elif val<curent.data:
                if curent.lchild:
                    curent = curent.lchild
                else:
                    curent.lchild = BiTreeNode(val)
                    curent.lchild.parent = curent
                    return 
            else:
                return 
                
    def in_order(self,root):
        if root:
            self.in_order(root.lchild)
            print(root.data,end=',')
            self.in_order(root.rchild)
                

    def pre_order(self,root):
        if root:
            print(root.data,end=',')
            self.pre_order(root.lchild)
            self.pre_order(root.rchild)


    def post_order(self,root):
        if root:
            self.post_order(root.rchild)
            self.post_order(root.rchild)
            print(root.data,end=',')
    

    def level_order(self,root):
        from collections import deque
        q = deque()
        q.append(root)
        while len(q) > 0:
            node = q.popleft()
            print(node.data,end=',')
            if node.lchild:
                q.append(node.lchild)
            if node.rchild:
                q.append(node.rchild)
        

    def select(self,val):
        p = self.root
        if not p: # 空树没有任何值
            return False 
        while True:
            if val<p.data:
                if p.lchild:
                    p = p.lchild
                else:
                    return None
            elif val>p.data:
                if p.rchild:
                    p = p.rchild
                else:
                    return None
            else:
                return p
    

    def __remove_node_1(self,node):# 方式1:叶子结点
        if not node.parent:
            self.root = None 
        if node == node.parent.lchild: # 如果node是左孩子
            node.parent.lchild = None 
            node.parent = None # 这步可以省略
        else: #右孩子
            node.parent.rchild = None 
            node.parent = None 


    def __remove_node_2_1(self,node): # 方式2-1:被删除的结点有一个左孩子
        if node == node.parent.lchild: # 被删除的结点是它父节点的左孩子
            node.parent.lchild = node.lchild
            node.lchild.parent = node.parent 
        else: # 被删除的结点时它父结点的右孩子
            node.parent.rchild = node.lchild 
            node.lchild.parent = node.parent
    

    def __remove_node_2_2(self,node): # 方式2-2:被删除的结点有一个右孩子
        if node == node.parent.lchild: # 被删除的结点是它父节点的左孩子
            node.parent.lchild = node.rchild
            node.rchild.parent = node.parent 
        else: # 被删除的结点时它父结点的右孩子
            node.parent.rchild = node.rchild 
            node.rchild.parent = node.parent



    def delete(self,val):
        node = self.select(val)
        if node:
            if not node.lchild and not node.rchild: # node没有左孩子也没有右孩子
                self.__remove_node_1(node)
            elif not node.rchild:#只有左孩子
                self.__remove_node_2_1(node)
            elif not node.lchild:
                self.__remove_node_2_2(node)
            else:
                min_node = node.rchild # 获取根的右节点作为最下结点
                while min_node.lchild: # 如果跟的右节点有左节点
                    min_node = min_node.lchild # 遍历一直到底
                node.data = min_node.data  # 使用右节点下面最小的子节点替换掉node的值
                self.__remove_node_1(min_node) # 移除掉最小子节点
  数据结构与算法 最新文章
【力扣106】 从中序与后续遍历序列构造二叉
leetcode 322 零钱兑换
哈希的应用:海量数据处理
动态规划|最短Hamilton路径
华为机试_HJ41 称砝码【中等】【menset】【
【C与数据结构】——寒假提高每日练习Day1
基础算法——堆排序
2023王道数据结构线性表--单链表课后习题部
LeetCode 之 反转链表的一部分
【题解】lintcode必刷50题<有效的括号序列
上一篇文章      下一篇文章      查看所有文章
加:2021-08-31 15:42:15  更:2021-08-31 15:43:14 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 0:53:09-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码