数据结构中常见的树

news2025/1/11 10:49:36

二叉树:每个子节点只有两个节点的树,每个结点至多拥有两棵子树(即二叉树中不存在度大于2的结
点),并且,二叉树的子树有左右之分,其次序不能任意颠倒
在这里插入图片描述
我们一般在解题过程中二叉树有两种主要的形式:满二叉树和完全二叉树。

满二叉树

满二叉树:如果一棵二叉树只有度为0的结点和度为2的节点,并且度为0的节点在同一层上,则这棵二叉树为满二叉树。
如图所示:
在这里插入图片描述
这棵二叉树为满二叉树,也可以说深度为k,有2^k-1个节点的二叉树。

完全二叉树

完全二叉树的定义如下:在完全二叉树中,除了最底层节点可能没填满外,其余每层节点数都达到最大值,并且最下面一层的节点都集中在该层最左边的若干位置。若最底层为第 h 层,则该层包含 1~ 2^(h-1) 个节点。
在这里插入图片描述

二叉树遍历操作

二叉树中的遍历规则有如下三种:
前序遍历:所谓的前序遍历就是先访问根节点,再访问左节点,最后访问右节点,即根-左-右遍历(前序)
中序遍历:所谓的中序遍历就是先访问左节点,再访问根节点,最后访问右节点,即左-根-右遍历
后序遍历:所谓的后序遍历就是先访问左节点,再访问右节点,最后访问根节点。即左-右-根遍
在这里插入图片描述
查找最小值:沿着根节点的左子树一路查找,直到最后一个不为空的节点,该节点就是当前这个树的最
小节点
查找最大值:沿着根节点的右子树一路查找,直到最后一个不为空的节点,该节点就是当前这个树的最
大节点
查找前驱节点:小于当前节点的最大值
查找后继节点:大于当前节点的最小值
在这里插入图片描述
删除节点
二叉树中的删除节点:本质上是找前驱节点或者后继节点来替代

  • 叶子节点直接删除
  • 只有一个子节点的用子节点替代(本质上就是找的前驱节点或者后继节点,左节点就是前驱节点,右
    节点就是后继节点)
  • 有两个子节点的,需要找到替代节点(替代节点就是前驱节点或者后继节点)

二叉搜索树

前面介绍的树,都没有数值的,而二叉搜索树是有数值的了,二叉搜索树是一个有序树

  • 若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值;
  • 若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值;
  • 它的左、右子树也分别为二叉排序树
    下面这两棵树都是搜索树
    在这里插入图片描述
    但是 一个二叉搜索树是由n个节点随机构成,所以,对于某些情况,二叉搜索树会退化成一个有n个节点的线
    性链.如下图
    在这里插入图片描述

平衡二叉搜索树

平衡二叉搜索树:又被称为AVL(Adelson-Velsky and Landis)树,且具有以下性质:它是一棵空树或它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一棵平衡二叉树。
如图:
在这里插入图片描述
最后一棵 不是平衡二叉树,因为它的左右两个子树的高度差的绝对值超过了1。

2-3-4树

2-3-4树是四阶的 B树(Balance Tree),他属于一种多路查找树,它的结构有以下限制:
所有叶子节点都拥有相同的深度。
节点只能是 2-节点、3-节点、4-节点之一。

  • 2-节点:包含1个元素的节点,有2个子节点
  • 3-节点:包含2个元素的节点,有3个子节点
  • 4-节点:包含3个元素的节点,有4个子节点

所有节点必须至少包含1个元素
元素始终保持排序顺序,整体上保持二叉查找树的性质,即父结点大于左子结点,小于右子结点;
而且结点有多个元素时,每个元素必须大于它左边的和它的左子树中元素。
如图所示:
在这里插入图片描述
2-3-4树的查询操作像普通的二叉搜索树一样,非常简单,但由于其结点元素数不确定,在一些编程
语言中实现起来并不方便,实现一般使用它的等同——红黑树

2-3-4树生成过程

第一次插入—2节点
在这里插入图片描述
插入第二个节点–3节点 合并

在这里插入图片描述
插入第三个节点—4节点 合并
在这里插入图片描述
插入第4个节点—需要分裂
在这里插入图片描述
插入6
在这里插入图片描述
插入7
在这里插入图片描述
插入8
在这里插入图片描述
插入9
在这里插入图片描述
插入10

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

插入12
在这里插入图片描述
最后插入1
在这里插入图片描述

和红黑树的等价关系

红黑树起源于2-3-4树,它的本质就是2-3-4树。
2节点
一个2节点对应的红黑树节点就是一个黑色节点
在这里插入图片描述
3节点
一个三节点可以有两种情况的红黑树节点,一种是右倾,一种是左倾,所以一个2-3-4树可以有多个红黑

