数据结构:平衡二叉树

2023-09-17 09:23:32


平衡二叉树

一,概述

平衡二叉树,也称为AVL树,是一种特殊的二叉排序树,它的每个节点的左子树和右子树的高度差不超过1。平衡二叉树的定义可以概括为以下两点:

  1. 左子树和右子树的高度差绝对值不超过1。
  2. 左子树和右子树都是平衡二叉树。

平衡因子是平衡二叉树中的一个重要概念,它表示一个节点的左子树高度减去右子树的高度。根据平衡二叉树的定义,每个节点的平衡因子只能是-1、0或1。

当在一个平衡二叉排序树上插入一个新节点时,有可能导致失衡,即出现平衡因子绝对值大于1的节点。为了恢复平衡,可能需要对树进行调整。常见的调整方法包括旋转和重新平衡。

旋转分为四种类型:左旋、右旋、左右旋和右左旋。旋转操作是平衡二叉树调整中常用的方法,它的目的是通过改变节点的位置来满足平衡二叉树的定义。

总体来说,平衡二叉树是一种重要的数据结构,具有很好的查找和插入性能。它通过保持树的平衡,提高了操作的效率。

简介

  • 平衡二叉树是一种自我平衡的二叉搜索树,它的左子树和右子树的高度差不超过1。
  • 平衡二叉树的基本操作包括插入、删除和查找,这些操作的时间复杂度均为O(log n),其中n为树中节点的数量。
  • 平衡二叉树的主要应用场景包括计算机科学、数据结构和算法等领域。

图示

以下是一个简单的平衡二叉树图示:

      50
     / \
    30  70
   / \  / \
  10 40 60 80

在这个平衡二叉树中,每个节点的左子树和右子树的高度差都不超过1。

示例

以下是一个在Java中实现平衡二叉树的简单示例:

public class AVLTree {
    class Node {
        int key;
        Node left, right;
        int height;

        public Node(int item) {
            key = item;
            left = right = null;
            height = 1;
        }
    }

    Node root;

    AVLTree(int key) {
        root = new Node(key);
    }

    AVLTree() {
        root = null;
    }

    int height(Node node) {
        if (node == null) return 0;
        return node.height;
    }

    Node insert(Node node, int key) {
        if (node == null) return new Node(key);
        if (key < node.key) {
            node.left = insert(node.left, key);
        } else if (key > node.key) {
            node.right = insert(node.right, key);
        } else { // Duplicate keys not allowed
            return node;
        }
        node.height = 1 + Math.max(height(node.left), height(node.right));
        return node;
    }
}

在这个示例中,定义了一个内部类Node来表示平衡二叉树的节点。每个节点都有一个键key和两个子节点leftright,以及一个表示节点高度的属性height。还定义了两个方法heightinsertheight方法用于计算节点的高度,而insert方法则用于向平衡二叉树中插入一个新的节点。

二,添加数据

在Java中,平衡二叉树是一种常见的数据结构,它可以有效地组织和搜索数据。平衡二叉树是一种自我平衡的二叉搜索树,它的任何一个节点的左子树和右子树的高度差的绝对值不超过1。AVL树和红黑树是平衡二叉树的两种常见类型。

下面是一个示例,展示如何在平衡二叉树中添加数据:

首先,需要创建一个表示平衡二叉树节点的类:

// 定义平衡二叉树的节点类
public class TreeNode {
    int value;
    TreeNode left;
    TreeNode right;

    // 构造方法
    public TreeNode(int value) {
        this.value = value;
        this.left = null;
        this.right = null;
    }
}

然后,可以创建一个表示平衡二叉树的类,并添加一个方法来添加数据:

// 定义平衡二叉树类
public class AVLTree {
    TreeNode root;

    // 构造方法
    public AVLTree() {
        root = null;
    }

    // 添加数据的方法
    public void add(int value) {
        root = addRecursive(root, value);
    }

    // 递归添加数据的方法
    private TreeNode addRecursive(TreeNode current, int value) {
        if (current == null) {
            // 如果当前节点为空,则创建一个新节点作为根节点
            return new TreeNode(value);
        }

        // 根据值的大小决定添加到左子树还是右子树
        if (value < current.value) {
            current.left = addRecursive(current.left, value);
        } else if (value > current.value) {
            current.right = addRecursive(current.right, value);
        } else {
            // 如果值已经存在于树中,则不做任何操作
            return current;
        }

        // 更新当前节点的高度为左子树和右子树的最大高度+1
        current.height = 1 + Math.max(getHeight(current.left), getHeight(current.right));

        // 获取当前节点的平衡因子,检查是否失衡
        int balance = getBalance(current);

        // 如果当前节点失衡,则根据情况进行旋转操作
        if (balance > 1) {
            // 如果左子树的平衡因子大于1,则进行右旋操作
            return rightRotate(current);
        } else if (balance < -1) {
            // 如果右子树的平衡因子小于-1,则进行左旋操作
            return leftRotate(current);
        } else {
            // 如果平衡因子为0,则不做任何操作,返回当前节点指针
            return current;
        }
    }

