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.mzph.cn/bicheng/41416.shtml

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

相关文章

如何在Qt使用uchardet库

如何在 Qt 中使用 uchardet 库 文章目录 如何在 Qt 中使用 uchardet 库一、简介二、uchardet库的下载三、在Qt中直接调用四、编译成库文件后调用4.1 编译工具下载4.2 uchardet源码编译4.3 测试编译文件4.4 Qt中使用 五、一些小问题5.1 测试文件存在的问题5.2 uchardet库相关 六…

聚合支付系统主要分账方案及API分析

1 常见分账场景介绍 分账一般分为线下场景分账和线上场景分账&#xff0c;分账API分为微信&#xff0c;支付宝或其他第三方支付公司、银行。今天我们主要探讨微信、支付宝线上和线下场景分账流程。 微信分账API分为收付通和线下服务商分账&#xff0c;支付宝分账分为互联网平…

YOLOV++ 详解 | 网络结构、代码解析、YOLOV 论文阅读、初识 VID

前言 代码地址&#xff1a;https://github.com/YuHengsss/YOLOV 本文网络结构按 YOLOV SwinTiny 绘制&#xff0c;不同的模型主要差异在于 Backbone&#xff0c;VID 相关的部分基本相同。 Predict Input 代码基于 vid_demo。首先会读取视频中的所有帧&#xff08;只能用短视频…

c++ 构造,析构,拷贝,移动构造函数

文章目录 概述1.构造函数2. 拷贝构造函数3.移动构造函数4.析构函数 例子QTUE4/5 c 小结 概述 对于c来说&#xff0c;最基础的是类。对于一个类来说&#xff0c;主要由以下函数构成。如下&#xff1a; 构造函数拷贝构造函数移动构造函数析构函数 当然&#xff0c;还有一个操作…

【简历】郑州某二本学院:JAVA实习简历指导,基本没有面试机会

注&#xff1a;为保证用户信息安全&#xff0c;姓名和学校等信息已经进行同层次变更&#xff0c;内容部分细节也进行了部分隐藏 简历说明 这份简历是一个25届二本同学找JAVA实习的简历&#xff0c;从整体来看&#xff0c;简历版式没有问题&#xff0c;非常清晰。 但是内容特…

数据操作10-15题(30 天 Pandas 挑战)

数据操作 1. 相关知识点1.12 分组与连表1.13 排名 2. 题目2.10 第N高的薪水2.11 第二高的薪水2.12 部门工资最高的员工2.13 分数排名2.14 删除重复的电子邮箱2.15 每个产品在不同商店的价格 1. 相关知识点 1.12 分组与连表 分组max_salaryemployee.groupby(departmentId)[sal…

搜索+动态规划

刷题刷题刷题刷题 ​​​​​​​​​​​​​​Forgery - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) 思路&#xff1a; 需要两个数组&#xff0c;一个数组全部初始化为".",另一个数组输入数据&#xff0c;每碰到一个“.”就进行染色操作&#xff0c;将其周围的…

Java后端每日面试题(day3)

目录 Spring中Bean的作用域有哪些&#xff1f;Spring中Bean的生命周期Bean 是线程安全的吗&#xff1f;了解Spring Boot中的日志组件吗&#xff1f; Spring中Bean的作用域有哪些&#xff1f; Bean的作用域&#xff1a; singleton&#xff1a;单例&#xff0c;Spring中的bean默…

已经安装deveco-studio-4.1.3.500的基础上安装deveco-studio-3.1.0.501

目录标题 1、执行exe文件后安装即可2、双击devecostudio64_3.1.0.501.exe2.1、安装Note (注意和4.1的Note放不同目录)2.2、安装ohpm (注意和4.1版本的ohpm放不同目录)2.3、安装SDK (注意和4.1版本的SDK放不同目录) 1、执行exe文件后安装即可 2、双击devecostudio64_3.1.0.501.e…

Ubuntu 22.04.4 LTS 安装 php apache LAMP 环境nginx

1 安装php-fpm apt update apt-get install php-fpm #配置php-fpm服务启动 systemctl enable php8.1-fpm systemctl start php8.1-fpm #查看服务 systemctl status php8.1-fpm #查看版本 rootiZbp1g7fmjea77vsqc5hmmZ:~# php -v PHP 8.1.2-1ubuntu2.18 (cli) (built: J…

