Java数据结构-树的面试题

news2024/11/19 2:28:02

目录

一.谈谈树的种类

二.红黑树如何实现

三.二叉树的题目

 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);

            // 返回左右子树中较大的高度,并加上根节点的高度1
            return 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 + 1
            if (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 + 1
            if (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) {
        // 如果根节点为空,直接返回null
        if (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.coloradmin.cn/o/1900043.html

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

相关文章

强技能 展风采 促提升——北京市大兴区餐饮行业职工技能竞赛精彩呈现

6月19日&#xff0c;由大兴区总工会、区商务局、青云店镇人民政府联合主办&#xff0c;区服务工会、区餐饮行业协会承办的“传承中国技艺&#xff0c;打造新一代餐饮工匠”2024年大兴区餐饮行业职工职业技能竞赛决赛在北京华联创新学习中心隆重开幕。区总工会副主席郝泽宏&…

运维锅总详解计算机存储

本文从计算机存储简介、存储设备介绍、软件定义存储(SDS)、常见的Kubernetes CSI存储插件介绍、如何平衡成本和存储性能等方面对计算机存储进行详细分析&#xff1b;本文最后还通过图形展示了存储在计算机体系结构中的重要作用。希望对您有所帮助&#xff01; 一、计算机存储简…

沉浸式三维园区场景漫游体验

利用图扑三维可视化技术展示园区在不同时间段的变化&#xff0c;提供全景漫游体验&#xff0c;帮助用户全方位感受和理解园区环境&#xff0c;实现智能化管理与优化。

昇思第10天

RNN实现情感分类 二分类问题&#xff1a;Positive和Negative两类 步骤&#xff1a; 1.加载IMDB数据集 2.加载预训练词向量:预训练词向量是对输入单词的数值化表示&#xff0c;通过nn.Embedding层&#xff0c;采用查表的方式&#xff0c;输入单词对应词表中的index&#xff0c;…

OPENCV(图像入门笔记)

使用OpenCV读取图像 使用cv.imread()函数读取图像。 第一个参数为图像名称 第二个参数是一个标志&#xff0c;它指定了读取图像的方式。分别有三种 cv.IMREAD_COLOR&#xff1a; 加载彩色图像。任何图像的透明度都会被忽视。它是默认标志。 cv.IMREAD_GRAYSCALE&#xff1a;以…

武汉免费 【FPGA实战训练】 Vivado入门与设计师资课程

一&#xff0e;背景介绍 当今高度数字化和智能化的工业领域&#xff0c;对高效、灵活且可靠的技术解决方案的需求日益迫切。随着工业 4.0 时代的到来&#xff0c;工业生产过程正经历着前所未有的变革&#xff0c;从传统的机械化、自动化逐步迈向智能化和信息化。在这一背景下&…

windows USB 设备驱动开发-控制传输的数据包

每次在主机控制器和 USB 设备之间移动数据时&#xff0c;都会发生传输。 通常&#xff0c;USB 传输可大致分为控制传输和数据传输。 所有 USB 设备都必须支持控制传输&#xff0c;并且可以支持用于数据传输的端点。 每种类型的传输都与设备缓冲区USB 端点 的类型相关联。 控制传…

vscode远程连接linux(配置免密)

远程连接 1.首先保证物理机和虚拟机网络可以ping通 2.查看ubuntu得ip地址 ifconfig IP为&#xff1a;192.168.52.133 3.连接远程主机 配置免密 1.打开cmd运行ssh-keygen -t rsa 一路回车就行 2.打开window文件夹C:\Users\xbj\.ssh 3.用记事本打开id_rsa.pub文件复制公…

没有tpm2.0,你就不打算升级win11?屁孩君小白式教学如何跳过

屁孩君终于回归了&#xff0c;回归首文 博主的姥爷电脑已用此方法成功 目录 屁孩君终于回归了&#xff0c;回归首文下载win11镜像将镜像进行提取删除检测文件断网&#xff0c;防止windows重新补全检测文件点击setup&#xff0c;进行检测安装 完成屁孩君终于回归了&#xff0c;记…

idea使用技巧---超实用的mybatisX插件

一、使用原因 传统创建mybatis项目之后&#xff0c;在mapper接口和xml映射文件之间手动切换非常麻烦&#xff1a;不仅需要记住文件的所在位置&#xff0c;而且每次在mapper当中添加一个新的接口&#xff0c;都需要单独手动点开xml再编写sql&#xff1b; eg&#xff1a;在item…

CSS中 实现四角边框效果

效果图 关键代码 border-radius:10rpx ;background: linear-gradient(#fff, #fff) left top,linear-gradient(#fff, #fff) left top,linear-gradient(#fff, #fff) right top,linear-gradient(#fff, #fff) right top,linear-gradient(#fff, #fff) left bottom,linear-gradient(…

多模态MLLM都是怎么实现的(11)--从SadTalker到快手LivePortait

我之前出差带休假差不多两个礼拜吧&#xff0c;今天回北京更新一篇 我确实找到了一个有意思的东西&#xff0c;LivePortrait 这东西开源了&#xff0c;你可以认为是目前做得最好的"Sadtalker"&#xff0c;国内也有dream-talker&#xff0c;EMO之类的。 我之前看EMO的…

Spring Boot集成olingo快速入门demo

1.什么是olingo&#xff1f; Apache Olingo 是个 Java 库&#xff0c;用来实现 Open Data Protocol (OData)。 Apache Olingo 包括服务客户端和 OData 服务器方面。 Open Data Protocol &#xff08;开放数据协议&#xff0c;OData&#xff09; 是用来查询和更新数据的一种W…

不要再盲目入场啦!跨境电商入场第一步!先收集整理这些数据,看清自己该如何入场!【纯分享】

23年、24年确实无愧于“品牌出海元年”的称号&#xff0c;23年出海四小龙——速卖通、TikTokshop、Temu、Shein在海外的爆发让大家看到了海外市场的活动&#xff1b;而24年则有更多的国内品牌将目光瞄向了海外市场&#xff0c;年后开工到今天基本上每天都有客户来咨询出海相关的…

Java应用系统设计与实现--学生信息管理系统(附解决方案源码)

一、实验目的及要求 1.1实验目的 掌握Java GUI编程技术&#xff0c;了解Swing框架的使用。 掌握MySQL数据库的基本操作&#xff0c;了解如何在Java中连接和操作数据库。 掌握用户权限管理的基本概念和实现方法。 提升综合运用所学知识设计和实现一个完整应用系统的能力…

hid-ft260驱动学习笔记 1 - 驱动模块注册与注销

目录 1. ft260_driver_init初始化 1.1 tty设备 1.1.1 申请tty驱动设备 1.1.2 初始化tty驱动程序 1.1.3 注册tty设备 1.2 hid设备 2. ft260_driver_exit注销模块 3. 调试 hid-ft260.c的最底部可以看到该驱动的注册与注销接口的申明。 module_init(ft260_driver_init); …

Nifi脚本组件ExecuteScript 的使用(一)

ExecuteScript 组件的基本使用 前面已经介绍过Nifi中基本的数据流程&#xff0c;这里介绍一下最为常用的一个组件&#xff0c;ExecuteScript processor&#xff0c;顾名思义ExecuteScript组件是一组以自定义脚本为主体的组件&#xff0c;意思就是&#xff0c;可以在该组件内部…

如何使用特殊的参数和符号来改变图像的风格、质量、比例

🪂🌹 /imagine prompt: 一朵白色的花,透明的花瓣,深如海水,晶莹剔透+露珠,8K,HD,常春藤,花卉,热带植物 --v 5 --ar 2:1 --c 80 --s 500 -v 5切换模型版本5--ar 2:1宽高比例为2:1--c 80混沌值为80--s 500样式值为500🧑🏼‍🎨Midjourney 动漫和插画风格 🌹…

Java视频点播网站

作者介绍&#xff1a;计算机专业研究生&#xff0c;现企业打工人&#xff0c;从事Java全栈开发 主要内容&#xff1a;技术学习笔记、Java实战项目、项目问题解决记录、AI、简历模板、简历指导、技术交流、论文交流&#xff08;SCI论文两篇&#xff09; 上点关注下点赞 生活越过…

Redis的八种数据类型介绍

Redis 是一个高性能的键值存储&#xff0c;它支持多种丰富的数据类型。每种数据类型都有其特定的用途和底层实现。下面我将介绍 Redis 支持的主要数据类型及其背后的数据结构。 本人这里还有几篇详细的Redis用法文章&#xff0c;可以用来进阶康康&#xff01; 1. 字符串 (Stri…