Java中如何构建平衡二叉树

news2024/10/1 12:20:06

定义:平衡二叉树是一棵二叉排序树,或者为空,或者满足以下条件:

             1)左右子树高度差的绝对值不大于1;

             2)左右子树都是平衡二叉树。

平衡因子:左子树的高度减去右子树的高度,显然,在平衡二叉树中,每个结点的平衡因子的值为-1,0或1。

在Java中,构造平衡二叉树通常涉及到 AVL 树(Adelson-Velsky and Landis tree)的实现。AVL 树是一种自平衡二叉搜索树,它通过保持每个节点的左右子树高度差不超过1来保持平衡。

插入操作的可能情况:

        LL型:新插入结点在A的左孩子(L)的左子树(L)中;

        LR型:新插入结点在A的左孩子(L)的右子树(R)中;

        RL型:新插入结点在A的右孩子(R)的左子树(L)中;

        RR型:新插入结点在A的右孩子(R)的右子树(R)中。

LL型:右旋是指将一个节点的左子树变为其父节点,同时该节点成为其左子树的右子节点。右旋用于解决左子树过深的情况。

LR型:右左旋是先对当前节点的右子树进行右旋,然后再对当前节点进行左旋。这用于解决右子树的左子树过深的情况。

RL型:左右旋是先对当前节点的左子树进行左旋,然后再对当前节点进行右旋。这用于解决左子树的右子树过深的情况。

RR型:左旋是指将一个节点的右子树变为其父节点,同时该节点成为其右子树的左子节点。左旋用于解决右子树过深的情况。

以上都是基于左旋和右旋实现的,那么接下来我们构建左旋和右旋的方法以及插入数据对树结构所做操作:

对一组数据构建平衡二叉树:10、5、20、13、17、4

现在我们利用代码实现。

首先,需要创建一个 TreeNode 类,这个类除了包含节点值之外,还需要保存节点的高度:

public class TreeNode {
    int val;
    int height;
    TreeNode left;
    TreeNode right;

    public TreeNode(int val) {
        this.val = val;
        this.height = 1; // 初始高度为1
    }
}

然后,创建一个 AVL 树的实现类,其中包括插入操作和平衡操作:

public class AVLTree {

	private TreeNode root;

    // 获取节点的高度
    private int height(TreeNode node) {
        if (node == null) {
            return 0;
        }
        return node.height;
    }
    // 获取平衡因子
    private int getBalance(TreeNode node) {
        if (node == null) {
            return 0;
        }
        return height(node.left) - height(node.right);
    }
    // 更新节点的高度
    private void updateHeight(TreeNode node) {
        if (node != null) {
            node.height = Math.max(height(node.left), height(node.right)) + 1;
        }
    }
    // 右旋转
    private TreeNode rightRotate(TreeNode y) {
    	TreeNode x = y.left;
    	TreeNode T2 = x.right;
        // 执行旋转
        x.right = y;
        y.left = T2;
        // 更新高度
        updateHeight(y);
        updateHeight(x);
        return x;
    }

    // 左旋转
    private TreeNode leftRotate(TreeNode x) {
    	TreeNode y = x.right;
    	TreeNode T2 = y.left;
        // 执行旋转
        y.left = x;
        x.right = T2;
        // 更新高度
        updateHeight(x);
        updateHeight(y);
        return y;
    }

    // 插入节点
    public TreeNode insert(TreeNode node, int val) {
        if (node == null) {
            return new TreeNode(val);
        }
        // 执行标准的BST插入
        if (val < node.val) {
            node.left = insert(node.left, val);
        } else if (val > node.val) {
            node.right = insert(node.right, val);
        } else {
            // 重复的值不被允许
            return node;
        }
        // 更新节点的高度
        updateHeight(node);
        // 获取平衡因子
        int balance = getBalance(node);
        // 左子树的左侧插入,需要右旋转
        if (balance > 1 && val < node.left.val) {
            return rightRotate(node);
        }
        // 右子树的右侧插入,需要左旋转
        if (balance < -1 && val > node.right.val) {
            return leftRotate(node);
        }
        // 左子树的右侧插入,需要先左旋转再右旋转
        if (balance > 1 && val > node.left.val) {
            node.left = leftRotate(node.left);
            return rightRotate(node);
        }
        // 右子树的左侧插入,需要先右旋转再左旋转
        if (balance < -1 && val < node.right.val) {
            node.right = rightRotate(node.right);
            return leftRotate(node);
        }
        return node;
    }
    // 插入新节点,外部调用该方法
    public TreeNode insert(int val) {
        root = insert(root, val);
        //返回根节点
        return root;
    }
    
}

定义一个BinaryTreePrinter类,使用深度优先搜索来打印二叉树:

