二叉搜索树之AVL树

目录

1.概念

2.定义

3.插入

4.旋转

1. 新节点插入较高左子树的左侧---右单旋

2. 新节点插入较高右子树的右侧---左单旋

3. 新节点插入较高左子树的右侧:先左单旋再右单旋【左右双旋】

4. 新节点插入较高右子树的左侧---右左:先右单旋再左单旋【右左双旋】

5.验证

6.删除

7.性能分析


1.概念

高度平衡的二叉搜索树

一颗AVL树或者是空树,或者是具有以下性质的二叉搜索树 (中序遍历是递增的):

1.左右树都是AVL树

2.左右子树高度之差的绝对值不超过1(-1/0/1)

2.定义

孩子双亲表示法

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

3.插入

1.把数据插入到AVL树当中(和二叉搜索树一样)

  1. 为空-->直接插入
  2. parent:父节点 cur:当前结点
  3. 遍历直到为null
    1. cur.val小,parent=cur,cur指向右结点
    2. 相等,return false-->已经有不用插入
    3. cur.val大,parent=cur,cur指向左结点
  4. cur==null 插入结点(此时parent为叶子结点)
    1. parent.val插入parent的右边
    2. parent.val>val -->插入parent的左边

2,插入后,根据平衡因子对树调整

  1. 先看cur是parent的左还是右,决定平衡因子是++,还是--
    1. 如果是右树,右树高度++,平衡因子++
    2. 如果是左树,左树高,平衡因子--
  2. 检查平衡
    1. 0代表整棵树平衡-->break;
    2. 1和-1表示当前平衡,不保证整棵树平衡,-->向上调整
    3. 2或者-2,当前不平衡
      1. bf==2-->右树高,左旋
      2. bf==-2-->左树高,右旋
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;
          }
      }
 if(parent.val<val){
            parent.right=node;
        }else{
            parent.left=node;
        }

      
      node.parent=parent;
      cur=node;
      
      while(parent!=null){
          if(cur==parent.left){
              parent.bf--;
          }else{
              parent.bf++;
          }
          
          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{
                      rotateRL(parent);
                  }
              }else{
                  if(cur.bf==-1){
                      rotateRight(parent);
                  }else{
                      rotateLR(parent);
                  }
              }
              break;
          }
      }
      return true;
    }

4.旋转

1.如果在一棵原本是平衡的AVL树中插入一个新节点,可能造成不平衡,此时必须调整树的结构,使之平衡化。根据节点插入位置的不同,AVL树的旋转分为四种:

1. 新节点插入较高左子树的左侧---右单旋

 

1.定义结点   subL   subLR

2.改变指向     parent指向subLR    subL指向parent   subLR指向parent

3.如果把subL提起来,要把subL的parent改为parent的parent

4.调整parent和上面的结点,判断parent是否是根节点

        1.如果是,subL变为根节点  root.parent为null

        2.如果是parent是pparent的左子树,subL改为pparent的左子树

        3.如果是parent是pparent的右子树,subL改为pparent的右子树

        4.subL指向pparent

4.平衡因子变为0

 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;
        }
        //调整parent和上面的结点
        TreeNode pparent=parent.parent;
        parent.parent=subL;

        if(parent==root){
            root=subL;
            root.parent=null;

        }else{
            if(pparent.right==parent){
                pparent.right=subL;
            }else{
                pparent.left=subL;
            }
            subL.parent=pparent;
        }
        //调整平衡因子
        subL.bf=0;
        parent.bf=0;
    }

2. 新节点插入较高右子树的右侧---左单旋

1.定义结点

2.改变指向

3.如果把subR提起来,要把subR的parent改为parent的parent

4.平衡因子变为0

 

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;
        if(parent==root){
            subR=root;
            root.parent=null;
        }else{
            if(pparent.right==parent){
                pparent.right=subR;
            }else{
                pparent.left=subR;
            }
            subR.parent=pparent;
        }
        subR.bf=0;
        parent.bf=0;
    }

3. 新节点插入较高左子树的右侧:先左单旋再右单旋【左右双旋】

 

因为两种平衡因子的结果不同,所以要区分

1.区分是哪一种情况

2.调用左旋函数

3,调用右旋函数

4.设置平衡因子

 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){
            subL.bf=0;
            subLR.bf=0;
            parent.bf=1;
        }else if(bf==1){
            subL.bf=-1;
            subLR.bf=0;
            parent.bf=0;
        }

    }

4. 新节点插入较高右子树的左侧---右左:先右单旋再左单旋【右左双旋】

 

private void rotateRL(TreeNode parent) {
        TreeNode subR=parent.right;
        TreeNode subRL=subR.left;
        int bf=subRL.bf;
        rotateRight(parent.right);
        rotateLeft(parent);
        if(bf==-1){
            parent.bf=0;
            subR.bf=1;
            subRL.bf=0;
        }else if(bf==1){//原先新插入的在右边
            parent.bf=-1;
            subR.bf=0;
            subRL.bf=0;
        }

    }

5.验证

1.验证为二叉搜索树

