数据结构-树详解

树简介

树存储和组织具有层级结构的数据(例:公司职级),就是一颗倒立生长的树。
属性:

  • 递归
  • n个节点有n-1个连接
  • 节点x的深度:节点x到根节点的最长路径
  • 节点x的高度:节点x到叶子节点的最长路径
    在这里插入图片描述

二叉树

完美、完全、平衡二叉树

二叉树:每个节点最多有两个子节点(左孩子,有孩子)。在第i层最多有2i个节点。
完美二叉树、完全二叉树查看之前文章
平衡二叉树:空树或左子树和右子树高度差不超过1
请添加图片描述
 
二叉树在内存中的存储方式:

  • 动态创建节点
  • 数组
    请添加图片描述

二叉树高度实现

求二叉树高度的实现方式:计算左右子树高度取较大者+1
在这里插入图片描述

class TreeNode{int data;TreeNode left;TreeNode right;public TreeNode(int data){this.data = data;this.left = null;this.right = null;}
}
public class DataStruct {//高度public int findHight(TreeNode root){if (root == null){return -1;}return Math.max(findHight(root.left),findHight(root.right))+1;}//遍历public static void main(String[] args) {DataStruct ds = new DataStruct();TreeNode root = new TreeNode(1);root.left = new TreeNode(2);root.left.left = new TreeNode(4);root.left.right = new TreeNode(5);root.left.right.left = new TreeNode(8);root.left.right.right = new TreeNode(9);root.right = new TreeNode(3);root.right.left = new TreeNode(6);root.right.right = new TreeNode(7);System.out.println(ds.findHight(root));}
}

二叉树遍历实现

树的遍历算法两类:广度优先(同一层级,下图举例即 F,D,J,B,E,G,K,A,C,I,H)、深度优先(左子树、根节点、右子树 三者顺序可变)
深度优先:前序遍历—根节点-左子树-右子树(F,D,B,A,C,E,J,G,I,H,K)
                  中序遍历—左子树-根节点-右子树(A,B,C,D,E,F,G,H,I,J,K)
                  后续遍历—左子树-右子树-根节点(A,C,B,E,D,H,I,G,K,J,F)

在这里插入图片描述

广度优先使用队列来实现:取出节点的同时,让他的孩子入队。f(n)=O(n),S(n)=O(1)最好情况,S(n)=O(n)最坏情况。
在这里插入图片描述

import java.util.LinkedList;
import java.util.Queue;
class TreeNode{char data;TreeNode left;TreeNode right;public TreeNode(char data){this.data = data;this.left = null;this.right = null;}
}
public class DataStruct {//广度优先public void levelOrder(TreeNode root){if (root == null){return;}Queue<TreeNode> queue = new LinkedList<>();queue.add(root);while (!queue.isEmpty()){TreeNode poll = queue.poll();System.out.print(poll.data + " ");if (poll.left != null){queue.add(poll.left);}if (poll.right != null){queue.add(poll.right);}}return;}//深度优先public void preOrder(TreeNode root){if(root == null){return;}System.out.print(root.data + " ");preOrder(root.left);preOrder(root.right);}public void inOrder(TreeNode root){if(root == null){return;}inOrder(root.left);System.out.print(root.data + " ");inOrder(root.right);}public void postOrder(TreeNode root){if(root == null){return;}postOrder(root.left);postOrder(root.right);System.out.print(root.data + " ");}public static void main(String[] args) {DataStruct ds = new DataStruct();TreeNode root = new TreeNode('F');root.left = new TreeNode('D');root.left.left = new TreeNode('B');root.left.right = new TreeNode('E');root.left.left.left = new TreeNode('A');root.left.left.right = new TreeNode('C');root.right = new TreeNode('J');root.right.left = new TreeNode('G');root.right.right = new TreeNode('K');root.right.left.right= new TreeNode('I');root.right.left.right.left = new TreeNode('H');System.out.println("广度优先:");ds.levelOrder(root);System.out.println();System.out.println("前序遍历:");ds.preOrder(root);System.out.println();System.out.println("中序遍历:");ds.inOrder(root);System.out.println();System.out.println("后序遍历:");ds.postOrder(root);}
}