public class BinaryTreePrinter {
    public static void printTree(TreeNode root) {
        printTreeHelper(root, 0);
    }

    private static void printTreeHelper(TreeNode node, int depth) {
        if (node == null) {
            return;
        }
        // 打印右子树,使其显示在上方
        printTreeHelper(node.right, depth + 1);
        // 打印当前节点
        for (int i = 0; i < depth; i++) {
            System.out.print("    "); // 每层缩进四个空格
        }
        System.out.println(node.val);
        // 打印左子树,使其显示在下方
        printTreeHelper(node.left, depth + 1);
    }
}

在测试类Test中创建了一个 AVLTree 实例,并调用其方法来操作 AVL 树:

public class Test {
	public static void main(String[] args) {
        AVLTree avlTree =new AVLTree();
        // 构造一棵平衡二叉树      
        avlTree.insert(5);
        avlTree.insert(10);
        avlTree.insert(20);
        avlTree.insert(13);
        avlTree.insert(17);
        TreeNode root=avlTree.insert(12);
        
        System.out.println("平衡二叉树高度:"+root.height);
        BinaryTreePrinter.printTree(root);
    }
}

根节点为13,结果如下:

与构建结果相同。

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

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

相关文章

【C/PTA —— 12.指针1(课内实践)】

C/PTA —— 12.指针1&#xff08;课内实践&#xff09; 6-1 交换两个整数的值6-2 利用指针找最大值6-3 字符串的连接6-4 移动字母 6-1 交换两个整数的值 void fun(int* a, int* b) {int* tmp *a;*a *b;*b tmp; }6-2 利用指针找最大值 void findmax(int* px, int* py, int* p…

Find My键盘|苹果Find My技术与键盘结合,智能防丢,全球定位

键盘是最常用也是最主要的输入设备&#xff0c;通过键盘可以将英文字母、汉字、数字、标点符号等输入到计算机中&#xff0c;从而向计算机发出命令、输入数据等。还有一些带有各种快捷键的键盘。随着时间的推移&#xff0c;渐渐的市场上也出现独立的具有各种快捷功能的产品单独…

VS2010配置opencv2.4.10

1.下载opencv2.4.10&#xff0c;百度网盘链接如下&#xff1a; 链接&#xff1a;https://pan.baidu.com/s/1UdoQJbRUEB_G2urT703xYQ 提取码&#xff1a;7lbd 2.运行opencv-2.4.10.exe&#xff0c;将文件提取到一个自定义目录里&#xff1a; 3.添加系统环境变量 在“系统变量…

Webhook端口中的自签名身份验证

概述 有时&#xff0c;可能需要通过 Webhook 端口从交易伙伴处接收数据&#xff0c;但该交易伙伴可能需要更多的安全性&#xff0c;而不仅仅是用于验证入站 Webhook 请求的基本身份验证用户名/密码 – 或者您可能只想在入站 Webhook 消息上添加额外的安全层。 使用 Webhook 端…

Ubuntu新手使用教程

&#x1f337;&#x1f341; 博主猫头虎&#xff08;&#x1f405;&#x1f43e;&#xff09;带您 Go to New World✨&#x1f341; &#x1f984; 博客首页——&#x1f405;&#x1f43e;猫头虎的博客&#x1f390; &#x1f433; 《面试题大全专栏》 &#x1f995; 文章图文…

STM32_9(USART串口)

一、串口通信 串口是一种应用十分广泛的通讯接口&#xff0c;串口成本低、容易使用、通信线路简单&#xff0c;可实现两个设备的互相通信单片机的串口可以使单片机与单片机、单片机与电脑、单片机与各式各样的模块互相通信&#xff0c;极大地扩展了单片机的应用范围&#xff0…

前缀和算法总结

前缀和思维导图&#xff1a; 一维前缀和算法模版&#xff1a; #include <iostream>using namespace std;const int N 100010;int n, m; int s[N];int main() {scanf("%d%d", &n, &m);for (int i 1; i < n; i){int x;scanf("%d", &…

​无人机石油管道巡检方案新亮点:灵活准确又高效

在当前石油工业的安全管理中&#xff0c;无人机技术逐渐成为一种不可或缺的工具。随着我国油气管道里程的持续增长&#xff0c;确保这些关键基础设施的安全运行变得越来越重要。传统的巡检方法已经无法满足现代油气行业的需求&#xff0c;而无人机石油管道巡检技术的应用提供了…

相同JS代码,多次混淆加密能得到不同的结果吗?

一份相同的JavaScript代码&#xff0c;进行多次混淆加密&#xff0c;能得到不同的结果吗&#xff1f; 答案是肯定的&#xff0c;能。 JShaman可以实现这个效果。即&#xff1a;加密结果具有多态性、变化性。 下面实测展示。 来到JShaman网站&#xff0c;用它默认的示例代码…

