平衡二叉树(AVL)

news2025/1/12 1:05:58

平衡二叉树

基本介绍

左旋转调整成平衡二叉树

右旋转调整成平衡二叉树

双旋转调整成平衡二叉树

上述三种旋转方式的代码实现

class Node:
    """
    创建 Node 节点
    """
    value: int = 0
    left = None
    right = None

    def __init__(self, value: int):
        self.value = value

    def height(self):
        """
        返回以当前节点为根节点的树的高度
        """
        # 如果左子树不为空,则遍历左子树,最终获得左子树的高度
        # 如果右子树不为空,则遍历右子树,最终获得右子树的高度
        # 返回左右子树两个高度中的较大的那个值
        # 加1是因为当前节点要算一层高度
        return max(self.left.height() if self.left else 0, self.right.height() if self.right else 0) + 1

    def left_height(self):
        """
        返回左子树的高度
        """
        if self.left:
            return self.left.height()
        return 0

    def right_height(self):
        """
        返回右子树的高度
        """
        if self.right:
            return self.right.height()
        return 0

    def left_rotate(self):
        """
        通过左旋转的方式调整二叉树为平衡二叉树
        """
        # 以当前节点的值创建一个新的节点
        new_node = Node(self.value)
        # 把新节点的左子树设置为当前节点的左子树
        new_node.left = self.left
        # 把新节点的右子树设置为当前节点的右子树的左子树
        new_node.right = self.right.left
        # 把当前节点的值替换为当前节点右子节点的值
        self.value = self.right.value
        # 把当前节点的右子树设置为当前节点右子树的右子树
        self.right = self.right.right
        # 把当前节点的左子树设置为新节点
        self.left = new_node

    def right_rotate(self):
        """
        通过右旋转的方式调整二叉树为平衡二叉树
        """
        # 以当前节点的值创建一个新的节点
        new_node = Node(self.value)
        # 把新节点的右子树设置为当前节点的右子树
        new_node.right = self.right
        # 把新节点的左子树设置为当前节点的左子树的右子树
        new_node.left = self.left.right
        # 把当前节点的值替换为当前节点左子节点的值
        self.value = self.left.value
        # 把当前节点的左子树设置为当前节点左子树的左子树
        self.left = self.left.left
        # 把当前节点的右子树设置为新节点
        self.right = new_node

    def add(self, node):
        """
        添加节点
        node 表示要添加的节点
        """
        if node is None:
            return
        # 判断要添加节点和当前子树根节点的大小
        if node.value < self.value:
            # 要添加节点小于当前子树根节点
            if self.left is None:
                # 如果当前子树左子节点为空,则直接将要添加的节点挂在左子节点上
                self.left = node
            else:
                # 否则,递归当前子树的左节点,找到要放置的位置
                self.left.add(node)
        else:  # 要添加节点大于等于当前子树根节点
            if self.right is None:
                # 如果当前子树右子节点为空,则直接将要添加的节点挂在右子节点上
                self.right = node
            else:
                # 否则,递归当前子树的右节点,找到要放置的位置
                self.right.add(node)

        # 添加完一个节点后,如果 (右子树高度 - 左子树高度) > 1,则进行左旋转
        # 之所以叫左旋转,是因为右子树的高度高于左子树,需要将右子树调整(个人理解)
        if self.right_height() - self.left_height() > 1:
            # 如果当前节点右子树的左子树高度大于当前节点右子树的右子树高度
            # 则进行双旋转操作(先右旋转再左旋转)
            if self.right and self.right.left_height() > self.right.height():
                # 先对当前节点的右节点进行右旋转
                self.right.right_rotate()
                # 然后对当前节点进行左旋转
                self.left_rotate()
            else:  # 否则,直接左旋转
                self.left_rotate()
            # !!!这里必须节return,否则会继续往下判断,有可能会出错
            return

        # 添加完一个节点后,如果 (左子树高度 - 右子树高度) > 1,则进行右旋转
        # 之所以叫右旋转,是因为左子树的高度高于右子树,需要将左子树调整(个人理解)
        if self.left_height() - self.right_height() > 1:
            # 如果当前节点左子树的右子树高度大于当前节点左子树的左子树高度
            # 则进行双旋转操作(先左旋转再右旋转)
            if self.left and self.left.right_height() > self.left.left_height():
                # 先对当前节点的左节点进行左旋转
                self.left.left_rotate()
                # 然后对当前节点进行右旋转
                self.right_rotate()
            else:  # 否则,直接右旋转
                self.right_rotate()

    def infix_order(self):
        """
        中序遍历二叉树
        """
        if self.left:
            self.left.infix_order()
        print(self.value, end=' ')
        if self.right:
            self.right.infix_order()


