平衡二叉树(AVLTree)

news2024/12/22 8:24:04

1.平衡二叉树的定义

1.1 什么是平衡二叉树

平衡二叉树,又称AVL树,用于解决二叉排序树高度不确定的情况,如果二叉排序树的子树间的高度相差太大,就会让二叉排序树操作的时间复杂度升级为O(n),为了避免这一情况,为最坏的情况做准备,就出现了平衡二叉树,使树的高度尽可能的小,其本质还是一棵二叉搜索树。

 1.2 平衡二叉树的性质

  1. 左子树和右子树的高度之差的绝对值小于等于1
  2. 左子树和右子树也是平衡二叉树

为了方便起见,给树上的每个结点附加一个数字,给出该结点左子树与右子树的高度差,这个数字称为结点的平衡因子(BF)

                平衡因子 = 右子树的高度 - 左子树的高度

  左右子树的高度差(平衡因子)< 2,因此平衡二叉树所有结点的平衡因子只能是-1、0、1,如下图,是一个平衡二叉树

 

2.平衡二叉树的基本代码实现

2.1平衡二叉树的插入

首先我们创建一颗二叉树,在开发软件中创建一个AVLTree类,增添树的特性。

 static class TreeNode{
        public int bf;
        public int val;
        public TreeNode left;
        public TreeNode right;
        public TreeNode parent;
        public TreeNode(int val){
            this.val = val;
        }
    }
    public TreeNode root;

接下来我们可以插入一个节点,创建一个boolean类型的insert方法同时传入int val。插入一个树首先考虑插入的树是否为空,如果为空直接添加,如果不为空,就需要比较该节点与插入节的大小。由AVLTree的性质可以知道如果插入的树大于该节点就往改节点的右边走,如果插入的树小于该节点就往改节点的左边走,直到节点为空,以下为该段话语代码的实现:

 TreeNode node = new TreeNode(val);
        if(root == null){
            root = node;
            return true;
        }
        TreeNode parent = null;
        TreeNode cur = root;
        while(cur != null){
            if(cur.val < val){
                parent = cur;
                cur = cur.right;
            }else if (cur.val == val){
               return false;
            }else{
                parent = cur;
                cur = cur.left;
            }
        }

 接下来cur为null,我们需要进行插入,如果父亲节点小于该节点则插入在父亲节点的右侧,如果父亲节点大于该节点则插入在父亲节点的左侧。

 //cur == null
        if(parent.val < val){
            parent.right = node;
        }else{
            parent.left = node;
        }

插入之后我们首先想到的便是平衡因子的修改。先看插入的树是处在父亲节点的左还是右,左进行减减右进行加加。平衡因子修改之后我们还需判断平衡因子是否为这三个符合条件的数字 1 ,-1 ,0  如果是0则说明已经平衡了直接break,如果是 1 或者  -1 则需要向上继续检查是否有不符合标准的情况直到parent为空,此条件便是循环条件。如果平衡因子是2 或者 -2 的话就需要考虑多种情况进行左旋还有右旋还有左右旋。

1. 第一种情况parent.bf = -2 cur.bf = -1 进行右旋。    parent = 60 ,subL = 30 ,subLR = 40

右旋之后  subL.right = parent , parent.left = subLR

 2.第二种情况 进行左旋 parent.bf = 2 cur.bf = 1

左旋之后 subR.left = parent , parent.right = subRL

 

 3.第三种情况  parent.bf = -2 , cur.bf = 1 进行先左旋再右旋,此时左旋传入的parent.left,即rotateleft(parent.left),右旋时传入的是parent,即rotate(parent)

左旋:subR.left = parent , parent.right = subRL

 

之后右旋: 

subL.right = parent

 4.第四种情况 parent.bf = 2 , cur.bf  = -1, bf = cur.left.bf

当bf = 1时,先右后左 rotate right(parent.right) , rotate left(parent)

右旋:

左旋:subR.left = parent

 

 

bf =  -1时 rotate right(parent.right), rotate left(parent) parent为30

 