    // 计算节点的高度的方法
    private int getHeight(TreeNode node) {
        if (node == null) {
            return 0;
        } else {
            return node.height;
        }
    }

    // 计算节点的平衡因子的方法(左子树高度-右子树高度)
    private int getBalance(TreeNode node) {
        if (node == null) {
            return 0;
        } else {
            return getHeight(node.left) - getHeight(node.right);
        }
    }
}

三,删除数据

在Java中,平衡二叉树是一种常见的数据结构,它可以有效地组织和搜索数据。平衡二叉树是一种自我平衡的二叉搜索树,它的任何一个节点的左子树和右子树的高度差的绝对值不超过1。AVL树和红黑树是平衡二叉树的两种常见类型。

下面是一个示例,展示如何在平衡二叉树中删除数据:

首先,需要创建一个表示平衡二叉树节点的类:

// 定义平衡二叉树的节点类
public class TreeNode {
    int value;
    TreeNode left;
    TreeNode right;

    // 构造方法
    public TreeNode(int value) {
        this.value = value;
        this.left = null;
        this.right = null;
    }
}

然后,可以创建一个表示平衡二叉树的类,并添加一个方法来删除数据:

// 定义平衡二叉树类
public class AVLTree {
    TreeNode root;

    // 构造方法
    public AVLTree() {
        root = null;
    }

    // 删除数据的方法
    public void remove(int value) {
        root = removeRecursive(root, value);
    }

    // 递归删除数据的方法
    private TreeNode removeRecursive(TreeNode current, int value) {
        if (current == null) {
            // 如果当前节点为空,则不做任何操作,返回null
            return null;
        }

        // 根据值的大小决定从左子树还是右子树中删除数据
        if (value < current.value) {
            current.left = removeRecursive(current.left, value);
        } else if (value > current.value) {
            current.right = removeRecursive(current.right, value);
        } else {
            // 如果值等于当前节点的值,则根据子节点的情况进行处理
            if (current.left == null && current.right == null) {
                // 如果当前节点没有子节点,则直接删除当前节点,返回null
                return null;
            } else if (current.left == null) {
                // 如果当前节点只有右子节点,则直接删除当前节点,并返回右子节点作为新的节点
                return current.right;
            } else if (current.right == null) {
                // 如果当前节点只有左子节点,则直接删除当前节点,并返回左子节点作为新的节点
                return current.left;
            } else {
                // 如果当前节点有两个子节点,则找到右子树中的最小节点作为新的节点,并删除该最小节点
                TreeNode minNode = findMinNode(current.right);
                current.value = minNode.value;
                current.right = removeRecursive(current.right, minNode.value);
            }
        }

        // 更新当前节点的高度为左子树和右子树的最大高度+1
        current.height = 1 + Math.max(getHeight(current.left), getHeight(current.right));

        // 获取当前节点的平衡因子,检查是否失衡
        int balance = getBalance(current);

        // 如果当前节点失衡,则根据情况进行旋转操作
        if (balance > 1) {
            // 如果左子树的平衡因子大于1,则进行右旋操作
            return rightRotate(current);
        } else if (balance < -1) {
            // 如果右子树的平衡因子小于-1,则进行左旋操作
            return leftRotate(current);
        } else {
            // 如果平衡因子为0,则不做任何操作,返回当前节点指针
            return current;
        }
    }

    // 计算节点的高度的方法
    private int getHeight(TreeNode node) {
        if (node == null) {
            return 0;
        } else {
            return node.height;
        }
    }

    // 计算节点的平衡因子的方法(左子树高度-右子树高度)
    private int getBalance(TreeNode node) {
        if (node == null) {
            return 0;
        } else {
            return getHeight(node.left) - getHeight(node.right);
        }
    }
    // 找到右子树中的最小节点的方法(递归)
    private TreeNode findMinNode(TreeNode node) {
        if (node == null) {
            return null;
        } else if (node.left == null) {
            return node;
        } else {
            return findMinNode(node.left);
        }
    }
}
更多推荐

Docker基础-namespace