计算机网络——数据链路层-数据链路层概述(介绍、三个重要问题、使用广播信道的数据链路层、其他问题)

目录 介绍 三个重要问题 封装成帧 差错检测 可靠传输 使用广播信道的数据链路层 其他问题 介绍 本篇对数据链路层进行概述&#xff0c;我们首先来看看数据链路层在网络体系结构中的地位&#xff1a; 主机H1给主机H2发送数据&#xff0c;中间要经过三个路由器和电话网、…

java选择排序和冒泡排序

1.区别 选择排序和冒泡排序的区别主要在于算法逻辑、稳定性和交换成本。 算法逻辑&#xff1a;选择排序和冒泡排序都属于比较排序&#xff0c;但在具体算法逻辑上有所不同。冒泡排序是通过相邻元素之间的比较和交换&#xff0c;将较大&#xff08;或较小&#xff09;的元素逐…

自动驾驶HWP功能规范

HWP功能规范 Highway Pilot Functional Specification 文件状态&#xff1a; 【√】草稿 【】正式发布 【】正在修改 文件起草分工 撰写&#xff1a; 审核&#xff1a; 编制&#xff1a; 签名&#xff1a; 日期&#xff1a; 审核&#xff1a; 签名&#xff1a; 日期&am…

Leetcode—739.每日温度【中等】

2023每日刷题&#xff08;四十二&#xff09; Leetcode—739.每日温度 单调栈实现思想 从右到左实现代码 class Solution { public:vector<int> dailyTemperatures(vector<int>& temperatures) {int n temperatures.size();stack<int> st;vector<i…

深度学习实战61-基于知识图谱与BiLSTM网络实现疾病相关智能问答系统,并支持数据扩展

大家好,我是微学AI,今天给大家介绍一下深度学习实战61-深度学习在医疗领域的应用:疾病相关智能问答系统,并支持数据扩展。本文将详细介绍如何使用Py2neo这个Python库来构建一个医疗领域知识图谱,并将数据导入Neo4j图数据库。我们将提供一些医疗领域的数据样例,并展示如何…

TIME_WAIT状态套接字重新使用

《TIME_WAIT相关知识》里边有相关理论知识。 《TIME_WAIT状态TCP连接导致套接字无法重用实验》有相关实验。 现代Linux的TCP协议栈已经做了许多升级&#xff0c;所以可以让我们直接重用TIME_WAIT状态套接字而不会引起问题。下边是优化的内容&#xff1a; 1.新连接的SYN告知序列…

原生代码布局

背景&#xff1a; 原生开发移动端&#xff0c;每一个页面的组成部分是哪些呢&#xff1f;在一个项目文件里&#xff0c;每一个页面的组成部分又是哪些呢&#xff1f;参考链接&#xff1a;pages页面的组成 效果展示&#xff1a; 注意&#xff1a; 一、布局代码&#xff1a; <…

33 - MySQL调优之索引:索引的失效与优化

不知道你是否跟我有过同样的经历&#xff0c;那就是作为一个开发工程师&#xff0c;经常被 DBA 叫过去“批评”&#xff0c;而最常见的就是申请创建新的索引或发现慢 SQL 日志了。 记得之前有一次迭代一个业务模块的开发&#xff0c;涉及到了一个新的查询业务&#xff0c;需要…

数据库应用:Ubuntu 20.04 安装MongoDB

目录 一、理论 1.MongoDB 二、实验 1.Ubuntu 20.04 安装MongoDB 三、问题 1.Ubuntu Linux的apt 包管理器更新安装软件报错 2.Ubuntu20.04安装vim报错 3.Ubuntu20.04如何更换阿里源 4.Ubuntu22.04如何更换阿里源 一、理论 1.MongoDB &#xff08;1&#xff09;概念 …

帆软报表 channel 反序列化漏洞复现

0x01 产品简介 FineReport、FineBI 是帆软软件开发的企业级报表设计和数据分析工具与商业智能平台。 0x02 漏洞概述 帆软FineReport、FineBI 存在反序列化漏洞&#xff0c;攻击者可向 /webroot/decision/remote/design/channel 接口发送精心构造的反序列化数据&#xff0c;在目…

2023.11.27【读书笔记】|医疗科技创新流程(前言)

目录 注重价值关键要素如何解决价值问题&#xff1f;注重三个关键点价值探索价值预测价值定位 中国视角背景挑战战术 洞察过程发现需求发现需求筛选 发明概念产生概念选择 发挥战略发展商业计划 注重价值 在美国&#xff0c;医疗费用的增长率已经多年超过GDP增长率&#xff1b…