0

0

通用树中节点父节点的查找:基于广度优先遍历的实现

花韻仙語

花韻仙語

发布时间:2025-08-11 16:04:25

|

1028人浏览过

|

来源于php中文网

原创

通用树中节点父节点的查找:基于广度优先遍历的实现

本文详细介绍了如何在通用树数据结构中,通过广度优先遍历(BFS)算法查找指定节点的父节点。我们将探讨通用树节点的定义,并提供一个高效的迭代实现方法。该方法利用队列逐层遍历树,检查每个节点的子节点是否匹配目标键值,若匹配则返回当前节点作为父节点。文章包含示例代码、算法分析及使用注意事项,旨在帮助读者掌握通用树中节点关系查找的关键技术。

通用树节点结构定义

在通用树(General Tree)中,一个节点可以拥有任意数量的子节点,这与二叉树每个节点最多只有两个子节点的结构有所不同。为了实现对通用树的操作,我们首先需要定义其节点结构。一个典型的通用树节点通常包含一个用于标识节点的值(或键),以及一个存储其所有子节点的列表。

以下是本文示例中使用的Java语言节点定义:

import java.util.ArrayList;
import java.util.LinkedList; // For Queue
import java.util.Queue;     // For Queue

/**
 * 通用树节点定义
 */
public class Node {
    int key; // 节点存储的键值
    ArrayList children; // 子节点列表

    /**
     * 构造函数
     * @param key 节点的键值
     */
    public Node(int key) {
        this.key = key;
        this.children = new ArrayList<>();
    }

    /**
     * 检查节点是否有子节点
     * @return 如果有子节点返回true,否则返回false
     */
    public boolean hasChildren(){
        return !children.isEmpty();
    }

    /**
     * 添加子节点
     * @param child 要添加的子节点
     */
    public void addChild(Node child) {
        this.children.add(child);
    }
}

在这个 Node 类中:

  • key:表示当前节点的值或标识符。
  • children:一个 ArrayList,用于存储当前节点的所有子节点。
  • Node(int key):构造函数,用于初始化节点。
  • hasChildren():一个辅助方法,用于判断当前节点是否有子节点。
  • addChild(Node child):一个辅助方法,用于向当前节点添加子节点。

问题描述:查找指定节点的父节点

我们的目标是编写一个函数,给定通用树的根节点(root)和一个目标键值(token),该函数需要返回拥有该目标键值的节点的父节点。如果目标节点是树的根节点(根节点没有父节点),或者树中不存在具有该键值的节点,则函数应返回 null。

广度优先遍历(BFS)策略

广度优先遍历(BFS)是一种图或树的遍历算法,它从起始节点开始,首先访问其所有邻居节点,然后访问这些邻居节点的邻居节点,依此类推。在树结构中,BFS会逐层地访问节点:先访问根节点,然后是其所有子节点(第一层),接着是第一层节点的所有子节点(第二层),以此类推。

Magician
Magician

Figma插件,AI生成图标、图片和UX文案

下载

BFS非常适合解决查找父节点的问题,原因如下:

  1. 逐层探索: BFS的特性使其能够一层一层地搜索树。当它遍历到某个节点 p 时,它会检查 p 的所有子节点 c。如果 c 的键值与 token 匹配,那么 p 自然就是 c 的父节点。
  2. 简单直接: 这种策略避免了深度优先遍历(DFS)中可能需要的复杂回溯逻辑,使得父节点的查找过程更加直观。

算法实现与解析

我们将使用一个队列(Queue)来实现广度优先遍历。算法步骤如下:

  1. 初始化队列: 创建一个 LinkedList 作为队列,并将树的根节点 root 加入队列。
  2. 循环遍历: 当队列不为空时,持续执行以下操作:
    • 出队: 从队列中取出一个节点 p(当前正在处理的节点)。
    • 检查子节点: 遍历 p 的所有子节点 c。
      • 匹配判断: 如果 c.key 等于目标 token,则说明我们找到了目标节点,此时 p 就是它的父节点,立即返回 p。
      • 入队: 如果 c.key 不匹配 token,则将 c 加入队列,以便在后续迭代中处理其子节点。
  3. 未找到: 如果循环结束,队列为空,但仍未找到匹配 token 的节点,则表示树中不存在该节点或目标节点是根节点(根节点无父节点),此时返回 null。