如果中序遍历可得到一个有序的序列,就说明为二叉搜索树

//中序遍历的结果是有序
public void inorder(TreeNode root){
    if(root==null) return;
    inorder(root.left);
    System.out.println(root.val+" ");
    inorder(root.right);
}

2. 验证其为平衡树

  • 每个节点子树高度差的绝对值不超过1(注意节点中如果没有平衡因子)
  • 节点的平衡因子是否计算正确
  • private int height(TreeNode root){
        if(root==null) return 0;
        int leftH=height(root.left);
        int rightH=height(root.right);
        return leftH > rightH ? leftH+1 : rightH+1;
    }
    
    //判断是否是平衡二叉树
    public boolean isBalanced(TreeNode root){
        if(root==null) return true;
        int leftH=height(root.left);
        int rightH=height(root.right);
    
        if(rightH-leftH !=root.bf){
            System.out.println("这个节点"+root.val+"平衡因子异常");
            return false;
        }
        return Math.abs(leftH-rightH) <=1
                && isBalanced(root.left)
                && isBalanced(root.right);
    
    }

3.验证用例

public static void main(String[] args) {
   int[] array={16,3,7,11,9,26,18,14,15};
    //int[] array={4, 2, 6, 1, 3, 5, 15, 7, 16, 14};
    AVLTree avlTree=new AVLTree();
    for(int i=0;i< array.length;i++){
        avlTree.insert(array[i]);
    }
    System.out.println(avlTree.isBalanced(avlTree.root));
}

6.删除

思路:

1、找到需要删除的节点

2、按照搜索树的删除规则删除节点

3、更新平衡因子,如果出现了不平衡,进行旋转。--单旋,双旋

7.性能分析

如果需要一种查询高效且有序的数据结构,而且数据的个数为静态的(即不会改变),可以考虑AVL树,但一个结构经常修改,就不太适合。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

I.MX6ULL_Linux_驱动篇(37) linux系统定时器

定时器是我们最常用到的功能&#xff0c;一般用来完成定时功能&#xff0c;本章我们就来学习一下 Linux 内核提供的定时器 API 函数&#xff0c;通过这些定时器 API 函数我们可以完成很多要求定时的应用。 Linux内核也提供了短延时函数&#xff0c;比如微秒、纳秒、毫秒延时函数…

Car Guide

文章目录 科目一第一章 机动车驾驶证申领和使用规定第一节 驾驶证的许可&#xff1f;种类和有效期第二节 驾驶证的申领第三节 驾驶证的使用第四节 驾驶考试第五节 违法记分制度 第二章 交通信号第一节 交通信号灯第二节 交通标志第三节 交通标线第四节 交警手势 第三章 道路交通…

【编程语言 · C语言 · 递归函数】

递归函数 C 语言的函数都支持递归, 也就是说&#xff0c;每个函数都可以直接或者间接第调用自己。所谓的间接调用&#xff0c;是指在递归函数调用的下层函数中再调用自己。 递归关系图如下&#xff1a; 递归之所以能实现&#xff0c;是因为函数的每个执行过程在栈中都有自己的…

Redis从入门到精通之底层数据结构快表QuickList详解

文章目录 0.前言1. 快表的结构2. Redis 6.0 快表quicklist 基本结构2.1 成员变量2.1 主要操作2.1 推导结果 3. 快表的操作 3. 快表的优缺点3.1 优点&#xff1a;3.2 缺点&#xff1a; 5. Redis从入门到精通系列文章 0.前言 上个篇章回顾&#xff0c;我们上个章节&#xff0c;讲…

Win10 系统专业版远程桌面如何才能多用户同时登录使用?

环境&#xff1a; Win10专业版19041 RDPWrap-v1.6.2 dell5493笔记本 问题描述&#xff1a; Win10 系统专业版远程桌面如何才能多用户同时登录使用&#xff1f; 解决方案&#xff1a; 安装RDPWrap 1.关闭remote desktop services服务 安装RDP之前&#xff0c;要先关闭re…

Kuberentes,k8s诞生简介

一、前言 什么是k8s&#xff1f; Kuberentes 是基于容器的集群管理平台&#xff0c;它的简称&#xff0c;是K8S。有人说之所以叫k8s&#xff0c;是因为k到s中间有8个字母&#xff0c;因此叫k8s&#xff0c;也有人说&#xff0c;在使用k8s的安装配置流程中&#xff0c;共分为8…

验证attention是否在图像分类问题上起决定性作用

来源&#xff1a;投稿 作者&#xff1a;摩卡 编辑&#xff1a;学姐 Motivation 现阶段出现了大量的Transformer-style图像分类模型&#xff0c;并且这些模型在ImageNet上取得了不俗的成绩&#xff0c;这些Transformer-style模型将取得高性能的功劳归功于Multi-head attention注…

12.异常检测

12.1 异常检测的应用 异常检测最常见的应用是欺诈检测&#xff1b; 如果你有很多用户&#xff0c;每个用户都在从事不同的的活动&#xff0c;你可以对不同的用户活动计算特征变量&#xff0c;然后可以建立一个模型来表示用户表现出各种行为的可能性&#xff0c;用来表示用户行…