class AVLTree:
    """
    二叉排序树
    """
    root: Node = None

    def add(self, node: Node):
        """
        添加节点
        node: 要添加的节点
        """
        if self.root is None:
            # 如果根节点为空,直接将新节点当做根节点
            self.root = node
        else:
            # 否则,将新节点放在根节点下
            self.root.add(node)

    def infix_order(self):
        """
        中序遍历
        """
        if self.root:
            self.root.infix_order()
            print()
        else:
            print("二叉排序树为空...")


# 测试左旋转
arr = [4, 3, 6, 5, 7, 8]
avl_tree = AVLTree()
for i in arr:
    node = Node(i)
    avl_tree.add(node)
avl_tree.infix_order()
print("左旋转处理过后:")
print("树的高度:", avl_tree.root.height())
print("树的左子树高度:", avl_tree.root.left.height())
print("树的右子树高度:", avl_tree.root.right.height())
# 测试右旋转
arr = [10, 12, 8, 9, 7, 6]
avl_tree = AVLTree()
for i in arr:
    node = Node(i)
    avl_tree.add(node)
avl_tree.infix_order()
print("右旋转处理过后:")
print("树的高度:", avl_tree.root.height())
print("树的左子树高度:", avl_tree.root.left.height())
print("树的右子树高度:", avl_tree.root.right.height())

# 测试双旋转
arr = [10, 11, 7, 6, 8, 9]
avl_tree = AVLTree()
for i in arr:
    node = Node(i)
    avl_tree.add(node)
avl_tree.infix_order()
print("双旋转处理过后:")
print("树的高度:", avl_tree.root.height())
print("树的左子树高度:", avl_tree.root.left.height())
print("树的右子树高度:", avl_tree.root.right.height())

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1134855.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

HFS 快速搭建 http 服务器

HFS 是一个轻量级的HTTP 服务工具&#xff0c;3.0版本前进提供Windows平台安装包&#xff0c;3.0版本开提供Linux和macOS平台的安装包。 HFS更适合在局域网环境中搭建文件共享服务或者安装配置源服务器。 甲 非守护进程的方式运行 HFS &#xff08;Ubuntu 22.04&#xff09; 一…

c语言进制的转换2进制转换16进制

c语言进制的转换2进制转换16进制 c语言的进制的转换 c语言进制的转换2进制转换16进制一、16进制的介绍二、八四二一法则2进制转换16进制的方法 一、16进制的介绍 十六进制&#xff1a; 十六进制逢十六进一&#xff0c;所有的数组是0到9和A到F组成&#xff0c;其中A代表10&…

【C++基础入门】42.C++中同名覆盖引发的问题

一、父子间的赋值兼容 子类对象可以当作父类对象使用&#xff08;兼容性) 子类对象可以直接赋值给父类对象子类对象可以直接赋值给父类对象父类指针可以直接指向子类对象父类引用可以直接引用子类对象 下面看一个子类对象兼容性的代码&#xff1a; #include <iostream>…

EasyConnect

EasyConnect 简介下载安装 简介 EasyConnect 是一种远程连接解决方案&#xff0c;它允许用户通过互联网远程访问和控制其设备和资源。 下载 链接: https://pan.baidu.com/s/1JvejSUA8Tma91FOUv6Gswg 提取码: 3fb5 安装

7-4、S加减速转动实现【51单片机控制步进电机-TB6600系列】

摘要&#xff1a;本节介绍实现步进电机S曲线运动的代码 一、目标功能 实现步进电机转动总角度720&#xff0c;其中加减速各90 加速段&#xff1a;加速类型&#xff1a;S曲线   加速角度&#xff1a;角度为90   起步速度&#xff1a;30RPM&#xff0c;   终止速度&#x…

现在java和大数据选什么?

现在java和大数据选什么&#xff1f; 到底是选择大数据还是JAVA&#xff1f;”相信这个问题困惑着许多转行待定人士和高校专业待选的学生。 在普通人眼里可能会觉得这两个专业或者行业没啥区别&#xff0c;都是IT里的&#xff0c;能有啥大不同。这是第一层。最近很多小伙伴找我…

Linux系统中让$前面显示完整的路径

目录 ■修改前效果 ■修改后效果 ■修改方法 ■修改前效果 ■修改后效果 ■修改方法 step1.找到当前用户下面的配置文件【.bashrc】 step2.使用vi命令编辑文件&#xff0c;在最后一行添加如下内容。 export PS1[\u\h $PWD]$ step3.使修改后的文件立即生效 source .bashrc

叮~程序员,你的专属1024程序员节已到账,请注意查收!

“1024&#xff0c;怎么过&#xff1f;” “&#xff1f;&#xff1f;&#xff1f;” “呆子。程序员节&#xff01;” 鲁迅曾说&#xff1a;世界上本没有节日&#xff0c;关注的人多了&#xff0c;便成了节。(hahaha....bushi) 如此小众的节日&#xff0c;外行的人听了好奇&a…

uboot通过图像化界面配置 dns命令