代码实现: 

 public boolean insert(int val){
        TreeNode node = new TreeNode(val);
        if(root == null){
            root = node;
            return true;
        }
        TreeNode parent = null;
        TreeNode cur = root;
        while(cur != null){
            if(cur.val < val){
                parent = cur;
                cur = cur.right;
            }else if (cur.val == val){
               return false;
            }else{
                parent = cur;
                cur = cur.left;
            }
        }
        //cur == null
        if(parent.val < val){
            parent.right = node;
        }else{
            parent.left = node;
        }
        //node.parent = parent;
        // cur = node
        //平衡因子修改
        while(parent != null){
            //先看平衡因子是左还是右决定平衡因子是++还是--
            if(cur == parent.right){
                parent.bf++;
            }else{
                //如果是左树,平衡因子--
                parent.bf--;
            }
            //检查平衡因子是否是 1 0 -1
            if(parent.bf == 0){
                //说明已经平衡了
                break;
            }else if(parent.bf == 1 || parent.bf == -1){
                //继续向上去修改平衡因子
                cur = parent;
                parent = cur.parent;
            }else{
                if(parent.bf == 2){
                    if(cur.bf == 1){
                        //左旋
                       rotateLeft(parent);
                    }else{
                        //cur.bf == -1 先右旋再左旋
                   rotateRL(parent);
                    }
                }else{
                    //parent.bf == -2 左树高,降低左树的高度
                    if(cur.bf == -1){
                        //右旋
                         rotateRight(parent);
                    }else{
                        //先左旋再右旋 cur.bf == 1
                       rotateLR(parent);
                    }

                }
                break;
            }
        }
        return true;
    }

2.2 左单旋

代码实现:

 private void rotateLeft(TreeNode parent){
         TreeNode subR = parent.right;
         TreeNode subRL = subR.left;
        parent.right = subRL;
         subR.left = parent;
         if(subRL != null) {
             subRL.parent = parent;
         }
         TreeNode pParent = parent.parent;
         parent.parent = subR;
         if(root == parent){
             root = subR;
             root.parent = null;
         }else{
             if(pParent.left == parent){
                 pParent.left = subR;
             }else {
                 pParent.right = subR;
             }
             subR.parent = pParent;
         }
         subR.bf = parent.bf = 0;
    }

 2.3 右单旋

代码实现:

 private void rotateRight(TreeNode parent){
        TreeNode subL = parent.left;
        TreeNode subLR = subL.right;
        parent.left = subLR;
        subL.right = parent;
        if(subLR != null){
            subLR.parent = parent;
        }
        TreeNode pParent = parent.parent;
        parent.parent = subL;
        if(parent == root){
            root = subL;
            root.parent = null;
        }else{
            if(pParent.left == parent){
                pParent.left = subL;
            }else{
                pParent.right = subL;
            }
            subL.parent = pParent;
        }
        subL.bf = 0;
        parent.bf = 0;
    }

 2.4 左右双旋

第一旋:对以A的左子树为根节点的树(即L后面结点,B-9-New)进行左旋

第二旋:再对以A为根节点的树(即全部结点)进行右旋;图中有错误第二旋为右旋

 private void rotateLR (TreeNode parent){
        TreeNode subL = parent.left;
        TreeNode subLR = subL.right;
        int bf = subLR.bf;
        rotateLeft(parent.left);
        rotateRight(parent);
        if(bf == 1){
            subLR.bf = 0;
            parent.bf = 0;
            subL.bf = -1;
        }else if(bf == -1){
            subLR.bf = 0;
            subL.bf = 0;
            parent.bf = 1;
        }
    }

 2.5 右左双旋

第一旋:对以A的右子树为根节点的树(即R后面结点,B-13-10-New)进行右旋

第二旋:再对以A为根节点的树(即全部结点)进行左旋

代码实现:

 private void rotateRL (TreeNode parent){
      TreeNode subR = parent.right;
      TreeNode subRL = subR.left;
      int bf = subRL.bf;
      rotateRight(parent.left);
      rotateLeft(parent);
      if(bf == 1){
          subRL.bf = 0;
          parent.bf = -1;
          subR.bf = 0;
      }else if(bf == -1){
          subRL.bf =0;
          parent.bf = 0;
          subR.bf = 1;
      }
    }

 完整代码:

public class AVLTree {
    static class TreeNode{
        public int bf;
        public int val;
        public TreeNode left;
        public TreeNode right;
        public TreeNode parent;
        public TreeNode(int val){
            this.val = val;
        }
    }
    public TreeNode root;
    public boolean insert(int val){
        TreeNode node = new TreeNode(val);
        if(root == null){
            root = node;
            return true;
        }
        TreeNode parent = null;
        TreeNode cur = root;
        while(cur != null){
            if(cur.val < val){
                parent = cur;
                cur = cur.right;
            }else if (cur.val == val){
               return false;
            }else{
                parent = cur;
                cur = cur.left;
            }
        }
        //cur == null
        if(parent.val < val){
            parent.right = node;
        }else{
            parent.left = node;
        }
        //node.parent = parent;
        // cur = node
        //平衡因子修改
        while(parent != null){
            //先看平衡因子是左还是右决定平衡因子是++还是--
            if(cur == parent.right){
                parent.bf++;
            }else{
                //如果是左树,平衡因子--
                parent.bf--;
            }
            //检查平衡因子是否是 1 0 -1
            if(parent.bf == 0){
                //说明已经平衡了
                break;
            }else if(parent.bf == 1 || parent.bf == -1){
                //继续向上去修改平衡因子
                cur = parent;
                parent = cur.parent;
            }else{
                if(parent.bf == 2){
                    if(cur.bf == 1){
                        //左旋
                       rotateLeft(parent);
                    }else{
                        //cur.bf == -1 先右旋再左旋
                   rotateRL(parent);
                    }
                }else{
                    //parent.bf == -2 左树高,降低左树的高度
                    if(cur.bf == -1){
                        //右旋
                         rotateRight(parent);
                    }else{
                        //先左旋再右旋 cur.bf == 1
                       rotateLR(parent);
                    }

                }
                break;
            }
        }
        return true;
    }

    /**
     * 右左双旋
     * @param parent
     */
    private void rotateRL (TreeNode parent){
      TreeNode subR = parent.right;
      TreeNode subRL = subR.left;
      int bf = subRL.bf;
      rotateRight(parent.left);
      rotateLeft(parent);
      if(bf == 1){
          subRL.bf = 0;
          parent.bf = -1;
          subR.bf = 0;
      }else if(bf == -1){
          subRL.bf =0;
          parent.bf = 0;
          subR.bf = 1;
      }
    }
    /**
     * 左右双旋
     */
    private void rotateLR (TreeNode parent){
        TreeNode subL = parent.left;
        TreeNode subLR = subL.right;
        int bf = subLR.bf;
        rotateLeft(parent.left);
        rotateRight(parent);
        if(bf == 1){
            subLR.bf = 0;
            parent.bf = 0;
            subL.bf = -1;
        }else if(bf == -1){
            subLR.bf = 0;
            subL.bf = 0;
            parent.bf = 1;
        }
    }

    /**
     * 左单旋
     * @param parent
     */
    private void rotateLeft(TreeNode parent){
         TreeNode subR = parent.right;
         TreeNode subRL = subR.left;
        parent.right = subRL;
         subR.left = parent;
         if(subRL != null) {
             subRL.parent = parent;
         }
         TreeNode pParent = parent.parent;
         parent.parent = subR;
         if(root == parent){
             root = subR;
             root.parent = null;
         }else{
             if(pParent.left == parent){
                 pParent.left = subR;
             }else {
                 pParent.right = subR;
             }
             subR.parent = pParent;
         }
         subR.bf = parent.bf = 0;
    }

    /**
     * 右单旋
     * @param parent
     */
    private void rotateRight(TreeNode parent){
        TreeNode subL = parent.left;
        TreeNode subLR = subL.right;
        parent.left = subLR;
        subL.right = parent;
        if(subLR != null){
            subLR.parent = parent;
        }
        TreeNode pParent = parent.parent;
        parent.parent = subL;
        if(parent == root){
            root = subL;
            root.parent = null;
        }else{
            if(pParent.left == parent){
                pParent.left = subL;
            }else{
                pParent.right = subL;
            }
            subL.parent = pParent;
        }
        subL.bf = 0;
        parent.bf = 0;
    }
}

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

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

相关文章

mac 安装Arthas

