二叉平衡树左右双旋(思维导图大纲+图解 看不懂来砍我!!!)

2024-01-04 18:10

本文主要是介绍二叉平衡树左右双旋(思维导图大纲+图解 看不懂来砍我!!!),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

文章目录

    • 为什么要使用二叉平衡树?
    • 平衡树的定义
    • 思路大纲
      • 节点类
      • AVL树类
    • 什么时候需要左旋?
    • 什么时候需要右旋
    • 为什么要双旋?
    • 测试双旋方法
      • 完整代码放上

为什么要使用二叉平衡树?

为了降低树的高度 避免出现树退化成数组的形式
如这样
在这里插入图片描述

平衡树的定义

在这里插入图片描述
划重点
任意节点的子树的高度差都小于等于1
任意节点的子树的高度差都小于等于1
任意节点的子树的高度差都小于等于1

如果超过1 即为不平衡树 需要旋转了

思路大纲

在这里插入图片描述
图片保存下做个笔记哦

先看一下这两个类 为后面做准备

节点类

方法:

  1. 获取树的高度(重点掌握 递归求树的高度)
  2. 获取左子树高度
  3. 获取右子树高度
  4. 根据value值插入结点方法
  5. 遍历方法

获取树的高度

class Node {Node left;Node right;int value;/*** 获取树的高度*/public int getHeight() {return Math.max(left == null ? 0 : left.getHeight(), right == null ? 0 : right.getHeight()) + 1;}/*** 左子树可能为空** @return*/public int leftHeight() {if (left == null) {return 0;} else {return left.getHeight();}}/*** 右子树可能为空** @return*/public int rightHeight() {if (right == null) {return 0;} else {return right.getHeight();}}/*** 插入方法 判断插入的元素比根节点大还是小 小放左边 大放右边 为空直接作为根节点** @param node 待插入的节点*/public void add(Node node) {if (node == null) {return;}if (node.value < this.value) {//放左边if (this.left == null) {this.left = node;} else {this.left.add(node);}} else {//相等或大于就放右边if (this.right == null) {this.right = node;} else {this.right.add(node);}}}/*** 前序遍历方法*/public void preface() {System.out.print(this.value + " ");if (this.left != null) {this.left.preface();}if (this.right != null) {this.right.preface();}}/*** 中序遍历方法*/public void midface() {if (this.left != null) {this.left.midface();}System.out.print(this.value + " ");if (this.right != null) {this.right.midface();}}public Node(int value) {this.value = value;}@Overridepublic String toString() {return "Node{" +"value=" + value +'}';}
}

AVL树类

一系列遍历方法 重点放在节点类里

class AvlTree {Node root;/*** 二叉树添加节点方法 为空直接替换根节点** @param node*/public void add(Node node) {if (root == null) {root = node;} else {root.add(node);}}/*** 中序遍历树*/public void midlist() {if (root != null) {root.midface();System.out.println();}}/*** 前序遍历树*/public void prelist() {if (root != null) {root.preface();System.out.println();}}}

什么时候需要左旋?

在这里插入图片描述

如图 在没添加8节点前 还是一个平衡树 但添加过后

此时我们看到左子树的高度为1 右子树的高度为3

也就是右子树高度-左子树高度>1 超过1个单位时 我们就需要往左旋转 来保持平衡了

思路截一下图
在这里插入图片描述
配合图一起看
在这里插入图片描述