微服务 springcloud 05 hystrix框架,降级,可视化Hystrix dashboard 仪表盘,熔断

01.微服务宕机时&#xff0c;ribbon 无法转发请求 关闭 user-service 和 order-service 02.hystrix框架 03.创建hystrix项目&#xff0c;hystrix与ribbon经常一起出现 第一步&#xff1a;复制 sp06-ribbon 项目&#xff0c;命名为sp07-hystrix 选择 sp06-ribbon 项目&#…

高并发架构设计方法

我们知道&#xff0c;“高并发”是现在系统架构设计的核心关键词。一个架构师如果设计、开发的系统不支持高并发&#xff0c;那简直不好意思跟同行讨论。但事实上&#xff0c;在架构设计领域&#xff0c;高并发的历史非常短暂&#xff0c;这一架构特性是随着互联网&#xff0c;…

【JVM】日志分析工具--gcviewer的使用

文章目录 gcviewer是什么&#xff1f;gcviewer的使用最后 gcviewer是什么&#xff1f; GCViewer是一个小工具&#xff0c;可以可视化Sun / Oracle、IBM、HP和BEA Java虚拟机生成的详细GC输出。它是在GNU LGPL下发布的自由软件。—官网翻译 gcviewer的使用 文章使用的配置 工具…

权限验证框架之Shiro

文章目录 前言shiro 核心项目构建默认Session模式配置测试接口Realm编写权限测试无权限测试登录测试权限测试 前后端分离tokenJWTFilter重写认证修改配置 总结 前言 交替换个脑子&#xff0c;一直搞考研的东西&#xff0c;实在是无聊。所以顺便把工程上的东西&#xff0c;拿来…

探索Redis内部数据结构

Redis支持多种数据结构&#xff0c;每种数据结构都有其特定的用途。下面对Redis支持的主要数据结构进行详细阐述&#xff1a; 一、字符串&#xff08;String&#xff09; 字符串是Redis最基本的数据结构&#xff0c;可以存储一个字符串或者二进制数据&#xff0c;例如图片、序…

HID协议学习

HID协议学习 0. 文档资料 USB_HID协议中文版_USB接口HID设备_AUJsRmB9kg.pdf HID报告描述符精细说明_mgCxM8_ci9.pdf hut1_22_U3cvnwn_ZZ.pdf 1. 基本概念 HID协议是一种基于USB的通讯协议&#xff0c;用于在计算机和输入设备之间进行数据传输。HID协议定义了标准的数据格…

如何实现在线书签内容替换

书签广泛应用于企业的各种办公自动化业务场景中。例如&#xff1a;在范式合同模板中将甲乙方书签自动替换成具体的公司名称&#xff1b;在红头文件模板中将红头标题书签替换成具体的行政指令&#xff1b;在各种协议模板中将协议日期书签替换为当前日期&#xff1b;等等。 在这…

【Elacticsearch】 原理/数据结构/面试经典问题整理

对Elacticsearch 原理/数据结构/面试经典问题整理的文章&#xff1b; 映射 | Elasticsearch: 权威指南 | Elastic Elacticsearch介绍 Elasticsearch,这里简称ES。ES是一个开源的高可用高扩展的分布式全文搜索与分析引擎&#xff0c;可以提供PB级近实时的数据存储和检索能力&am…

《离散数学》:集合、关系和函数

〇、前言 这章将会对集合、以及集合之上的关系、以及两个集合之间的映射情况做一个细致的讨论。集合作为数学和其他领域中的基础概念&#xff0c;具有广泛的应用和重要的地位。它为数学建立了基本的体系和推理方法&#xff0c;为各个领域的研究和应用提供了一种统一的描述和分…

基于web漏洞扫描及分析系统设计_kaic

基于web漏洞扫描及分析系统设计 摘 要 随着信息技术的发展和网络应用在我国的普及&#xff0c;针对我国境内信息系统的恶意网络攻击也越来越多&#xff0c;并且随着黑客攻击技术的不断地更新&#xff0c;网络犯罪行为变得越来越难以应对&#xff0c;用户日常访问的网站是否安全…

Mysql主从复制及读写分离

&#x1f353; 简介&#xff1a;java系列技术分享(&#x1f449;持续更新中…&#x1f525;) &#x1f353; 初衷:一起学习、一起进步、坚持不懈 &#x1f353; 如果文章内容有误与您的想法不一致,欢迎大家在评论区指正&#x1f64f; &#x1f353; 希望这篇文章对你有所帮助,欢…

LaTeX插入参考文献

接着上一篇&#xff0c;用EndNote组织参考文献&#xff0c;然后再导入到LeTex中感觉不太好用&#xff0c;然后就学习了一下BibTeX来管理参考文献&#xff0c;发现还可以&#xff0c;这里记录一下&#xff0c;方便以后查阅。 LaTeX插入参考文献 thebibliographyBibTeX参考资料 t…