二叉搜索树

概述

搜索:用数组、链表进行搜索耗时O(n)。如果是已排序的数组,用二分查找(可查看之前算法文章)耗时O(logn)。

数据结构数组链表二分查找二叉搜索树
搜索O(n)O(n)O(logn)O(logn)
插入O(1)O(1)O(n)O(logn)
删除O(n)O(n)O(n)O(logn)

二叉搜索树:对于任意节点,左子树上的所有节点值都小于它,右子树上的所有节点值都大于它,并且这种性质在每个子树上都递归成立。
请添加图片描述
二叉搜索树搜索时间复杂度O(logn)原理:每次比较不是往左就是往右,每次数量都会减少一半,跟二分查找同理。但需要注意二叉搜索树需要是平衡的,否则时间复杂度>O(logn),下图最坏情况是O(n)
在这里插入图片描述

查找最小值和最大值

根据二叉搜索树的特性,最小值一定在左边,最大值一定在右边

class TreeNode{int data;TreeNode left;TreeNode right;public TreeNode(int data){this.data = data;this.left = null;this.right = null;}
}
public class DataStruct {//迭代写法public int findMin(TreeNode root){TreeNode temp = root;while (temp!=null && temp.left!=null){temp=temp.left;}return temp.data;}//递归写法public int findMin1(TreeNode root){TreeNode temp = root;if (temp==null){return -1;}if (temp.left==null){return temp.data;}return findMin1(temp.left);}public static void main(String[] args) {DataStruct ds = new DataStruct();TreeNode root = new TreeNode(15);root.left = new TreeNode(10);root.left.left = new TreeNode(8);root.left.right = new TreeNode(12);root.right = new TreeNode(20);root.right.left = new TreeNode(17);root.right.right = new TreeNode(25);System.out.print(ds.findMin(root));}
}

判断是否是二叉搜索树

对于isSubTreeGreater,isSubTreeLesser也可以换种思路,即寻找最大最小值与父节点比较。
进一步优化:舍去比较大小的递归函数,而采用传入该节点的数据范围的参数来进行比较。
另一种方法:二叉搜索树的中序遍历是排序好的,也可以检查中序遍历结果是否排序好了。

class TreeNode{int data;TreeNode left;TreeNode right;public TreeNode(int data){this.data = data;this.left = null;this.right = null;}
}
public class DataStruct {public boolean isSubTreeLesser(TreeNode root,int data){if (root == null){return true;}if (root.data <= data && isSubTreeLesser(root.left, data) && isSubTreeLesser(root.right, data)){return true;}return false;}public boolean isSubTreeGreater(TreeNode root,int data){if (root == null){return true;}if (root.data>=data && isSubTreeGreater(root.left, data) && isSubTreeGreater(root.right, data)){return true;}return false;}public boolean isBinaryTree(TreeNode root){if(root == null){return true;}if (isSubTreeLesser(root.left, root.data) && isSubTreeGreater(root.right, root.data)&& isBinaryTree(root.left) && isBinaryTree(root.right)){return true;}return false;}public boolean isBinaryTree1(TreeNode root,int min,int max){if(root == null){return true;}if (root.data < max && root.data > min && isBinaryTree1(root.left,min,root.data) && isBinaryTree1(root.right,root.data,max)){return true;}return false;}public static void main(String[] args) {DataStruct ds = new DataStruct();TreeNode root = new TreeNode(7);root.left = new TreeNode(4);root.left.left = new TreeNode(1);root.left.right = new TreeNode(6);root.right = new TreeNode(9);System.out.println(ds.isBinaryTree(root));System.out.println(ds.isBinaryTree1(root,Integer.MIN_VALUE,Integer.MAX_VALUE));}
}

二叉搜索树查询、插入、删除实现