以下是该算法的Java实现:

// 为了运行示例,这里假设 Node 类和必要的 import 语句已经定义
// import java.util.ArrayList;
// import java.util.LinkedList;
// import java.util.Queue;

public class TreeOperations {

    /**
     * 在通用树中查找指定节点的父节点
     * 使用广度优先遍历(BFS)实现
     *
     * @param root 树的根节点
     * @param token 要查找的子节点的键值
     * @return 目标节点的父节点;如果目标节点是根节点或未找到,则返回null
     */
    public static Node findParent(Node root, int token) {
        // 如果树为空,或者目标节点是根节点(根节点没有父节点),则直接返回null
        // 注意:如果token就是root.key,此函数也会返回null,符合根节点无父节点的逻辑
        if (root == null) {
            return null;
        }

        // 使用LinkedList作为队列实现BFS
        Queue queue = new LinkedList<>();
        queue.add(root); // 将根节点加入队列

        // 当队列不为空时,持续进行遍历
        while (!queue.isEmpty()) {
            Node currentNode = queue.poll(); // 从队列中取出当前节点(作为潜在的父节点)

            // 遍历当前节点的所有子节点
            for (Node child : currentNode.children) {
                // 如果子节点的键值与目标token匹配
                if (child.key == token) {
                    return currentNode; // 找到目标节点,返回其父节点(即当前节点)
                }
                // 如果子节点不匹配,则将其加入队列,以便后续处理其子节点
                queue.add(child);
            }
        }

        // 遍历完所有节点仍未找到目标token,或者目标token是根节点本身
        return null;
    }

    public static void main(String[] args) {
        // 构造一个通用树示例
        //      10
        //     / | \
        //    20 30 40
        //   / \   |
        //  50 60  70

        Node root = new Node(10);
        Node node20 = new Node(20);
        Node node30 = new Node(30);
        Node node40 = new Node(40);
        Node node50 = new Node(50);
        Node node60 = new Node(60);
        Node node70 = new Node(70);

        root.addChild(node20);
        root.addChild(node30);
        root.addChild(node40);

        node20.addChild(node50);
        node20.addChild(node60);

        node40.addChild(node70);

        // 测试用例
        System.out.println("查找节点 50 的父节点:");
        Node parent50 = findParent(root, 50);
        System.out.println(parent50 != null ? "父节点是: " + parent50.key : "未找到父节点或目标是根节点"); // 预期: 20

        System.out.println("\n查找节点 70 的父节点:");
        Node parent70 = findParent(root, 70);
        System.out.println(parent70 != null ? "父节点是: " + parent70.key : "未找到父节点或目标是根节点"); // 预期: 40

        System.out.println("\n查找节点 30 的父节点:");
        Node parent30 = findParent(root, 30);
        System.out.println(parent30 != null ? "父节点是: " + parent30.key : "未找到父节点或目标是根节点"); // 预期: 10

        System.out.println("\n查找节点 10 (根节点) 的父节点:");
        Node parent10 = findParent(root, 10);
        System.out.println(parent10 != null ? "父节点是: " + parent10.key : "未找到父节点或目标是根节点"); // 预期: null

        System.out.println("\n查找不存在的节点 99 的父节点:");
        Node parent99 = findParent(root, 99);
        System.out.println(parent99 != null ? "父节点是: " + parent99.key : "未找到父节点或目标是根节点"); // 预期: null
    }
}

注意事项与性能分析

  1. 时间复杂度:
    • 该算法的时间复杂度为 O(N),其中 N 是树中节点的总数。在最坏情况下,我们需要访问树中的所有节点才能找到目标节点或确定其不存在。
  2. 空间复杂度:
    • 空间复杂度取决于队列中存储的最大节点数。在最坏情况下(例如,一个非常宽的树),队列可能需要存储一整层的节点。因此,空间复杂度为 O(W),其中 W 是树的最大宽度。在极端情况下,如果树是一个链表(只有一个子节点),W=1;如果树是完全平衡的,W 可能是 N/2。因此,最坏情况下的空间复杂度可以达到 O(N)(例如,一个只有根节点和大量直接子节点的树)。
  3. 根节点的处理:
    • 如果 token 的值与根节点的 key 相同,findParent 函数将返回 null。这是符合逻辑的,因为根节点没有父节点。
  4. 未找到目标节点:
    • 如果树中不存在具有 token 值的节点,函数将遍历完整个树,最终队列为空,并返回 null。
  5. 空树处理:
    • 如果传入的 root 为 null,函数会立即返回 null,避免了空指针异常。

