java平衡二叉树左旋,Java 平衡二叉树之单旋(左旋,右旋)与双旋

article/2025/9/29 7:17:28

1.平衡二叉树

平衡二叉树也叫平衡二叉搜索树(Self-balancing binary search tree)又被称为AVL树, 可以保证查询效率较高。

具有以下特点:它是一 棵空树或它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一棵平衡二叉树。

首先要明确的是,平衡二叉树是一棵二叉排序树,它的出现是为了解决普通二叉排序树(普通二叉排序树)不平衡的问题。如图,在插入结点之前首先要查找插入位置,假如要在5结点后插入,普通二叉排序树需要比较五次,而平衡二叉树只需要比较三次。假如结点规模进一步加大,效率提升也会更明显。

44a3c53899e87ad2e47a08e35760fd68.png

2.二叉树到平衡二叉树:单旋(左旋,右旋)与双旋

2.1单旋转:

左旋(当rightHeight-leftHeight>1)

旋转后

根结点:最新的根结点的右孩子为原根结点的右孩子

左子树:左子树的根即为原来的根,左子树的左子树即为原来的左子树,左子树的 右子树为原来右子树的左子树

右子树:右子树为原根结点右孩子的右子树

3f49f4f3d3a69108146237002ca003f4.png

右旋(当rightHeight-leftHeight>1)

旋转后

根结点:最新的根结点的左孩子为原根结点的右孩子

左子树:左子树为原根结点左孩子的左子树

右子树:右子树的根即为原来的根,右子树的右子树即为原来的右子树,右子树的左子树为原来左子树的右子树

c49f32fc5a019c6cd022e3560d7dedc6.png

2.2.双旋转:

我们会发现,对于有些树,单旋是无法解决问题的:

1ce226cf18b66506d28f64f40943f6f2.png

问题分析:

当符合右旋的条件时(左旋同理),如果它的左子树的右子树高度大于它的右子树高度,

假设左子树的高度为x,右子树的高度为(x-2),左子树的左子树高度(x-2),左子树的右子树高度(x-1)

右旋后:左子树的高度为x-2,右子树的高度x((x-1)+1=x),仍不满足平衡二叉树

解决:先对这个结点的左节点进行左旋转,再对当前结点进行右旋转即可。

9ce5cf34d121d465ff68ca7c408e52c0.png

3.代码实现

关于单旋(左旋,右旋)与双旋的处理都在添加结点的功能后完成,即添加一个结点,就对新的树进行判断是否需要"平衡"。

当前结点的高度与左右结点的高度

//求该结点的高度

public int getHeight(){

return Math.max(this.left==null?0:this.left.getHeight(),this.right==null?0:this.right.getHeight())+1; //妙

}

//左节点的高度

public int getLeftHeight(){

if(this.left==null){

return 0;

}

else{

return this.left.getHeight();

}

}

//右节点的高度

public int getRightHeight(){

if(this.right==null){

return 0;

}

else{

return this.right.getHeight();

}

}

左旋

//左旋

public void leftRotate(){

//创建新的左子树

//创建新的结点,以当前根结点的值

AVLNode node=new AVLNode(this.value);

//把新的结点的左子树设置成当前结点的左子树

node.left=this.left;

//把新的结点的右子树设置成带你过去结点的右子树的左子树

node.right=this.right.left;

//创建新的根结点

//把当前结点的值替换成右子结点的值

this.value=this.right.value;

//(根结点+右子树)

//把当前结点的右子树设置成当前结点右子树的右子树

this.right=this.right.right;

//(根结点+右子树+左子树)

//把当前结点的左子树(左子结点)设置成新的结点

this.left=node;

}

右旋

//右旋

public void rightRotate(){

//创建新的右子树

//创建新的结点,以当前根结点的值

AVLNode node=new AVLNode(this.value);

//把新的结点的右子树设置成当前结点的右子树

node.right=this.right;

//把新的结点的左子树设置成带你过去结点的左子树的右子树

node.left=this.left.right;

//创建新的根结点

//把当前结点的值替换成右子结点的值

this.value=this.left.value;

//(根结点+左子树)

//把当前结点的左子树设置成当前结点左子树的左子树

this.left=this.left.left;

//(根结点+右子树+左子树)

//把当前结点的左子树(左子结点)设置成新的结点

this.right=node;

}

向二叉排序树添加结点(平衡二叉树的创建)

/**

* 向二叉排序树添加结点

* @param node

*/