HTML内容爬取:使用Objective-C进行网页数据提取

网页爬取简介 网页爬取&#xff0c;通常被称为网络爬虫或爬虫&#xff0c;是一种自动浏览网页并提取所需数据的技术。这些数据可以是文本、图片、链接或任何网页上的元素。爬虫通常遵循一定的规则&#xff0c;访问网页&#xff0c;解析页面内容&#xff0c;并存储所需信息。 …

mars3d加载wms服务或者wmts服务注意事项

1.wms只支持4326、3857、4490的标准切片&#xff0c;其他坐标系不支持 Mars3D三维可视化平台 | 火星科技 2.wmts同理&#xff0c;Mars3D三维可视化平台 | 火星科技 3.对应级别tilematrix找到的瓦片tilerow&tilecol这两个参数使用常见报错无效参考&#xff1a; 【Mars3d】…

护航端侧大模型平稳健康发展,百度大模型内容安全Lite版正式发布

6月28日&#xff0c;WAVE SUMMIT深度学习开发者大会 2024 “智变应用、码动产业”平行论坛在北京召开。与会&#xff0c;百度大模型内容安全Lite版正式发布&#xff0c;可面向低算力和超低算力的终端大模型提供离线场景下的一站式安全解决方案&#xff0c;为各类终端大模型平稳…

国际工业巨头遭勒索,亚信安全《勒索家族和勒索事件监控报告》

本周态势快速感知 本周全球共监测到勒索事件94起&#xff0c;事件数量有小幅下降。从整体上看&#xff0c;Lockbit3.0仍然是影响最严重的勒索家族&#xff1b;本周RansomHub是影响最严重的勒索家族&#xff1b;Akira和Dragonforce恶意家族紧随其后&#xff0c;需要注意防范。拉…

ython 使用 cx_Freeze 打包,不想要打包文件中能直接看到依赖的代码,如何处理

背景&#xff1a;因为使用 cx_Freeze 打包时&#xff0c;添加需要依赖的文件 cx_Freeze 是一个用于将 Python 程序打包成独立可执行文件的工具&#xff0c;支持多个平台。当你需要打包包含多个 .py 文件的项目时&#xff0c;你可以通过编写一个 setup.py 文件来指定哪些模块应…

基于Spring Boot框架的EAM系统设计与实现

摘 要&#xff1a;文章设计并实现一个基于Spring Boot框架的EAM系统&#xff0c;以应对传统人工管理模式存在的低效与信息管理难题。系统利用Java语言、JSP技术、MySQL数据库等技术栈&#xff0c;构建了一个B/S架构的高效管理平台&#xff0c;提升了资产管理的信息化水平。该系…

独立站外链的重要性是什么?

独立站外链在提升网站排名和增加流量方面有着重要的作用。简单来说&#xff0c;外链就是从其他网站指向你网站的链接。谷歌和其他搜索引擎会根据这些外链来判断你网站的权威性和相关性。 有了高质量的外链&#xff0c;搜索引擎会更倾向于认为你的网站内容是有价值的&#xff0c…

c++ 附赠课程的知识点记录

&#xff08;1&#xff09; 静态变量的赋值 再一个例子&#xff1a; &#xff08;2&#xff09; 一般在定义类的赋值运算符函数时&#xff0c; operator ( const A& a ) 函数&#xff0c;应避免自赋值的情况&#xff0c;就是把对象 a 又赋值给 对象a 如同 a a 这样的情况…

如何摆脱反爬虫机制?

在网站设计时&#xff0c;为了保证服务器的稳定运行&#xff0c;防止非法数据访问&#xff0c;通常会引入反爬虫机制。一般来说&#xff0c;网站的反爬虫机制包括以下几种&#xff1a; 1. CAPTCHA&#xff1a;网站可能会向用户显示CAPTCHA&#xff0c;要求他们在访问网站或执行…

空状态页面设计的艺术与科学

空状态界面是用户在网站、APP中遇到的因无数据展示而中断体验的界面&#xff0c;这个界面设计对于解决用户疑惑有着很大的帮助。那么我们应该如何设计空状态界面呢&#xff1f;空状态是指在界面设计中&#xff0c;没有内容或数据时所显示的状态。它可能出现在各种情况下&#x…