Docker-namespacenamespace基础命令dd命令mkfsdfmountunsharepid隔离试验mount隔离namespacenamespace是Linux内核用来隔离内核资源的方式。通过namespace可以让一些进程只能看到与自己相关的一部分资源,而另外一些进程也只能看到与它们自己相关的资源,

Spark 框架概述

目录一、Spark是什么1.1统一分析引擎?二、Spark风雨十年​三、SparkVSHadoop(MapReduce)3.1面试题:Hadoop的基于进程的计算和Spark基于线程方式优缺点?四、Spark四大特点​4.1速度快4.2易于使用4.3通用性强​4.4运行方式五、Spark框架模块5.1介绍5.2Spar

Python+Selenium定位不到元素常见原因及解决办法(报:NoSuchElementException)

这篇文章主要介绍了Python+Selenium定位不到元素常见原因及解决办法(报:NoSuchElementException),文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧在做web应用的自动化测试时,定位元素是必不可少的,这个过程经常会碰到定

虹科分享 | 软件供应链攻击如何工作?如何评估软件供应链安全?

说到应用程序和软件,关键词是“更多”。在数字经济需求的推动下,从简化业务运营到创造创新的新收入机会,企业越来越依赖应用程序。云本地应用程序开发更是火上浇油。然而,情况是双向的:这些应用程序通常更复杂,使用的开放源代码比以往任何时候都包含更多的漏洞。此外,威胁行为者正在创造和使用更多的攻击方法和技术,通常是组合在一起的。

华为云云耀云服务器L实例评测|部署功能强大的监控和可视化工具Grafana

应用场景Grafana介绍Grafana是一个功能强大的监控和可视化工具,适用于各种行业和应用场景,如IT运维监控、网络监控、能源管理、金融市场分析等。它提供了灵活的数据源支持、强大的可视化功能和告警机制,以及注释和过滤功能,使得用户能够更好地理解和分析实时数据。下面的监控查询面板都是使用Grafana制作的。一个用于

Rust的注释与文档

rust中//!和///有什么区别?在Rust中,//!和///是特殊注释语法,用于文档注释(DocumentationComments)。它们用于编写文档,并生成Rust代码的API文档。//!用于编写模块级别的文档注释,通常放置在模块的开头。它允许您编写与整个模块相关的文档。这些注释会被Rust编译器解析,生成与模

zookeeper集群

一,zookeeper定义Zookeeper是一个开源的分布式的,为分布式框架提供协调服务的Apache项目。二,zookeeper工作机制Zookeeper从设计模式角度来理解:是一个基于观察者模式设计的分布式服务管理框架,它负责存储和管理大家都关心的数据,然后接受观察者的注册,一旦这些数据的状态发生变化,Zooke

论文笔记 DETR

detr摘要和引言2020论文facebook不需要proposal,不需要基于anchor的先验知识(比如预训练的模型),也不需要NMS进行筛选,直接端到端不需要后处理利用transformer的全局建模能力,看成集合预测问题,不会输出很多冗余的框,直接端到端,不需要NMS,简化了训练和部署NMS:非极大值抑制,抑制

Web3.0时代什么时候到来,Web3.0有什么机会?

🏆作者简介,黑夜开发者,CSDN领军人物,全栈领域优质创作者✌,CSDN博客专家,阿里云社区专家博主,2023年6月CSDN上海赛道top4。🏆数年电商行业从业经验,历任核心研发工程师,项目技术负责人。🎉欢迎👍点赞✍评论⭐收藏文章目录🚀一、前言🚀二、Web1.0-Web3.0🔎2.1Web1.0:信息的获

穿越时空的创新:解析云原生与Web3.0的奇妙渊源

🌷🍁博主猫头虎带您GotoNewWorld.✨🍁🦄博客首页——猫头虎的博客🎐🐳《面试题大全专栏》文章图文并茂🦕生动形象🦖简单易学!欢迎大家来踩踩~🌺🌊《IDEA开发秘籍专栏》学会IDEA常用操作,工作效率翻倍~💐🌊《100天精通Golang(基础入门篇)》学会Golang语言,畅玩云原生,走遍大

Web3.0实战(02)-联盟链入门讲解

联盟链是介于公有链和私有链之间,具备部分去中心化的特性。联盟链是由若干机构联合发起,由盟友共同来维护,它只针对特定某个群体的成员和有限的第三方开放。8.1部分去中心化联盟链只属于联盟内部的成员所有,联盟链的节点数是有限所以容易达成共识。8.2可控性较强公有链是一旦区块链形成,将不可篡改,这主要源于公有链的节点一般是海量

热文推荐