在这里插入图片描述
原则 上黑下红
4节点
一个四节点转换的情况只有一种,中间节点黑色,左右节点红色
在这里插入图片描述
裂变状态
还有就是在2-3-4树中存在的裂变状态。转换为红黑树后会先变色(不能有两个相邻的红色节点)
在这里插入图片描述

转换为红黑树

2-3-4树是如何转换为对应的红黑树的?
原始的2-3-4树
在这里插入图片描述
按照右倾规则来转换为
在这里插入图片描述
转换后满足黑色节点平衡的要求

按照左倾规则来转换为
在这里插入图片描述

红黑树

红黑树,Red-Black Tree 「RBT」是一个自平衡(不是绝对的平衡)的二叉查找树(BST),树上的每个节点
都遵循下面的规则:

  1. 每个节点要么是黑色,要么是红色。
  2. 根节点是黑色。
  3. 每个叶子节点(NIL)是黑色。
  4. 每个红色结点的两个子结点一定都是黑色。
  5. 任意一结点到每个叶子结点的路径都包含数量相同的黑结点。

红黑树能自平衡,它靠的是什么?三种操作:左旋、右旋和变色

操作描述
左旋以某个结点作为支点(旋转结点),其右子结点变为旋转结点的父结点,右子结点的左子结点变为旋转结点的右子结点,左子结点保持不变。
右旋以某个结点作为支点(旋转结点),其左子结点变为旋转结点的父结点,左子结点的右子结点变为旋转结点的左子结点,右子结点保持不变。
变色结点的颜色由红变黑或由黑变红

旋转操作

左旋:以某个节点作为旋转点,其右子节点变为旋转节点的父节点,右子节点的左子节点变为旋转节点的右子节点,左子节点保持不变。
在这里插入图片描述
右旋:以某个节点作为旋转点,其左子节点变为旋转节点的父节点,左子节点的右子节点变为旋转节点的左子节点,右子节点保持不变。
在这里插入图片描述
代码实现:
类结构定义

public class BRTree {
    private static final boolean RED = false;
    private static final boolean BLACK = true;
    private RBNode root;
    public RBNode getRoot() {
        return root;
    }
    public void setRoot(RBNode root) {
        this.root = root;
    }
    /**
     * 表示 节点
     * @param <K>
     * @param <V>
     */
    static class RBNode<K extends Comparable<K>,V>{
        // 节点是双向的
        private RBNode parent;
        private RBNode left;
        private RBNode right;
        private boolean color;
        private K key;
        private V value;
        public RBNode() {
        }
        public RBNode(RBNode parent, RBNode left, RBNode right, boolean color, K
                key, V value) {
            this.parent = parent;
            this.left = left;
            this.right = right;
            this.color = color;
            this.key = key;
            this.value = value;
        }
        public RBNode getParent() {
            return parent;
        }
        public void setParent(RBNode parent) {
            this.parent = parent;
        }
        public RBNode getLeft() {
            return left;
        }
        public void setLeft(RBNode left) {
            this.left = left;
        }
        public RBNode getRight() {
            return right;
        }
        public void setRight(RBNode right) {
            this.right = right;
        }
        public boolean isColor() {
            return color;
        }
        public void setColor(boolean color) {
            this.color = color;
        }
        public K getKey() {
            return key;
        }
        public void setKey(K key) {
            this.key = key;
        }
        public V getValue() {
            return value;
        }
        public void setValue(V value) {
            this.value = value;
        }
    }
}

左旋代码实现

  /**
     * 实现左旋
     * p                 pr
     * / \               / \
     * pl  pr     ==>   p   rr
     * / \             / \
     * rl rr          pl  rl
     * 左旋操作:
     * p-pl 和pr -rr的关系不需要调整
     * 需要调整的情况
     * 1.pr-rl 调整为 p-rl
     * 将rl变为p的右子节点
     * 将p设置为rl的父节点
     * 2. 判断p是否右父节点
     * 有:
     * pr.parent=p.parent
     * pr为p.parent的子节点,到底是左子节点还是右子节点呢?
     * if(p.parent.left==p)
     * p.parent.left=pr
     * else{
     * P.parent.right=r
     * }
     * 没有:
     * 直接把pr设置为root节点
     * 3.最后p和pr交换
     * p.parent=pr
     * pr.left=p
     *
     * @param p
     */
    private void leftRotate(RBNode p) {

        if (p != null) {
            //获取到了pr节点
            RBNode pr = p.right;
            //情况1:pr-rl调整为p-rl
            p.right = pr.left;
            if (pr.left != null) {
                pr.left.parent = p;
            }
            //情况2:判断P节点是否有父节点
            pr.parent = p.parent;//不管是否存在父节点,我们都设置P的父节点也为pr的父节点
            if (p.parent == null) {
                //说明P就是root节点,这时pr会变成新的root节点
                root = pr;
            } else if (p.parent.left == p) {   //说明p存在父节点
                //说明p是父节点的左子节点,那么pr也肯定是p的父节点的左子节点
                p.parent.left = pr;
            } else {
                p.parent.right = pr;
            }
            //情况3:设置p为pr的左子节点
            pr.left = p;
            p.parent = pr;
        }

    }