一. 简介 之前文章简单介绍了 uboot图像化配置操作。地址如下&#xff1a; uboot图像化配置操作说明-CSDN博客 本文就以如何使能 dns 命令为例&#xff0c;讲解一下如何通过图形化界面来配置 uboot。 二. uboot 通过图像化界面配置 dns命令 这里所使用的 uboot的源码包&…

M1本地部署Stable Diffusion

下载安装 参考博客: 在Mac上部署Stable Diffusion&#xff08;超详细&#xff0c;AI 绘画入门保姆级教程&#xff09; 安装需要的依赖库 brew install cmake protobuf rust python3.10 git wget 可能中途会存在下载报错或者下载卡主的问题,需要切国内源 brew进行替换源: …

小黑子—spring:第一章

spring入门1.0 一 小黑子对spring基础进行概述1.1 spring导论1.2 传统Javaweb开发困惑及解决方法1.3 三大的思想提出1.3.1 IOC入门案例1.3.2 DI入门案例 1.4 框架概念1.5 初识spring1.5.1 Spring Framework 1.6 BeanFactory快速入门1.7 ApplicationContext快速入门1.8 BeanFact…

SpringBoot项目中的测试类,无法注入类,注入类为空

开发中&#xff0c;需要用到测试类来测试接口 我最开始使用的注入方式是Autowired&#xff0c;但是在执行测试时&#xff0c;注入类报空指针异常&#xff0c;一直为null 后来上网查到几种解决方案&#xff0c;最终在通过下述内容解决了&#xff1a; 1.测试类中添加注解 SpringB…

【云上探索实验室-码上学堂】免费学习领好礼!

走过路过&#xff0c;不要错过&#xff01;上云AI三步走&#xff0c;学着课程奖品有&#xff01; 亚马逊云科技又放福利了&#xff0c;为了让同学们更快入手Amazon CodeWhisperer&#xff0c;官方推出《云上探索实验室-码上学堂》活动&#xff0c;作为一名Amazon CodeWhisperer…

一种晶圆表面形貌测量方法-无图晶圆几何量测系统

晶圆检测机&#xff0c;又称为半导体芯片自动化检测设备&#xff0c;是用于对半导体芯片的质量进行检验和测试的专用设备。它可以用于硅片、硅晶圆、LED芯片等半导体材料的表面检测&#xff0c;通过对晶圆的表面特征进行全面检测&#xff0c;可以有效降低产品的不良率&#xff…

Z41H-40C明杆闸阀型号解析

Z41H-40C型号字母含义 Z41H-40C型号是德特森阀门常用的明杆闸阀型号字母分别代表的意思是: Z——代表阀门类别《闸阀》 4——代表连接方式《法兰》 1——代表结构形式《明杆》 H——代表密封材质《不锈钢合金》 -《分隔键》 40——代表公称压力《4.0MPA》 C——代表阀体…

MongoDB副本集调整节点

点击上方蓝字关注我 MongoDB的副本集&#xff08;Replica Set&#xff09;是一个高可用性、可扩展性和冗余性的数据库解决方案。它能够确保数据库的高可用性&#xff0c;同时保障了数据的安全性。在本文中&#xff0c;我们将探讨如何在一个已经包含三个数据节点的副本集集群中&…

前端(二十四)——轮询与 WebSocket的battle

&#x1f603;博主&#xff1a;小猫娃来啦 &#x1f603;文章核心&#xff1a;轮询与 WebSocket的battle 文章目录 前言轮询的原理及实现WebSocket的原理及实现轮询与WebSocket的比较轮询的应用场景WebSocket的应用场景使用场景的对比与选择WebSocket的安全性考虑WebSocket与服…

匝间冲击耐压试验仪

概述 武汉凯迪正大KDYD2835kV匝间冲击耐压试验仪是采用脉冲波形比较法,以高压冲击波对二线圈或绕组进行过电压的模拟检测&#xff0c;并由示波器来判别二绕组波形差异的一种测试仪器。它能迅速、正确地判断线圈或绕组匝间绝缘电晕放电、局部或相间短路、开路、接线嵌线错误、线…

正点原子嵌入式linux驱动开发——Linux I2C驱动

在电子产品硬件设计当中&#xff0c;I2C 是一种很常见的同步、串行、低速、近距离通信接口&#xff0c;用于连接各种IC、传感器等器件&#xff0c;它们都会提供I2C接口与SoC主控相连&#xff0c;比如陀螺仪、加速度计、触摸屏等&#xff0c;其最大优势在于可以在总线上扩展多个…

uniapp开发小程序—根据生日日期计算年龄 周岁

0、需求 在UniApp开发小程序中&#xff0c;将接口返回的出生日期转化为年龄&#xff1b;判断接口返回的年龄是否是周岁 可以使用JavaScript的日期处理方法来实现。 一、第一种方式&#xff08;示例代码&#xff09;&#xff1a; //javascript // 假设接口返回的年龄为生日的…