Java数据结构-树的面试题

目录

一.谈谈树的种类

二.红黑树如何实现

三.二叉树的题目

 1.求一个二叉树的高度,有两种方法。

2.寻找二叉搜索树当中第K大的值

3、查找与根节点距离K的节点

4.二叉树两个结点的公共最近公共祖先


本专栏全是博主自己收集的面试题,仅可参考,不能相信面试官就出这种题目。

一.谈谈树的种类

        树,最为常见的是二叉树,而在二叉树的基础上,又衍生了很多具有特性的二叉树。

1.二叉树

        每个结点最多有两个子节点,为左节点和右节点

2.二叉搜索树

        一种特殊的二叉树,左子树的节点值一定小于右子树的节点值,右子树的节点都大于根节点的值。 

3.平衡二叉树

        一种特殊的二叉树,也称AVL树,左右子树高度差不超过1。

4.红黑树

        特殊的二叉搜索树,名 平衡的二叉搜索树(平衡是指,结构稳定),通过节点的颜色保持平衡。根节点是黑色,空节点为黑色,从任一节点到其每个叶子节点的所有路径上不能有两个连续的红色节点,任一节点到其每个叶子节点的路径都包含相同数目的黑色节点。

5.B树和B+树

标题图片来源于B站蓝不过海博主

        B树是一种平衡的多路搜索树,广泛用于数据库和文件系统当中,和二叉树不同。

特点:

  • 每个节点可以有多个子节点。
  • 节点中的键值按顺序排列,使得范围查询等操作更加高效。
  • 所有叶子节点都在同一层级,这保证了查找操作的稳定性能。
  • 内部节点存储键值和指向子节点的指针,叶子节点存储键值和实际数据的指针。

        B+树与B树的结构很相似,是在B树基础上进行的扩展和优化,也是一种自平衡的树结构,B+树经常用于数据库的索引结构,不同处:

  • 所有的数据都存储在叶子节点中,而非像B树那样部分数据存储在内部节点。并且以链表的形式存在。
  • 由于所有数据都存储在叶子节点且有序排列,B+树支持高效的范围查询(Range Query)和顺序访问。
  • B+树的内部节点只存储键值和指向子节点的指针,而叶子节点之间通过链表连接,这样的结构使得范围查询更为高效。

6.Trie树

标题图片来源于csdn的啊啊啊安博主

        一种树形结构,典型应用是用于统计,排序和保存大量的字符串(但不仅限于字符串,如01字典树)。主要思想是利用字符串的公共前缀来节约存储空间。很好地利用了串的公共前缀,节约了存储空间。字典树主要包含两种操作,插入查找

7.堆

        堆是一种结构类似树形结构,通常实现优先队列,有最大堆和最小堆两种形式。

二.红黑树如何实现

        节点结构:每个节点包含关键字(key),颜色(红或黑),指向左子节点和右子节点的指针,以及指向父节点的指针。叶子节点通常被视为NIL节点,它们是黑色的。

        颜色规则:根节点为黑色,叶子节点都是黑色,一个节点是红色,那么子节点为黑色。

        路径规则:任一节点到其每个叶子节点的所有路径都包含相同数目的黑色节点,最短路径和最长路径不会相差超过2倍。

        插入规则:插入节点默认为红色,

  • 插入结点是根节点,直接变黑
  • 插入结点的叔叔是红色,叔父爷结点都变色,爷爷变插入结点
  • 插入结点的叔叔是黑色,判断(LL,RR,LR,RL)进行旋转,然后变色。        

        删除规则:

        讲不清楚,可以去看B站红黑树讲解:https://www.bilibili.com/

三.二叉树的题目

 1.求一个二叉树的高度,有两种方法。

        第一种是递归;第二种是迭代。