右旋代码实现

 private void rightRotate(RBNode p) {

        if (p != null) {
            //获取到了pr节点
            RBNode pr = p.left;
            //情况1:pr-rl调整为p-rl
            p.left = pr.right;
            if (pr.right != null) {
                pr.right.parent = p;
            }
            //情况2:判断P节点是否有父节点
            pr.parent = p.parent;//不管是否存在父节点,我们都设置P的父节点也为pr的父节点
            if (p.parent == null) {
                //说明P就是root节点,这时pr会变成新的root节点
                root = pr;
            } else if (p.parent.left == p) {   //说明p存在父节点
                //说明p是父节点的左子节点,那么pr也肯定是p的父节点的左子节点
                p.parent.left = pr;
            } else {
                p.parent.right = pr;
            }
            //情况3:设置p为pr的左子节点
            pr.right = p;
            p.parent = pr;
        }
    }

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

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

相关文章

徐延涛:医疗健康企业如何重构客户管理的“营销”与“服务”?

随着人口老龄化和生活健康水平的提升&#xff0c;中国的医疗健康行业市场规模前景向好。《2023易凯资本中国健康产业白皮书》显示&#xff0c;从2022年到2030年的八年里&#xff0c;中国健康产业的整体规模将从10万亿元增长到接近20万亿&#xff0c;年复合增长率将达到9.5%-10%…

TS入门(TS类型有哪些?怎么使用?)

TS简介 TS&#xff08;TypeScript&#xff09;是一种由微软开发的开源编程语言&#xff0c;它是 JavaScript 的超集&#xff0c;能够为 JavaScript 添加静态类型检查和面向对象编程的特性。TS 可以在编译时进行类型检查&#xff0c;从而提高代码的可读性、可维护性和可靠性&am…

PMP课堂模拟题目及解析(第12期)

111. 客户拒绝了一项交付成果&#xff0c;因为它不符合约定的质量规格&#xff0c;项目团队调查该问题&#xff0c;并确定供应商提供的零件有问题&#xff0c;供应商拒绝纠正这种情况。项目经理应该审查什么&#xff1f; A. 与供应商订立的服务水平协议 B. 采购管理计划和合…

从领英退出中国,解析融云《社交泛娱乐出海作战地图》从0到1出海方法论

近期&#xff0c;“领英职场”宣布将于 2023 年 8 月 9 日起正式停止服务。移步【融云全球互联网通信云】回复“地图”免费领 一时之间&#xff0c;网友纷纷送上祭文。有人觉得猝不及防&#xff0c;但更多人直言并不意外。 领英在中国的折戟终局&#xff0c;似乎从 2021 年改版…

chatgpt赋能python:PythonSave函数:保存和保护你的数据

Python Save函数&#xff1a;保存和保护你的数据 Python Save函数是Python编程中最常用的函数之一。它允许开发者将数据保存到文件或数据库中&#xff0c;在未来的操作中访问和使用。无论你是处理大数据集还是需要保护数据免受未经授权访问&#xff0c;Python Save函数都可以为…

Hegegraph的Gremlin语言(全)

Hegegraph的Gremlin语言&#xff08;全&#xff09; 内容 • 基本概念 • Step讲解 • HugeGraph特有Gremlin语句&#xff08;schema相关&#xff09;基本概念 • Gremlin • 是一门图的查询语言&#xff0c;地位作用与数据库的 SQL相当 • 支持图数据的增、删、改、查 • 图…

鸿蒙Hi3861学习十九-DevEco Device Tool源码获取、编译、下载

一、简介 在上一篇文章中&#xff0c;已经讲述了如何在Windows通过Remote SSH远程连接Linux下的DevEco Device Tool。这篇文章&#xff0c;来说一下关于源码的获取、编译与下载。建议先按照上一篇文章进行环境搭建。 鸿蒙Hi3861学习十八-DevEco Device Tool环境搭建_t_guest的…

运动员最佳配对问题——算法设计与分析(C实现)

目录 一、问题简述 二、分析 三、代码展示 四、结果验证 一、问题简述 问题描述&#xff1a;羽毛球队有男女运动员各n人。给定2个n*n矩阵P和Q。P[i][j]是男运动员i和女运动员j配对组成混合双打的男运动员竞争优势&#xff1b;Q[i][j]是男运动员i和女运动员j配合的女运动员竞…

msvcr110.dll丢失的解决方法,多种方法助你解决msvcr110.dll丢失

