数据结构中常见的树

news/2024/11/28 6:51:07/

二叉树:每个子节点只有两个节点的树,每个结点至多拥有两棵子树(即二叉树中不存在度大于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, Kkey, 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-rlp.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-rlp.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.ppmy.cn/news/83686.html

相关文章

【从零开始写视觉SLAM】v0.1基于特征点的简单VO

v0.1版本的oSLAM实现了基于orb特征点的简单视觉里程计&#xff0c;通过连续两帧的rgbd数据实现相机相对位姿的估计。 #mermaid-svg-ibQfHFVHezQD5RWW {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-ibQfHFVHezQD5RW…

字段信息 详解,以易举例,创建数据库,程序自动创建数据库的前提,程序读写数据库的第一步

今天要做一个处理比较多数据的工具&#xff0c;就是桌面小软件&#xff0c;重新收拾起以前的易语言来编写&#xff0c;C#等也可以&#xff0c;反正就是最后的成品是绿色免安装。 数据多&#xff0c;优先考虑的就是数据库操作了&#xff0c;又快又好是吧&#xff1f; 第一步&am…

遍历 globals() 时必不可少的 RuntimeError

文章目录 参考描述globals() 函数For Loop 过程中产生的迭代变量Runtime Errordictionary changed size during iteration异常产生原因解决方案copy 方法绕过 RuntimeError 产生 RuntimeError 异常的基本要求遍历 locals() 时可能产生的 RuntimeError 参考 项目描述Python 官方…

HR不会告诉你!Java程序员月薪8K和20K的区别!

昨天有同学问好程序员&#xff0c;为啥都是干Java程序员&#xff0c;别人可以拿20k&#xff0c;我才拿8k呢&#xff1f;为啥人家能提前转正我就得晚俩月&#xff1f;小源一听大事不妙&#xff0c;赶紧连夜整理了以下清单供大家check&#xff01; 对于刚入职场还有跳槽成功的同学…

NRK3303语音识别芯片在照明灯上的运用,一款可分布式语音IC方案

随着科技的不断进步&#xff0c;人们对于家居生活中的照明设备的要求也逐渐提高。传统的照明方式已经不能满足人们对智能家居的需求&#xff0c;我们需要更加智能、易于操作、高效节能的智能化照明系统。因此&#xff0c;智能照明应运而生&#xff0c;为我们提供了更加智能化、…

Java Swing 快速入门

Java Swing 快速入门 文章目录 Java Swing 快速入门一、Java Swing 简单介绍1、Java Swing 介绍2、Java Swing 使用步骤3、Java Swing 组件二、Java Swing 简单使用案例1、Hello World 程序2、一个用户登录框实例三、附录1、概念解析2、Swing 的坐标图一、Java Swing 简单介绍 …

【LeetCode】字符串转换整数 (atoi) [M](模拟)

8. 字符串转换整数 (atoi) - 力扣&#xff08;LeetCode&#xff09; 一、题目 请你来实现一个 myAtoi(string s) 函数&#xff0c;使其能将字符串转换成一个 32 位有符号整数&#xff08;类似 C/C 中的 atoi 函数&#xff09;。 函数 myAtoi(string s) 的算法如下&#xff1a…

第十二章 异常(Exception)

一、异常的概念&#xff08;P444&#xff09; Java 语言中&#xff0c;将程序执行中发生的不正常情况称为“异常”。&#xff08;开发过程中的语法错误和逻辑错误不是异常&#xff09; 执行过程中所发生的异常事件可分为两大类&#xff1a; &#xff08;1&#xff09;Error&…