在这里插入图片描述

class TreeNode{int data;TreeNode left;TreeNode right;public TreeNode(int data){this.data = data;this.left = null;this.right = null;}
}
public class DataStruct {public TreeNode insert(TreeNode root, int data){if (root == null){return new TreeNode(data);}if (data<=root.data){root.left=insert(root.left,data);}else {root.right=insert(root.right,data);}return root;}public boolean search(TreeNode root, int data){if (root == null){return false;}if (data==root.data){return true;}if (data<root.data){return search(root.left,data);}else {return search(root.right,data);}}public TreeNode deleteNode(TreeNode root, int data){if (root == null){return null;}if (data<root.data){root.left=deleteNode(root.left,data);}else if (data>root.data){root.right=deleteNode(root.right,data);}else {//要删除的节点是叶子节点if (root.left==null && root.right==null){return null;}//要删除的节点只有一个子节点if (root.left==null){return root.right;//用右节点替代当前节点}if (root.right==null){return root.left;}//要删除的节点有两个节点,需要用子节点替换当前被删除的节点,然后删除子节点//此子节点要么是右子树中的最小值,要么是左子树中的最大值TreeNode minNode = root.right;while (minNode.left!=null){minNode = minNode.left;}root.data=minNode.data;root.right=deleteNode(root.right,minNode.data);}return root;}public void inOrder(TreeNode root){if(root == null){return;}inOrder(root.left);System.out.print(root.data + " ");inOrder(root.right);}   public static void main(String[] args) {DataStruct ds = new DataStruct();TreeNode root = null;root=ds.insert(root,15);root=ds.insert(root,10);root=ds.insert(root,20);root=ds.insert(root,8);root=ds.insert(root,12);root=ds.insert(root,17);root=ds.insert(root,25);ds.inOrder(root);System.out.print("\n");System.out.println(ds.search(root,12));System.out.println(ds.search(root,19));ds.deleteNode(root,15);ds.inOrder(root);}
}

寻找某个节点的中序后继节点

二叉搜索树的中序遍历结果是已排序的。中序后继节点就是排序好的数据中某个节点的下一个数据是什么。如果使用中序遍历找后继节点时间复杂度O(n)。

优化:

  • 某节点有右子树,后继节点=右子树的最小值。
  • 某节点无右子树,后继节点=最近祖先节点(前提:某节点一定位于祖先节点的左子树上)。(为了存储父祖先,需要从跟节点走到指定节点)

10后继=11,6后继=8,12后继=15
在这里插入图片描述

class TreeNode{int data;TreeNode left;TreeNode right;public TreeNode(int data){this.data = data;this.left = null;this.right = null;}
}
public class DataStruct {public TreeNode getSuccessor(TreeNode root, TreeNode p){if (root == null){return null;}if (p.right != null){return findMin(p.right);}else {TreeNode successor = null;TreeNode temp = root;while (temp != p){if (p.data<temp.data){successor = temp;temp = temp.left;}else {temp=temp.right;}}return successor;}}public TreeNode findMin(TreeNode root){TreeNode temp = root;while (temp!=null && temp.left!=null){temp=temp.left;}return temp;}public static void main(String[] args) {DataStruct ds = new DataStruct();TreeNode root = new TreeNode(15);root.left = new TreeNode(10);root.left.left = new TreeNode(8);root.left.right = new TreeNode(12);root.left.left.left = new TreeNode(6);root.left.right.left = new TreeNode(11);root.right = new TreeNode(20);root.right.left = new TreeNode(17);root.right.right = new TreeNode(25);root.right.left.left = new TreeNode(16);root.right.right.right = new TreeNode(27);System.out.println(ds.getSuccessor(root,root.left.right).data);}
}

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

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

相关文章

【安卓Sensor框架-2】应用注册Sensor 流程

注册传感器的核心流程为如下&#xff1a;应用层调用 SensorManager注册传感器&#xff0c;framework层创建SensorEventQueue对象&#xff08;事件队列&#xff09;&#xff0c;通过JNI调用Native方法nativeEnableSensor()&#xff1b;SensorService服务端createEventQueue()创建…

新版本没有docker-desktop-data分发 | docker desktop 镜像迁移

在新版本的docker desktop中&#xff08;如4.42版本&#xff09;&#xff0c;镜像迁移只需要更改路径即可。如下&#xff1a; 打开docker desktop的设置&#xff08;图1&#xff09;&#xff0c;将图2的原来的地址C:\Users\用户\AppData\Local\Docker\wsl修改为你想要的空文件…

EtherCAT SOEM源码分析 - ec_init

ec_init SOEM主站一切开始的地方始于ec_init, 它是EtherCAT主站初始化的入口。初始化SOEM 主站&#xff0c;并绑定到socket到ifname。 /** Initialise lib in single NIC mode* param[in] ifname Dev name, f.e. "eth0"* return >0 if OK* see ecx_init*/ in…

84、原理解析-SpringApplication创建初始化流程

84、原理解析-SpringApplication初始化流程 # SpringApplication创建初始化流程原理解析 SpringApplication的创建和初始化是Spring Boot应用启动的关键步骤&#xff0c;主要包括以下过程&#xff1a; ## 1. 创建SpringApplication实例 ### 1.1 调用构造函数 - 当调用SpringApp…

【数理逻辑】 选择公理与集值映射

目录 选择公理1. 有限指标集 I I I2. 可数无限指标集 I I I &#xff08;简称为 ACC 或 ACω&#xff09;3. 不可数无限指标集 I I I4. 选择公理的层级与数学应用5. 选择公理的深层意义 集值映射的选择函数1. 选择公理的核心作用2. 不同情况下的依赖性分析3. AC 的必要性证明…

微信小程序使用wx.chooseImage上传图片时进行压缩,并添加时间水印

在微信小程序的开发过程&#xff0c;经常会使用自带的api(wx.chooseImage)进行图片拍照或选择图片进行上传&#xff0c;有时图片太大&#xff0c;造成上传和下载时过慢&#xff0c;现对图片进行压缩后上传&#xff0c;以下是流程和代码 一、小程序的版本选择了3.2.5&#xff0…

RAII简介

&#x1f4e6; 一、技术原理简介&#xff1a;RAII是个“托管狂魔” 想象你有个健忘的朋友&#xff0c;每次借东西都会忘记归还。RAII&#xff08;Resource Acquisition Is Initialization&#xff0c;资源获取即初始化&#xff09;就是C派来的“超级管家”&#xff1a; “你负…

微信小程序入门实例_____打造你的专属单词速记小程序

上次通过天气查询小程序&#xff0c;我们初探了微信小程序开发的世界。这次&#xff0c;咱们再挑战一个有趣又实用的项目 ——“单词速记小程序”。无论是学生党备考&#xff0c;还是上班族提升英语&#xff0c;都能用得上&#xff01;接下来就跟着我&#xff0c;一步一步把它做…

gateway白名单存储nacos,改成存储数据库

前言 很久没写博客了&#xff0c;csdn都开始ai润色了&#xff0c;之前都是看相应框架的源码看了个遍&#xff0c;感觉底层原理都差不多&#xff0c;这阵子着手改造了下gateway中的白名单&#xff0c;之前白名单存储到nacos&#xff0c;要改成存到数据库。里面涉及到浅浅的源码…

ubentu服务器版本安装Dify

Docker 中安装Dify 首先安装Docker 1. 克隆Dify代码仓库 从github克隆 Dify 源代码至要本地环境。 我的ubentu服务器版本&#xff0c;我把源代码下载到 /var/下 在var文件夹下执行 git clone https://github.com/langgenius/dify.git执行成功后&#xff0c;进入Dify源代码的…

Redis分布式锁实战:从入门到生产级方案

目录 一、为什么需要分布式锁&#xff1f; 二、Redis分布式锁核心特性 三、实现方案与代码详解 方案1&#xff1a;基础版 SETNX EXPIRE 原理 代码示例 问题 方案2&#xff1a;Redisson框架&#xff08;生产推荐&#xff09; 核心特性 代码示例 优势 方案3&#xff…

【Redis】StringRedisTemplate 和 RedisTemplate 的区别

StringRedisTemplate 和 RedisTemplate 是 Spring Data Redis 提供的两种用于操作 Redis 的模板类&#xff0c;它们的核心区别在于 序列化方式 和 操作的数据类型。以下是两者的主要区别和使用建议&#xff1a; ✅ 1. 数据类型支持 类名支持的数据类型说明RedisTemplate支持所…

docker-compose快速搭建redis集群

目录结构 redis-cluster/ ├── config/ │ ├── master.conf │ ├── slave1.conf │ └── slave2.conf └── docker-compose.yml配置文件内容 1. config/master.conf # Redis主节点配置 port 6379 bind 0.0.0.0 protected-mode no logfile "redis-mas…

SpringCloud系列(39)--SpringCloud Gateway常用的Route Predicate

前言&#xff1a;在上一节中我们实现了SpringCloud Gateway的动态路由 &#xff0c;而在本节中我们将着重介绍各种Route Predicate的作用。 1、可以到官方文档里查看常用的Route Predicate的种类 https://cloud.spring.io/spring-cloud-static/spring-cloud-gateway/2.2.1.REL…

渐变色的进度条控件

近日&#xff0c;用VB.net2003重写了一个渐变色的进度条控件。主要有以下功能&#xff1a; 支持自定义进度条分段数量&#xff0c;可拆分为多个步骤&#xff1b;每个步骤可独立显示完成百分比及渐变色效果。 每个步骤均可配置任务名称和描述&#xff1b;运行时能实时显示当前执…

【DICOM后处理】qt+vs 实现DICOM数据四视图显示

目录 1、DICOM四视图2、vtkImageViewer2 实现二维平面图显示3、vtkVolume实现三维体数据显示4、实现界面图 1、DICOM四视图 DICOM四视图通常指同时显示医学影像的四个不同平面或视角&#xff0c;用于全面分析三维数据&#xff08;如CT、MRI等&#xff09;。 标准四视图布局&a…

Google Maps 安装使用教程

一、Google Maps 简介 Google Maps 是谷歌提供的地图服务&#xff0c;通过其 JavaScript API&#xff0c;开发者可以在网页中嵌入地图&#xff0c;添加标记、路径、地理编码、路线导航等功能&#xff0c;适用于位置展示、物流追踪、LBS 应用等场景。 二、获取 Google Maps API…

Nginx+Keepalived实现前台服务高可用

现阶段项目开发往往采用前后台分离&#xff0c;前台常用的技术有vue、react等&#xff0c;前台代码部署在nginx中&#xff0c;代码中配置了后台服务的网关地址&#xff0c;由网关向后台分发服务请求&#xff0c;架构示意图如下&#xff1a; 在上述架构图中&#xff0c;如果Ngin…

Gradio全解13——MCP协议详解(5)——Python包命令:uv与uvx实战

Gradio全解13——MCP协议详解&#xff08;5&#xff09;——Python包命令&#xff1a;uv与uvx实战 第13章 MCP协议详解13.5 Python包命令&#xff1a;uv与uvx实战13.5.1 uv核心亮点与常用命令1. uv介绍2. 安装与项目管理3. 脚本与工具4. Python版本与pip接口 13.5.2 uv核心指令…

OD 算法题 B卷【求最小步数】

文章目录 求最小步数 求最小步数 求从坐标零点到坐标点n的最小步数&#xff0c;一次只能沿着横坐标轴向左或向右移动2或3&#xff1b;途经的坐标点可以为负数&#xff1b; 输入描述: 坐标点n 输出描述: 从坐标零点移动到坐标点n的最小步数 n在【1,10^9】 示例1 输入&#xf…