mac安装有两种方式 1.第一步安装Arthas 第一种&#xff1a; curl -L https://arthas.aliyun.com/install.sh | sh 第二种jar包形式 curl -O https://arthas.aliyun.com/arthas-boot.jar个人比较推荐第一种因为运行测试成功了 第一种安装后可能会出现一些命令不符合 需…

NVIDIA刚刚发布了关于 AI 的免费在线课程!

英伟达最近上线了一批不错的免费课程&#xff0c;先收藏起来&#xff01; ps:有时候真想有一个收藏即学会的技能啊 数据中心中的人工智能 了解数据中心的 AI 基础知识&#xff0c;涵盖机器学习、深度学习、GPU 架构和部署。 了解多系统 AI 集群和基础设施规划。 课程地址&…

勇闯机器学习(第三关-特征工程)

以下内容皆为原创&#xff0c;制作不易&#xff0c;请帅锅、镁铝点点赞赞和关注吧❥(^_^) 一.提问环节 机器学习是什么&#xff1f; 机器学习就是通过自动分析大量数据去建立模型&#xff0c;训练模型&#xff0c;预测数据。 这么好记的概念&#xff0c;你应该记住了吧&#x…

多线程编程的拙见

一. 线程和进程的概念 1.为什么引入多线程编程&#xff1f; 在多线程&#xff08;Multithreaded&#xff0c;MT&#xff09;编程出现之前&#xff0c;电脑程序的运行由一个执行序列组成&#xff0c;执行序列按顺序在主机的中央处理器CPU中运行。即使整个程序由多个相互独立无…

基于Yolov5的安全帽检测系统设计与开发(论文+源码)_kaic

摘 要 安全帽检测系统的设计意义在于提高工作场所的安全性和生产效率&#xff0c;通过安全帽检测系统可以实时监控工人是否佩戴安全帽&#xff0c;及时发现不佩戴安全帽的工人并进行提醒和警示&#xff0c;避免因为不佩戴安全帽导致意外事故的发生。因此&#xff0c;本文是一个…

云呼叫中心系统哪家好?这个系统强烈推荐

云呼叫中心系统作为企业客户服务与运营的核心平台&#xff0c;正逐步成为提升企业竞争力的关键要素。面对市场上琳琅满目的云呼叫中心系统提供商&#xff0c;企业往往面临选择难题&#xff1a;“云呼叫中心系统哪家好&#xff1f;” 云呼叫中心系统&#xff1a;定义与核心功能 …

【HuggingFace Transformers】BertModel源码解析

BertModel源码解析 1. BertModel 介绍2. BertModel 源码逐行注释 1. BertModel 介绍 BertModel 是 transformers 库中的核心模型之一&#xff0c;它实现了 BERT&#xff08;Bidirectional Encoder Representations from Transformers&#xff09;模型的架构。BERT 是基于 Trans…

百数教学——企业互联,让业务合作跨越距离与障碍

一、简介 企业互联作为强大的纽带&#xff0c;不仅促进了企业间的紧密合作与深入交流&#xff0c;还显著提升了企业的运营效率和市场竞争力。它通过无缝链接外部组织&#xff0c;实现双方企业项目数据的即时共享与整合&#xff0c;从而深化了业务合作的层次与广度&#xff0c;…

如何在SOLIDWORKS中自定义材料库

使用SolidWorks对模型进行评估时都需要现定义一个材料&#xff1b;例如&#xff1a;测量模型的质量属性、使用限元分析模型等&#xff0c;SolidWorks自带了丰富的材质库&#xff0c;满足了绝大部分的设计需求。但是难免会遇到一些特点的材质属性&#xff0c;在SOLIDWORKS中无法…

【LLM大模型论文日更】| 格式胜过内容:揭示大型语言模型的提示效应

论文&#xff1a;https://arxiv.org/pdf/2408.08780代码&#xff1a;未开源机构&#xff1a;北京大学领域&#xff1a;提示学习&#xff0c;上下文学习发表&#xff1a;arXiv 研究背景 研究问题&#xff1a;这篇文章探讨了在上下文学习&#xff08;ICL&#xff09;中&#xf…

ubuntu20.4 安装postgresql并远程连接