    /*** 左旋方法*/public void leftRotate() {Node newnode = new Node(value);//将新节点左子树设置为当前节点左子树newnode.left = left;//新节点右子树设置为当前节点右子树的左子树newnode.right = right.left;//root的值替换为他的右子节点的值value = right.value;//root的右边指向右子树的右子节点right = right.right;//root的左边指向新节点newnodeleft = newnode;}

注意 我们左旋方法的添加是在节点添加方法里实现的

即 每添加一个节点 就判断左右树的高度 所以不用担心后面的子树 子树的子树之类的情况哦!

左旋过后 该树平衡

	//add方法添加左旋代码//计算左子树的高度int l = leftHeight();//计算右子树的高度int r = rightHeight();//当他们高度相差2时 就需要旋转if (l - r > 1) {leftRotate();}

什么时候需要右旋

在这里插入图片描述
看图 此时添加6 该树不平衡了

也就是左子树高度-右子树高度>1 超过1个单位时 我们就需要往右旋转 来保持平衡了

在这里插入图片描述
在这里插入图片描述

/*** 右旋方法*/public void rightRotate() {Node newnode = new Node(value);newnode.right = right;newnode.left = left.right;value = left.value;left = left.left;right = newnode;}

同样的 也要在add方法里添加判断的条件

为什么要双旋?

看图
在这里插入图片描述
我们可以数一数 新的左右子树的 高度 发现是左边为3 右边为1 明显相差2 所以就引出了双旋

在这里插入图片描述
我们以10为根节点 判断如果左子树大于右子树 则右旋 否则左旋
在这里插入图片描述
在这里插入图片描述

这是整个add方法的步骤

  /*** 插入方法 判断插入的元素比根节点大还是小 小放左边 大放右边 为空直接作为根节点** @param node 待插入的节点*/public void add(Node node) {if (node == null) {return;}if (node.value < this.value) {//放左边if (this.left == null) {this.left = node;} else {this.left.add(node);}} else {//相等或大于就放右边if (this.right == null) {this.right = node;} else {this.right.add(node);}}//计算左子树的高度int l = leftHeight();//计算右子树的高度int r = rightHeight();//当他们高度相差2时 就需要旋转if (l - r > 1) {//双旋的情况 左子树的左子树的高度小于左子树的右子树的高度if (left.leftHeight() < left.rightHeight()) {//要将左子树左旋 再将整个树右旋left.leftRotate();rightRotate();} else {rightRotate();}}if (r - l > 1) {//双旋的情况 右子树的左子树的高度大于右子树的左子树的高度if (right.leftHeight() > right.rightHeight()) {//要将右子树右旋 再将整个树左旋right.rightRotate();leftRotate();} else {leftRotate();}}}

测试双旋方法

//对双旋做个测试  写入public static void main(String[] args) {int[] arr = {7, 6, 10, 9, 8, 11};AvlTree tree = new AvlTree();for (int i : arr) {tree.add(new Node(i));}System.out.println("整个树的高度为"+tree.root.getHeight());System.out.println("左子树高度为"+tree.root.leftHeight());System.out.println("右子树高度为"+tree.root.rightHeight());//前序tree.prelist();//中序tree.midlist();}
}

在这里插入图片描述
打印结果

整个树的高度为3
左子树高度为2
右子树高度为2
9 7 6 8 10 11
6 7 8 9 10 11

完整代码放上

package cn.bb.study;/*** @program: datastructure* @description: 平衡二叉树* @author: sharpbb* @create: 2020-10-29 08:11**/public class Demo {
//对双旋做个测试  写入public static void main(String[] args) {int[] arr = {7, 6, 10, 9, 8, 11};AvlTree tree = new AvlTree();for (int i : arr) {tree.add(new Node(i));}System.out.println("整个树的高度为"+tree.root.getHeight());System.out.println("左子树高度为"+tree.root.leftHeight());System.out.println("右子树高度为"+tree.root.rightHeight());//前序tree.prelist();//中序tree.midlist();}
}class AvlTree {Node root;/*** 二叉树添加节点方法 为空直接替换根节点** @param node*/public void add(Node node) {if (root == null) {root = node;} else {root.add(node);}}/*** 中序遍历树*/public void midlist() {if (root != null) {root.midface();System.out.println();}}/*** 前序遍历树*/public void prelist() {if (root != null) {root.preface();System.out.println();}}}class Node {Node left;Node right;int value;/*** 左旋方法*/public void leftRotate() {Node newnode = new Node(value);//将新节点左子树设置为当前节点左子树newnode.left = left;//新节点右子树设置为当前节点右子树的左子树newnode.right = right.left;value = right.value;right = right.right;left = newnode;}/*** 右旋方法*/public void rightRotate() {Node newnode = new Node(value);newnode.right = right;newnode.left = left.right;value = left.value;left = left.left;right = newnode;}/*** 左子树可能为空** @return*/public int leftHeight() {if (left == null) {return 0;} else {return left.getHeight();}}/*** 右子树可能为空** @return*/public int rightHeight() {if (right == null) {return 0;} else {return right.getHeight();}}/*** 获取树的高度*/public int getHeight() {return Math.max(left == null ? 0 : left.getHeight(), right == null ? 0 : right.getHeight()) + 1;}/*** 插入方法 判断插入的元素比根节点大还是小 小放左边 大放右边 为空直接作为根节点** @param node 待插入的节点*/public void add(Node node) {if (node == null) {return;}if (node.value < this.value) {//放左边if (this.left == null) {this.left = node;} else {this.left.add(node);}} else {//相等或大于就放右边if (this.right == null) {this.right = node;} else {this.right.add(node);}}//计算左子树的高度int l = leftHeight();//计算右子树的高度int r = rightHeight();//当他们高度相差2时 就需要旋转if (l - r > 1) {//双旋的情况 左子树的左子树的高度小于左子树的右子树的高度if (left.leftHeight() < left.rightHeight()) {//要将左子树左旋 再将整个树右旋left.leftRotate();rightRotate();} else {rightRotate();}}if (r - l > 1) {//双旋的情况 右子树的左子树的高度大于右子树的左子树的高度if (right.leftHeight() > right.rightHeight()) {//要将右子树右旋 再将整个树左旋right.rightRotate();leftRotate();} else {leftRotate();}}}/*** 前序遍历方法*/public void preface() {System.out.print(this.value + " ");if (this.left != null) {this.left.preface();}if (this.right != null) {this.right.preface();}}/*** 中序遍历方法*/public void midface() {if (this.left != null) {this.left.midface();}System.out.print(this.value + " ");if (this.right != null) {this.right.midface();}}public Node(int value) {this.value = value;}@Overridepublic String toString() {return "Node{" +"value=" + value +'}';}
}

ps:要多想 在那以前要多想

这篇关于二叉平衡树左右双旋(思维导图大纲+图解 看不懂来砍我!!!)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/570154

相关文章

图解TCP三次握手|深度解析|为什么是三次

写在前面 这篇文章我们来讲解析 TCP三次握手。 TCP 报文段 传输控制块TCB:存储了每一个连接中的一些重要信息。比如TCP连接表,指向发送和接收缓冲的指针,指向重传队列的指针,当前的发送和接收序列等等。 我们再来看一下TCP报文段的组成结构 TCP 三次握手 过程 假设有一台客户端,B有一台服务器。最初两端的TCP进程都是处于CLOSED关闭状态,客户端A打开链接,服务器端

图解可观测Metrics, tracing, and logging

最近在看Gophercon大会PPT的时候无意中看到了关于Metrics,Tracing和Logging相关的一篇文章,凑巧这些我基本都接触过,也是去年后半年到现在一直在做和研究的东西。从去年的关于Metrics的goappmonitor,到今年在排查问题时脑洞的基于log全链路(Tracing)追踪系统的设计,正好是对这三个话题的实践。这不禁让我对它们的关系进行思考:Metrics和Loggi

浙大数据结构:04-树7 二叉搜索树的操作集

这道题答案都在PPT上,所以先学会再写的话并不难。 1、BinTree Insert( BinTree BST, ElementType X ) 递归实现,小就进左子树,大就进右子树。 为空就新建结点插入。 BinTree Insert( BinTree BST, ElementType X ){if(!BST){BST=(BinTree)malloc(sizeof(struct TNo

颠覆你的开发模式:敏捷思维带来的无限可能

敏捷软件开发作为现代软件工程的重要方法论,强调快速响应变化和持续交付价值。通过灵活的开发模式和高效的团队协作,敏捷方法在应对动态变化和不确定性方面表现出色。本文将结合学习和分析,探讨系统变化对敏捷开发的影响、业务与技术的对齐以及敏捷方法如何在产品开发过程中处理持续变化和迭代。 系统变化对敏捷软件开发的影响 在敏捷软件开发中,系统变化的管理至关重要。系统变化可以是需求的改变、技术的升级、

写给大数据开发:你真的“慢“了吗?揭秘技术与职场的平衡艺术

你是否曾经在深夜里,面对着一个棘手的数据处理问题,感到无比沮丧?或者在一次重要的项目汇报中,突然语塞,无法清晰地表达你的技术方案?作为一名大数据开发者,这些场景可能再熟悉不过。但别担心,因为你并不孤单。让我们一起探讨如何在这个瞬息万变的行业中,既磨练技术利刃,又培养职场软实力。 目录 技术与时间的赛跑1. 长远视角的重要性2. 复利效应在技能学习中的应用 跨界思维:数据结构教我们的职场智

0906作业+思维导图梳理

一、作业: 1、创捷一个类似于qq登录的界面 1)源代码 #include "widget.h"#include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget){ui->setupUi(this);//QPushbutton:登录、退出this->join = new QP

【数据结构】排序算法系列——希尔排序(附源码+图解)

希尔排序 算法思想 希尔排序(Shell Sort)是一种改进的插入排序算法,希尔排序的创造者Donald Shell想出了这个极具创造力的改进。其时间复杂度取决于步长序列(gap)的选择。我们在插入排序中,会发现是对整体数据直接进行了统一的插入排序,每个数据之间的间隙是1,这里的1指的就是步长序列gap。在希尔排序中,我们会将整体数据一分为多份,进行散布式的插入排序,这时候每一个子序列之间的

[机缘参悟-222] - 系统的重构源于被动的痛苦、源于主动的精进、源于进化与演进(软件系统、思维方式、亲密关系、企业系统、商业价值链、中国社会、全球)

目录 前言:系统的重构源于被动的痛苦、源于主动的精进、源于进化与演进 一、软件系统的重构 1、重构的定义与目的 2、重构的时机与方法 3、重构的注意事项 4、重构的案例分析 二、大脑思维的重构 1、大脑思维重构的定义 2、大脑思维重构的方法 3、大脑思维重构的挑战与前景 三、认知的重构 1、定义 2、目的 3、方法 四、实例 五、总结 四、婚姻家庭的重构 1、婚

代码随想录 -- 二叉树 -- 平衡二叉树

110. 平衡二叉树 - 力扣(LeetCode) 思路:仍然是递归调用 1. 定义一个递归函数 count 用来计算二叉树的层数 2. isBalanced 函数:如果传入根节点为空返回真;如果根节点 | 左子树的层数 - 右子树的层数 | 大于1,返回假;最后返回根节点左子树、右子树是否是平衡二叉树。 class Solution(object):def count(self,root

算法图解(8~10贪心,动态规划,K最近邻算法)

贪心算法 在每一步都选择局部最优解,从而期望最终得到全局最优解。 贪心算法并不总能保证全局最优解,因此需要满足以下两个条件: 贪心选择性质:可以通过局部最优选择构造出全局最优解。最优子结构:问题的最优解包含其子问题的最优解。 实例:给定面额的硬币,用最少硬币凑出指定金额 int minCoins(vector<int>& coins, int amount) {int count = 0