// 求二叉树高度的函数
public class BinaryTreeHeight {public int getHeight(TreeNode root) {if (root == null) {return 0;} else {int leftHeight = getHeight(root.left);int rightHeight = getHeight(root.right);// 返回左右子树中较大的高度,并加上根节点的高度1return Math.max(leftHeight, rightHeight) + 1;}}//层序遍历public int getHeight2(TreeNode root) {if (root == null) {return 0;}Queue<TreeNode> queue = new LinkedList<>();queue.offer(root);int height = 0;while (!queue.isEmpty()) {int levelSize = queue.size(); // 当前层的节点数量// 遍历当前层的所有节点,并将它们的子节点加入队列for (int i = 0; i < levelSize; i++) {TreeNode node = queue.poll();if (node.left != null) {queue.offer(node.left);}if (node.right != null) {queue.offer(node.right);}}// 每遍历完一层,高度加一height++;}return height;}public static void main(String[] args) {// 创建一个示例二叉树TreeNode root = new TreeNode(1);root.left = new TreeNode(2);root.right = new TreeNode(3);root.left.left = new TreeNode(4);root.left.right = new TreeNode(5);// 计算二叉树的高度BinaryTreeHeight btHeight = new BinaryTreeHeight();int height = btHeight.getHeight(root);System.out.println("Binary Tree Height: " + height); // 输出高度}
}

2.寻找二叉搜索树当中第K大的值

思路:二叉搜索树(BST)的后序遍历实际是对树节点的升序排列。所以同第一题,有递归法和迭代法实现BST的中序遍历,遍历后再逆序,返回第k个最大值。

递归法实现中序遍历:中序遍历,可以得到二叉搜索树从小到大排序,那么逆中序遍历,并且设置一个变量result,每一次遍历,都增一,当result等于K时,则得出结果!

class TreeNode {int val;TreeNode left;TreeNode right;TreeNode(int x) {val = x;}
}public class KthLargestInBST {private int count;private int result;public int kthLargest(TreeNode root, int k) {count = 0;result = 0;reverseInOrder(root, k);return result;}private void reverseInOrder(TreeNode node, int k) {if (node == null || count >= k) {return;}// 递归右子树reverseInOrder(node.right, k);// 访问当前节点count++;if (count == k) {result = node.val;return; // 提前结束递归}// 递归左子树reverseInOrder(node.left, k);}public static void main(String[] args) {// 创建一个示例二叉搜索树TreeNode root = new TreeNode(5);root.left = new TreeNode(3);root.right = new TreeNode(8);root.left.left = new TreeNode(2);root.left.right = new TreeNode(4);root.right.left = new TreeNode(6);root.right.right = new TreeNode(10);int k = 3; // 寻找第三大的值KthLargestInBST solution = new KthLargestInBST();int kthLargest = solution.kthLargest(root, k);System.out.println("The " + k + "th largest element in BST is: " + kthLargest); // 输出结果}
}

3、查找与根节点距离K的节点

        直接深度优先遍历(DFS)或者广度优先遍历(BFS)

广度优先搜索(BFS)+队列:我们可以在遍历每一层节点时,将该节点的子节点加入队列(size--控制循环),并记录它们的距离。当距离等于K时,将该节点的值存储起来。

深度优先搜索(DFS)+栈:使用一个栈来存储当前节点和距离的信息。在每次循环中,取出栈顶元素,检查当前距离是否等于K,如果是,则将该节点的值存储到结果数组中。然后,将当前节点的子节点按照右子节点先入栈,左子节点后入栈,并将距离加1。这样,我们可以确保在深度优先搜索中,离根节点更远的节点会在栈中先被访问。

class TreeNode {int val;TreeNode left;TreeNode right;TreeNode(int x) {val = x;}
}public class NodesAtDistanceK {public List<Integer> findNodesAtDistanceK(TreeNode root, int K) {List<Integer> result = new ArrayList<>();findNodesAtDistanceK(root, K, result);return result;}private int findNodesAtDistanceK(TreeNode node, int K, List<Integer> result) {if (node == null) return -1; // 如果节点为空,返回 -1 表示找不到目标距离 K 的节点if (K == 0) {result.add(node.val); // 当 K 为 0,说明当前节点就是目标节点return 0;}// 递归左子树,在左子树中查找距离 K 的节点int leftDistance = findNodesAtDistanceK(node.left, K - 1, result);if (leftDistance != -1) {// 如果找到目标节点,当前节点距离根节点的距离就是 leftDistance + 1if (leftDistance + 1 == K) {result.add(node.val);} else {// 否则,继续在右子树中查找剩余距离的节点findNodesAtDistanceK(node.right, K - leftDistance - 2, result);}return leftDistance + 1; // 返回左子树中目标距离 K 的节点距离}// 递归右子树,在右子树中查找距离 K 的节点int rightDistance = findNodesAtDistanceK(node.right, K - 1, result);if (rightDistance != -1) {// 如果找到目标节点,当前节点距离根节点的距离就是 rightDistance + 1if (rightDistance + 1 == K) {result.add(node.val);} else {// 否则,继续在左子树中查找剩余距离的节点findNodesAtDistanceK(node.left, K - rightDistance - 2, result);}return rightDistance + 1; // 返回右子树中目标距离 K 的节点距离}return -1; // 如果左右子树都找不到目标距离 K 的节点,返回 -1}public static void main(String[] args) {// 创建示例二叉树TreeNode root = new TreeNode(3);root.left = new TreeNode(5);root.right = new TreeNode(1);root.left.left = new TreeNode(6);root.left.right = new TreeNode(2);root.left.right.left = new TreeNode(7);root.left.right.right = new TreeNode(4);root.right.left = new TreeNode(0);root.right.right = new TreeNode(8);NodesAtDistanceK solution = new NodesAtDistanceK();int K = 2;List<Integer> nodesAtDistanceK = solution.findNodesAtDistanceK(root, K);System.out.println("Nodes at distance " + K + " from root: " + nodesAtDistanceK);}
}

4.二叉树两个结点的公共最近公共祖先

思路:使用递归。

方法一:假设,如上图的二叉树,我们需要查出2,0的最近公共祖先,我们可以通过后序遍历搭配栈使用,得出 从根节点到2的路径 3->5->2  和从根结点到0的路径   3->1->0 通过路径相比,我们可以得出3是他们最近的公共结点

方法二:从根节点开始递归搜索:

  • 如果当前节点是 null,或者等于 p 或 q,则直接返回当前节点。
  • 递归地在左子树和右子树中搜索节点 p 和节点 q

根据左右子树的搜索结果,判断以下几种情况:

  • 如果左子树和右子树分别找到了 p 和 q,说明当前节点就是它们的最近公共祖先。
  • 如果只在左子树找到了 p 或 q,则说明公共祖先必定在左子树。
  • 如果只在右子树找到了 p 或 q,则说明公共祖先必定在右子树。
public class LowestCommonAncestor {public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {// 如果根节点为空,直接返回nullif (root == null) return null;// 如果根节点是其中一个目标节点,直接返回根节点if (root == p || root == q) return root;// 在左子树中查找p和q的最近公共祖先TreeNode leftLCA = lowestCommonAncestor(root.left, p, q);// 在右子树中查找p和q的最近公共祖先TreeNode rightLCA = lowestCommonAncestor(root.right, p, q);// 如果左右子树分别找到了p和q,则当前节点是最近公共祖先if (leftLCA != null && rightLCA != null) {return root;}// 如果只有一边找到了最近公共祖先,则返回那个节点return (leftLCA != null) ? leftLCA : rightLCA;}public static void main(String[] args) {// 创建示例二叉树TreeNode root = new TreeNode(3);root.left = new TreeNode(5);root.right = new TreeNode(1);root.left.left = new TreeNode(6);root.left.right = new TreeNode(2);root.left.right.left = new TreeNode(7);root.left.right.right = new TreeNode(4);root.right.left = new TreeNode(0);root.right.right = new TreeNode(8);LowestCommonAncestor solution = new LowestCommonAncestor();TreeNode p = root.left.left;TreeNode q = root.left.right.left;TreeNode lca = solution.lowestCommonAncestor(root, p, q);System.out.println("Lowest Common Ancestor of " + p.val + " and " + q.val + " is: " + lca.val);}
}

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

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

相关文章

pandas,dataframe使用笔记

目录 新建一个dataframe不带列名带列名 dataframe添加一行内容查看dataframe某列的数据类型新建dataframe时设置了列名&#xff0c;则数据类型为object dataframe的保存保存为csv文件保存为excel文件 dataframe属于pandas 新建一个dataframe 不带列名 df pd.DataFrame() 带…

gda动态调试-cnblog

忽的发现gda有动态调试功能 动态监听返回值 框柱指定方法&#xff0c;选择调试方法&#xff0c;gda会自动监听函数的返回值&#xff0c;例如 自定义frida脚本 gda会自动生成hook该函数的frida脚本

SpringBoot学习06-[SpringBoot与AOP、SpringBoot自定义starter]

SpringBoot自定义starter SpringBoot与AOPSpringBoot集成Mybatis-整合druid在不使用启动器的情况下&#xff0c;手动写配置类进行整合使用启动器的情况下,进行整合 SpringBoot启动原理源码解析创建SpringApplication初始化SpringApplication总结 启动 SpringBoot自定义Starter定…

matplotlib下载安装

matplotlib下载安装过程同之前写的pygame很类似。 Pygame下载安装 python官网 1.搜索matplotlib 直接点进去 查看历史版本&#xff0c;因为新版本可能出现与python不匹配问题。 我选择3.6.3版本&#xff0c;因为我安装的python是3.8&#xff0c;可以匹配版本。同时window操…

Android - 模拟器

Android SDK 包括一个在您的计算机上运行的虚拟移动设备模拟器。 该模拟器可让您在不使用物理设备的情况下对 Android 应用程序进行原型设计、开发和测试。 在本章中&#xff0c;我们将探索真实安卓设备中存在的模拟器中的不同功能。 创建 AVD 如果您想模拟真实设备&#xff0c…

赋能心理大模型,景联文科技推出高质量心理大模型数据库

生成式大模型作为当前发展势头最为强劲的人工智能前沿技术&#xff0c;其在临床心理学领域中的创新应用已成为社会关注和医学聚焦的热点之一。 心理大模型在落地应用过程中可能面临的痛点主要包括以下几个方面&#xff1a; 数据隐私与安全&#xff1a;确保敏感的个人信息在模型…

第一次的pentest show总结

第一次的pentest show总结 前言 开始之前&#xff0c;我特别感谢TryHackMe(英)、HackTheBox(美)、zero-point security(英)、offsec(美)等平台&#xff0c;使我们能够通过网络以线上的方式学习与练习&#xff0c;打破传统线下各地区教育资源差异大的限制&#xff0c;对网络教…

磁钢生产领域上下料解决方案

随着智能制造技术的不断革新&#xff0c;磁钢生产领域正逐步引入自动化生产线。然而&#xff0c;传统的人工上下料方式存在诸多问题&#xff0c;难以满足现代生产需求。富唯智能提出了一款复合机器人磁钢上下料解决方案&#xff0c;通过先进的自动化技术&#xff0c;提高生产效…

海量设备集中运维,向日葵远程控制赋能农牧产品加工产业链

产业规模越大&#xff0c;单位成本就越低&#xff0c;这是一个广泛存在的商业规律。 在诸多行业中&#xff0c;农牧业的这种“规模效应”尤为明显&#xff0c;这使得在农牧行业内逐渐发展出许多横跨产业链上下游的大型企业集团&#xff0c;业务甚至覆盖相关产业设备的设计与生…

【Odoo开源ERP】别把ERP与进销存软件混为一谈

导读&#xff1a;企业使用ERP软件能够实现管理升级&#xff0c;多方信息集成&#xff0c;按照既定策略逻辑运算&#xff0c;生成计划建议&#xff0c;减少人力成本&#xff0c;提高准确率的同时提高经营能力。 ERP&#xff0c;是MRP II的下一代软件&#xff0c;除了MRP II已有的…

DataWhale-吃瓜教程学习笔记 (七)

学习视频**&#xff1a;第6章-支持向量机_哔哩哔哩_bilibili 西瓜书对应章节&#xff1a; 第六章 支持向量机 - 算法原理 几何角度 对于线性可分数据集&#xff0c;找距离正负样本距离都最远的超平面&#xff0c;解是唯一的&#xff0c;泛化性能较好 - 超平面 - 几何间隔 例…

网络爬虫(二) 哔哩哔哩热榜高频词按照图片形状排列

我们有时候需要爬取结果生成为自定义的词云图 生成自定义的词云图通常需要以下步骤&#xff1a; 1. 爬取数据&#xff1a;使用爬虫工具或库&#xff0c;如requests、BeautifulSoup等&#xff0c;可以爬取网页、论坛、社交媒体等平台上的文本数据。 2. 数据预处理&#xff1a…

学习笔记(linux高级编程)10

IPC 进程间通信 interprocess communicate 三大类&#xff1a; 1、古老的通信方式 无名管道 有名管道 信号 2、IPC对象通信 system v BSD suse fedora kernel.org 消息队列(用的相对少&#xff0c;这里不讨论) 共享内存 信号量集 3、socket通信 网络通信 特…

windows电脑网络重置后wifi列表消失怎么办?

我们的电脑网络偶尔会出现异常&#xff0c;我们通常会下意识选择网络诊断&#xff0c;运行完诊断后一般会让我们选择重置网络&#xff0c;然而&#xff0c;重置后wifi列表突然消失&#xff0c;无法愉快地上网了&#xff0c;找了一圈&#xff0c;都说是更改适配器选项&#xff0…

【东奥会计-注册安全分析报告】

前言 由于网站注册入口容易被黑客攻击&#xff0c;存在如下安全问题&#xff1a; 暴力破解密码&#xff0c;造成用户信息泄露短信盗刷的安全问题&#xff0c;影响业务及导致用户投诉带来经济损失&#xff0c;尤其是后付费客户&#xff0c;风险巨大&#xff0c;造成亏损无底洞…

JavaScript(6)——数据类型转换

为什么需要类型转换&#xff1f; JavaScript是弱数据类型&#xff1a;JavaScript不知道变量到底属于哪种数据类型&#xff0c;只有赋值了才清除 使用表单&#xff0c;prompt获取的数据默认为字符串类型&#xff0c;此时不能直接进行算数运算 隐式转换 某些运算符被执行时&am…

gitLab使用流程

标题1.配置账户 git config --global user.name git config --global user.email mygitlabmali.cn 标题2.生成秘匙 ssh-keygen -t rsa -C “mygitlabmail.cn” 。 //输入命令后一直回车 &#xff0c;输入命令后一直回车&#xff08;密码可以不填&#xff09;&#xff0c;至…

证券交易系统中服务器监控系统功能设计

1.背景介绍 此服务器监控系统的目的在于提高行情服务器的监管效率&#xff0c;因目前的的行情服务器&#xff0c;包括DM、DT、DS配置数量较多&#xff0c;巡回维护耗时较多&#xff0c;当行情服务器出现异常故障&#xff0c;或者因为网络问题造成数据断线等情况时&#xff0c;监…

k8s record 20240705

k8s 安全管理 request 是1g&#xff0c;你得不到要求&#xff0c;我就不创建了&#xff0c;这就是准入控制二次校验 SA就是serviceAccount。 内部是SA和 token, 外部用户进来就是 .kube/config文件 namespace下的是role&#xff0c;整个集群是 ClusterRole. 动作就是Binding li…

电机驱动----L298N

一、介绍 L298N 是一种双H桥电机驱动芯片&#xff0c;其中每个H桥可以提供2A的电流&#xff0c;内含4路逻辑驱动电路&#xff0c;功率部分的供电电压范围是2.5-48v&#xff0c;逻辑部分5v供电&#xff0c;接受5vTTL电平。一般情况下&#xff0c;功率部分的电压应大于6V否则芯片…