public void add(AVLNode node){

if(node==null){

return;

}

if(node.value1,左旋转

if(this.getRightHeight()-this.getLeftHeight()>1){

//如果它的右子树的左子树高度大于它的左子树高度,双旋转

if(this.right!=null&&this.right.getLeftHeight()>this.getLeftHeight()){

//先对这个结点的右节点进行右旋转

this.right.rightRotate();

}

//再对当前结点进行左旋转即可。

this.leftRotate();

}

//当添加完一个结点后,如果:(左子树的高度-右子树的高度)>1,右旋转

else if(this.getLeftHeight()-this.getRightHeight()>1){

//如果它的左子树的右子树高度大于它的右子树高度,双旋转

if(this.left!=null&&this.left.getRightHeight()>this.getRightHeight()){

//先对这个结点的左节点进行左旋转

this.left.leftRotate();

}

//再对当前结点进行右旋转即可。

this.rightRotate();

}

else{

return;

}

}

4.完整代码

package tree;

/**

* 平衡二叉树

* 1.左旋

* 2,右旋

* 3.双旋

* @author BayMax

*

*/

public class AVLTreeDemo {

public static void main(String[] args) {

AVLTree avlt=new AVLTree();

int []arr={10,7,11,6,8,9};

//循环添加结点到二叉排序树

for(int tmp:arr){

avlt.add(new AVLNode(tmp));

}

//中序遍历

avlt.infixOrder();

//测试结点的高度

System.out.println(avlt.getRoot()+"\t"+avlt.getHeight());

for(int tmp:arr){

System.out.println(tmp+" "+avlt.search(tmp).getHeight());

}

}

}

class AVLTree{

private AVLNode root;

public AVLTree() {

super();

// TODO Auto-generated constructor stub

}

public AVLTree(AVLNode root) {

super();

this.root = root;

}

public AVLNode getRoot() {

return root;

}

public void setRoot(AVLNode root) {

this.root = root;

}

//添加结点的方法

public void add(AVLNode node){

if(root==null){

root=node;

}

else{

root.add(node);

}

}

//中序遍历

public void infixOrder(){

if(root==null){

System.out.println("该二叉树为空");

}

else{

root.infixOrder();

}

}

//查找结点

public AVLNode search(int value){

if(root==null){

System.out.println("该二叉树为空");

}

return root.search(value);

}

//树的高度

public int getHeight(){

if(root==null){

return 0;

}

return root.getHeight();

}

}

class AVLNode{

private int value;

private AVLNode left;

private AVLNode right;

public AVLNode() {

super();

}

public AVLNode(int value) {

super();

this.value = value;

}

public int getValue() {

return value;

}

public void setValue(int value) {

this.value = value;

}

public AVLNode getLeft() {

return left;

}

public void setLeft(AVLNode left) {

this.left = left;

}

public AVLNode getRight() {

return right;

}

public void setRight(AVLNode right) {

this.right = right;

}

@Override

public String toString() {

return "BSTNode [value=" + value + "]";

}

/**

* 向二叉排序树添加结点

* @param node

*/

public void add(AVLNode node){

if(node==null){

return;

}

if(node.value1,左旋转

if(this.getRightHeight()-this.getLeftHeight()>1){

//如果它的右子树的左子树高度大于它的左子树高度,双旋转

if(this.right!=null&&this.right.getLeftHeight()>this.getLeftHeight()){

//先对这个结点的右节点进行右旋转

this.right.rightRotate();

}

//再对当前结点进行左旋转即可。

this.leftRotate();

}

//当添加完一个结点后,如果:(左子树的高度-右子树的高度)>1,右旋转

else if(this.getLeftHeight()-this.getRightHeight()>1){

//如果它的左子树的右子树高度大于它的右子树高度,双旋转

if(this.left!=null&&this.left.getRightHeight()>this.getRightHeight()){

//先对这个结点的左节点进行左旋转

this.left.leftRotate();

}

//再对当前结点进行右旋转即可。

this.rightRotate();

}

else{

return;

}

}

//中序遍历

public void infixOrder(){

if(this.getLeft()!=null){

this.left.infixOrder();

}

System.out.println(this);

if(this.getRight()!=null){

this.right.infixOrder();

}

}

//查找要删除结点

public AVLNode search(int value){

if(this.value==value){

return this;

}

//左子树查找

if(value


http://chatgpt.dhexx.cn/article/J7yCpyRA.shtml

相关文章

平衡二叉树的左旋和右旋

文章目录 复习树1. 树的概念2. 二叉树(Binary Tree)3. 满二叉树4. 完全二叉树5. 二叉堆6. 二叉搜索树 左旋和右旋7. 平衡二叉树(平衡二叉搜索树) 本文章是我的库存文章,本来不发的,但还是发吧,请跳到第7节,那才是讲左旋和右旋的。…

HashMap-红黑树插入平衡、左旋、右旋源码解析

目录 一、树的演变 二、红黑树 1.红黑树的特点 2.树左旋右旋的过程 3.红黑树插入节点情景分析: 三、HashMap插入平衡、左旋、右旋源码解析 1.添加值 2.插入平衡 3.左旋、右旋 一、树的演变 为什么会有树,因为链表的查询效率是logOn,树的查询效率…

HashMap底层实现原理:红黑树左旋右旋

HashMap中的红黑树左旋、右旋: 一、什么是左旋、右旋: 红黑树的性质: 每个节点要么是黑色,要么是红色根节点是黑色每个叶子节点(NIL)是黑色每个红色结点的两个子结点一定都是黑色任意一结点到每个叶子结点…

平衡二叉查找树(AVL)的构建——左旋右旋

原文链接:https://www.cnblogs.com/ZhaoxiCheung/p/6012783.html 平衡二叉树,又称AVL(Adelson-Velskii和Landis)树,是带有平衡条件的二叉查找树。这个平衡条件必须要容易保持,而且它必须保证树的深度是 O&…

详解红黑树之左旋右旋

为什么要左旋右旋? 为了使得左右子树的高度差在一定范围内,需要通过旋转调整,这样就可以保持平稳的搜索效率 左旋: 步骤 1.设原来E的父节点是father,那么左旋之后需要改变的是: 2.S和father的关系&#…

avl树左旋右旋的理解

一直没搞懂非平衡二叉树变平衡二叉树时左旋右旋,今天下定决心搞懂,然后在众多博客中终于找到了这样一篇,非常形象,记录如下: AVL树是最先发明的自平衡二叉查找树。在AVL树中任何节点的两个子树的高度最大差别为一&…

搞懂平衡二叉树的左旋右旋双旋(Java实现)

刚看到韩顺平老师的数据结构与算法对于平衡二叉树的讲解(最后会附上地址),有如下理解,希望能帮助大家!哪里需要改正的欢迎指正! 平衡二叉树:一种二叉排序树(BST Binary Sort Tree&a…

图示讲解AVL平衡二叉树的左旋和右旋

AVLTree 高度平衡的搜索二叉树 一棵平衡树,或是空树,或是具有以下性质的二叉搜索树:左子树和右子树都是AVL树,且左右子树的高度之差的绝对值不超过1。 该二叉树,根结点的右子树高度为3,左子树高度为2。…

左右旋对比

目录 前言 一,逆置法 1.1逆置思路 1.2逆置实现 二,左旋和右旋对比 右旋代码分析 特点对比 前言 之前在up主的博客里面已经有过了对于左旋的三种实现方法。当然,如果我们考虑到时间复杂度的问题,那么我们只要一种方法&#xf…

平衡二叉树的左旋右旋详解 看不懂你打我

平衡二叉树的左旋右旋 看不懂你打我 左旋右旋的操作为什么要左旋右旋左旋右旋能保持排序二叉排序树的性质吗下次写平衡二叉树的LL、RR、LR、RL。 左旋右旋的操作 1.左旋:对X节点左旋,即以X的右孩子Y为轴,将X节点转下来,变为Y的左…

二叉树的旋转,左旋和右旋

在AVLTree中经常会有以某个节点为点对子树进行旋转的操作,今天就和大家分享一下什么是二叉树的旋转。 这是一棵二叉树,上图称为图一。 将图一中的树以1为旋转点进行左旋后得到图二: 将图一中的树以1为旋转点进行右旋旋后得到图三&#xff1…

day062:平衡二叉树——左旋、右旋

二叉树、平衡二叉树的介绍:day061:二叉树、二叉查找树、平衡二叉树_ZQyyds:)的博客-CSDN博客 目录 一、平衡二叉树的左旋 1.为什么要左旋、右旋? 2.什么是左旋? 3.图解 二、平衡二叉树的右旋 1.什么是…

大型json文件格式化【超简单】

问题 遇到了一个很大的JSON文件(约4M),想格式化查看,在线json工具会直接崩溃,网上其他同学说的python方法之类的我也都实验失败,但是发现了vs code中一个超强的代码格式化 解决1(2019.2.10更…

Unity存档系统——Json格式的文件

实例场景 点击Save按钮后,查看保存的文件 点击Load按钮后加载文档数据 Json介绍https://www.json.org/json-zh.htmlUnity中自带的JsonUtility可以将可序列化对象与Json格式相互转换。 将对象转为可序列化对象需要添加[SerializeField],且为public&#…

将json文件格式转化成Excel表格形式

在程序员的工作中,经常有产品或者运营部门的小姐姐需要数据,由于不懂技术,就需要我们将Json格式的数据转换成Excel文档提供给她们进行数据分析。 本文就介绍一个非常简单方便的方法 1.运用的是Excel表格自带的功能 首先打开Excel文件 点击插…

js导出JSON格式文件

在src目录下新建tools文件价,在tools文件中新建index.js(文件内名字随意) 在index.js文件中 const Tools {// 导出文件exportJson(name, data) {let blob new Blob([data]); // 创建 blob 对象let link document.createElement("a");link.href URL.…

json文件

认识一下 json文件 直接使用记事本打开:例如猫狗二分类 一般都使用类似字典的方式存储,但和字典不同,无论是键还是值,都要加上双引号。 json文件的读取与写入 import jsondata {"a":"1","b":&q…

JSON格式校验工具

经常用ApiPost 和 Postman 测试自己写的接口的话,有时会不小心写错传进去的json对象,我们可以用json格式检验工具去检查一下自己json格式。 在线工具:在线 JSON 工具,JSON 校验/格式化/压缩/工具 - 在线工具-wetools.com微工具

python文件处理——JSON格式文件

python文件处理——JSON格式文件 hello!我是wakeyo_J,每天一个konwledge point,一起学python,让技术无限发散。 JSON格式文件 python文件处理——JSON格式文件1. JSON格式1.1 JSON常用的两种结构数据类型1.2 JSON数据与python数据…