总结

通过广度优先遍历(BFS)查找通用树中指定节点的父节点是一种高效且直观的方法。它利用队列的特性,逐层检查节点及其子节点,从而在找到目标节点时能够直接确定其父节点。这种方法不仅易于理解和实现,而且在大多数情况下具有良好的性能表现。掌握BFS在树结构中的应用,对于处理各种树相关的查找和遍历问题都至关重要。

相关专题

更多
java
java

Java是一个通用术语,用于表示Java软件及其组件,包括“Java运行时环境 (JRE)”、“Java虚拟机 (JVM)”以及“插件”。php中文网还为大家带了Java相关下载资源、相关课程以及相关文章等内容,供大家免费下载使用。

832

2023.06.15

java正则表达式语法
java正则表达式语法

java正则表达式语法是一种模式匹配工具,它非常有用,可以在处理文本和字符串时快速地查找、替换、验证和提取特定的模式和数据。本专题提供java正则表达式语法的相关文章、下载和专题,供大家免费下载体验。

737

2023.07.05

java自学难吗
java自学难吗

Java自学并不难。Java语言相对于其他一些编程语言而言,有着较为简洁和易读的语法,本专题为大家提供java自学难吗相关的文章,大家可以免费体验。

734

2023.07.31

java配置jdk环境变量
java配置jdk环境变量

Java是一种广泛使用的高级编程语言,用于开发各种类型的应用程序。为了能够在计算机上正确运行和编译Java代码,需要正确配置Java Development Kit(JDK)环境变量。php中文网给大家带来了相关的教程以及文章,欢迎大家前来阅读学习。

397

2023.08.01

java保留两位小数
java保留两位小数

Java是一种广泛应用于编程领域的高级编程语言。在Java中,保留两位小数是指在进行数值计算或输出时,限制小数部分只有两位有效数字,并将多余的位数进行四舍五入或截取。php中文网给大家带来了相关的教程以及文章,欢迎大家前来阅读学习。

398

2023.08.02

java基本数据类型
java基本数据类型

java基本数据类型有:1、byte;2、short;3、int;4、long;5、float;6、double;7、char;8、boolean。本专题为大家提供java基本数据类型的相关的文章、下载、课程内容,供大家免费下载体验。

446

2023.08.02

java有什么用
java有什么用

java可以开发应用程序、移动应用、Web应用、企业级应用、嵌入式系统等方面。本专题为大家提供java有什么用的相关的文章、下载、课程内容,供大家免费下载体验。

430

2023.08.02

java在线网站
java在线网站

Java在线网站是指提供Java编程学习、实践和交流平台的网络服务。近年来,随着Java语言在软件开发领域的广泛应用,越来越多的人对Java编程感兴趣,并希望能够通过在线网站来学习和提高自己的Java编程技能。php中文网给大家带来了相关的视频、教程以及文章,欢迎大家前来学习阅读和下载。

16925

2023.08.03

Java 桌面应用开发(JavaFX 实战)
Java 桌面应用开发(JavaFX 实战)

本专题系统讲解 Java 在桌面应用开发领域的实战应用,重点围绕 JavaFX 框架,涵盖界面布局、控件使用、事件处理、FXML、样式美化(CSS)、多线程与UI响应优化,以及桌面应用的打包与发布。通过完整示例项目,帮助学习者掌握 使用 Java 构建现代化、跨平台桌面应用程序的核心能力。

36

2026.01.14

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
10分钟--Midjourney创作自己的漫画
10分钟--Midjourney创作自己的漫画

共1课时 | 0.1万人学习

Midjourney 关键词系列整合
Midjourney 关键词系列整合

共13课时 | 0.9万人学习

AI绘画教程
AI绘画教程

共2课时 | 0.2万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号