当您在尝试打开某个程序或游戏时&#xff0c;可能会看到一个错误消息&#xff0c;提示您的计算机缺少msvcr110.dll文件。这是因为该文件是Microsoft Visual C Redistributable库的一部分&#xff0c;缺少它可能会导致应用程序无法正常运行。在本文中&#xff0c;我们将详细介绍…

【接口测试】JMeter接口关联测试

‍‍1 前言 我们来学习接口管理测试&#xff0c;这就要使用到JMeter提供的JSON提取器和正则表达式提取器了&#xff0c;下面我们来看看是如何使用的吧。 2 JSON提取器 1、添加JSON提取器 在线程组右键 > 添加 > 后置处理器 > JSON提取器 2、JSON提取器参数说明 N…

19-03 基于业务场景的架构技术选型

Java架构师系列导航目录 金融领域的挑战与架构设计 金融领域的方向 借贷保险证券交易 互联网金融 vs 传统金融 满足更广泛群体的金融需求增强金融普惠性提高金融服务效率 互联网金融前景 近十年蓬勃发展&#xff0c;朝阳行业&#xff1a;花呗、借呗、微粒贷、余额宝双刃剑&am…

【案例教程】基于“遥感+”蓝碳储量估算、红树林信息提取实践技术应用与科研论文写作

光谱和图像是人们观察世界的两种方式&#xff0c;高光谱遥感通过“图谱合一”的技术创新将两者结合起来&#xff0c;大大提高了人们对客观世界的认知能力&#xff0c;本来在宽波段遥感中不可探测的物质&#xff0c;在高光谱遥感中能被探测。以高光谱遥感为核心&#xff0c;构建…

动态远程桌面如何用来做爬虫

爬虫需要动态IP主要是为了避免被目标网站封禁或限制访问。如果使用固定IP进行爬取&#xff0c;很容易被目标网站识别出来并封禁&#xff0c;导致无法继续爬取数据。而使用动态IP可以让爬虫在不同的IP地址之间切换&#xff0c;降低被封禁的风险。此外&#xff0c;动态IP还可以帮…

Ebay、亚马逊高低单价产品如何打造?自养号测评策略解析

很多卖家都认为低单价产品太卷了&#xff0c;于是选择了进入了高单价细分类目&#xff0c;一进入&#xff0c;发现广告竞价高到自己无法接受&#xff0c;转化还特别差&#xff0c;然后一直在挣扎中。眼下整个跨境市场&#xff0c;无论是高单价产品&#xff0c;还是低单价产品&a…

redis-server源码

1 redis主流程 redis启动流程: 1 加载配置&#xff1b;2 初始化redis master、slave以及sentinel的sri&#xff1b;3 注册事件事件serverCron。 <span style"background-color:#f5f2f0"><span style"color:black"><span style"color:…

WebRTC学习笔记01——最简单实现一对一视频通讯

最近开始学习WebRTC音视频通讯技术&#xff0c;这里来分享一下学习的内容和感受。 学习WebRTC的门槛稍微高那么一点点&#xff0c;需要同时具备服务端和前端的开发能力&#xff0c;因为我主要是做java服务端开发&#xff0c;这里我用到的服务端代码也是java编写的。 在写代码…

阿里组织架构迎来巨变!拆分为六大业务,或可分别独立上市

“16N”组织调整是阿里巴巴“24年来最重要的一次组织变革”&#xff0c;六大业务集团及业务公司可以独立融资或独立上市&#xff0c;意味着阿里的整体估值将得到大幅提升。 马云回国、阿里巴巴宣布启动“16N”组织调整、具备条件的业务集团和公司将独立上市……一系列有关阿里…

jetcache参考文档

jetcache简介 https://github.com/alibaba/jetcache/blob/master/docs/CN/GettingStarted.md 简介 JetCache是一个基于Java的缓存系统封装&#xff0c;提供统一的API和注解来简化缓存的使用。 JetCache提供了比SpringCache更加强大的注解&#xff0c;可以原生的支持TTL、两级…

SpringBoot + Docker 实现一次构建到处运行

一、容器化部署的好处 Docker 作为一种新兴的虚拟化方式&#xff0c;它可以更高效的利用系统资源&#xff0c;不需要进行硬件虚拟以及运行完整操作系统等额外开销。 传统的虚拟机技术启动应用服务往往需要数分钟&#xff0c;而 Docker 容器应用&#xff0c;由于直接运行宿主内…

javaweb实验:Java Web综合应用开发__基于MVC模式

目录 前言实验目的实验原理实验内容实验过程项目结构代码实现Java代码controller层AddNewsServlet类DeletrNewsServlet类LoginServlet类LogoutServlet类QueryAllNewsServlet类QueryNewsServlet类RegisterServlet类UpdateNewsServlet类 dao层NewsDao类UserDao类 daoimpl层NewsDa…