1、安装对应的库 如果提示安装失败,E: Unable to locate package postgresql这个错误的话,那就更新下,执行sudo apt update 命令,再次下载,应该就可以成功 sudo apt install postgresql 2、端口设置 检查5432端口是否监听 ss -nlt 需要将多个远程客户端连接上数据库,配…

合宙LuatOS产品规格书——Air700ECQ

Air700ECQ是合宙通信推出的LTECat.1bis通信模块&#xff1b; Air700ECQ采用移芯EC716E平台&#xff0c;支持LTE3GPPRel.13技术&#xff1b; Air700ECQ支持移动双模&#xff0c;超小封装&#xff0c;极致成本&#xff0c;满足小型化低成本需求。 Air700ECQ支持单1.8/3.0V USIM…

酒店民宿在线预约系统,搭建全攻略

在旅游业的推动下&#xff0c;酒店民宿获得了更多的发展机遇。随着数字化的来临&#xff0c;酒店民宿也迎来了转型升级&#xff0c;线上预约酒店民宿小程序成为了必不可少的发展方式。小程序可以为酒店民宿提供一个高效便利的在线预约系统&#xff0c;满足用户预约酒店的需求&a…

20. 数据可视化

20. 数据可视化 本章概述一. `elasticsearch`实现数据统计1.1 创建用户信息索引1.1.1 控制台创建`aggs_user`索引1.1.2 `aggs_user`索引结构初始化1.1.3 `aggs_user`索引的`EO`对象1.1.4 用户类型枚举1.1.5 数据初始化1.2 内置统计聚合1.2.1 `terms`与`date_histogram``terms``…

传统RFID标签与RFID光触发标签的全面差异解读

在当今数字化、智能化的大趋势下&#xff0c;RFID技术凭借其非接触式自动识别的独特优势&#xff0c;在物流、零售、制造等众多领域得到了广泛应用。其中&#xff0c;RFID标签作为承载数据和实现识别的关键组件&#xff0c;不断推陈出新&#xff0c;传统RFID标签虽已历经多年发…

BER编码的Identifier octets

在了解DLMS/COSEM应用层协议的时候有必要了解一下ASN.1、BER、A-XDR。 这里只对部分做记录。 参考资料&#xff1a;ASN.1、BER和DER的PKCS相关子集入门介绍_golang asn1-CSDN博客 1、介绍 抽象语法表示法一&#xff08;ASN.1&#xff09;、基本编码规则&#xff08;BER&…

工厂现场多功能帮手,三防平板改善管理体验

随着制造业的智能化变革&#xff0c;信息化、自动化和智能化逐渐成为工厂管理的新常态。在这一波技术浪潮中&#xff0c;三防平板作为一种多功能的工作工具&#xff0c;正在逐步改善工厂现场的管理体验。 一、三防平板的定义与特点 三防平板&#xff0c;顾名思义&#xff0c;是…

一篇文章讲清楚Zotero所有实用插件

主要介绍常用的zotero基础高使用&高实用插件及功能展示。 zotero7更新链接&#xff1a;链接 目录 插件表一览插件列表插件效果展示actions and Tags for Zotero插件说明插件设置Awesome GPTBetter Notes for zoteroCrush ReferenceEasier CitationEthereal Stylejasminum…

谢谢微软,又又又Open了!一口气发布3款Phi-3.5新模型,领先Llama3.1和谷歌同级模型

家人们&#xff01;微软又用爱发电了&#xff01;一觉醒来&#xff0c;微软发布了最新的小模型三兄弟&#xff1a; Phi-3.5-MoE-instruct Phi-3.5-mini-instruct Phi-3.5-vision-instruct 三兄弟的表现可以说是相当的不错&#xff0c;其中&#xff0c;Phi-3.5-MoE 在基准测…

【NVM-下载、安装、使用】

前置条件 已经安装node&#xff0c;需要卸载node # 查看是否安装nodejs&#xff0c;展示版本则是已安装 node -v 在控制面板中卸载nodejs 删除nodejs安装目录 删除.npmrc配置文件(不知道在什么位置可以直接搜索.npmrc) 查看是否删除成功 node -v 提示【不是内部或外部命令&…