0

0

实现Java双向路径搜索的正确方法

碧海醫心

碧海醫心

发布时间:2025-10-10 09:44:24

|

539人浏览过

|

来源于php中文网

原创

实现java双向路径搜索的正确方法

本文旨在帮助开发者理解并正确实现Java中的双向路径搜索算法。通过分析常见的实现错误,我们将提供一种清晰、可行的解决方案,并详细解释如何构建完整的路径,克服单向搜索树的局限性,从而实现从起点到终点的完整路径搜索。

双向路径搜索是一种优化路径搜索效率的策略,它同时从起点和终点开始搜索,并在中间相遇。然而,在实现过程中,一些常见的错误可能会导致算法无法正常工作,或者只能返回部分路径。以下将详细介绍如何避免这些错误,并构建一个完整的双向路径搜索算法。

理解双向搜索的核心思想

双向搜索的核心在于同时维护两个搜索树:一个从起点开始,另一个从终点开始。 搜索过程持续进行,直到两个搜索树相遇,即找到一个共同的顶点。 此时,从起点到相遇顶点以及从终点到相遇顶点的两条路径可以合并成一条完整的路径。

避免常见的实现错误

原代码中存在一个关键问题:使用单个 searchTreeParentByChild 映射来存储两个方向的搜索树。 这导致无法区分路径的方向,并且只能正确重建一个方向的路径。 为了解决这个问题,我们需要为每个搜索方向维护独立的搜索树。

立即学习Java免费学习笔记(深入)”;

RecoveryFox AI
RecoveryFox AI

AI驱动的数据恢复、文件恢复工具

下载

正确实现双向路径搜索

以下是一种改进的双向路径搜索的实现方法:

import java.util.*;

public class BidirectionalSearch {

    private final Graph graph;
    private final Map forwardSearchTree = new HashMap<>();
    private final Map backwardSearchTree = new HashMap<>();

    public BidirectionalSearch(Graph graph) {
        this.graph = graph;
    }

    public Optional> findPath(Vertex start, Vertex end) {
        if (!graph.vertices().containsAll(List.of(start, end))) {
            throw new IllegalArgumentException("start or stop vertices not from this graph");
        }

        if (start.equals(end)) {
            return Optional.of(List.of(start));
        }

        forwardSearchTree.clear();
        backwardSearchTree.clear();

        Queue forwardQueue = new ArrayDeque<>();
        Queue backwardQueue = new ArrayDeque<>();

        forwardQueue.add(start);
        backwardQueue.add(end);

        forwardSearchTree.put(start, null);
        backwardSearchTree.put(end, null);

        Vertex intersection = null;

        while (!forwardQueue.isEmpty() && !backwardQueue.isEmpty()) {
            // Forward search
            Vertex currentForward = forwardQueue.poll();
            for (Edge edge : currentForward.edges()) {
                Vertex neighbor = edge.to();
                if (!forwardSearchTree.containsKey(neighbor)) {
                    forwardSearchTree.put(neighbor, currentForward);
                    forwardQueue.add(neighbor);
                    if (backwardSearchTree.containsKey(neighbor)) {
                        intersection = neighbor;
                        break;
                    }
                }
            }
            if (intersection != null) break;

            // Backward search
            Vertex currentBackward = backwardQueue.poll();
            for (Edge edge : currentBackward.edges()) {
                Vertex neighbor = edge.to();
                if (!backwardSearchTree.containsKey(neighbor)) {
                    backwardSearchTree.put(neighbor, currentBackward);
                    backwardQueue.add(neighbor);
                    if (forwardSearchTree.containsKey(neighbor)) {
                        intersection = neighbor;
                        break;
                    }
                }
            }
            if (intersection != null) break;
        }

        if (intersection == null) {
            return Optional.empty(); // No path found
        }

        // Reconstruct the path
        List forwardPath = reconstructPath(forwardSearchTree, start, intersection);
        List backwardPath = reconstructPath(backwardSearchTree, end, intersection);
        Collections.reverse(backwardPath); // Reverse the backward path

        List fullPath = new ArrayList<>(forwardPath);
        fullPath.addAll(backwardPath.subList(1, backwardPath.size())); // Avoid duplicate intersection vertex

        return Optional.of(fullPath);
    }

    private List reconstructPath(Map searchTree, Vertex start, Vertex end) {
        List path = new ArrayList<>();
        Vertex current = end;
        while (current != null) {
            path.add(current);
            current = searchTree.get(current);
        }
        Collections.reverse(path);
        return path;
    }


    // 示例Graph和Vertex/Edge类的定义 (需要根据你的实际情况调整)
    interface Graph {
        Set vertices();
    }

    interface Vertex {
        Set edges();
    }

    interface Edge {
        Vertex to();
    }
}

代码解释:

  1. 维护两个搜索树: forwardSearchTree 从起点开始,backwardSearchTree 从终点开始。 每个搜索树都存储了 child -> parent 的映射关系。
  2. 搜索过程: 使用两个队列分别进行前向和后向搜索。 在每次迭代中,从一个队列中取出一个顶点,并探索其邻居。 如果邻居尚未被访问,则将其添加到相应的搜索树和队列中。 如果邻居在另一个搜索树中已经存在,则表示找到了相遇顶点。
  3. 路径重建: 使用 reconstructPath 方法分别从起点和终点到相遇顶点重建路径。 由于后向路径是从终点开始构建的,因此需要反转。
  4. 合并路径: 将前向路径和反转后的后向路径合并成完整的路径。 需要注意避免重复包含相遇顶点。
  5. Optional返回: 使用Optional避免返回null,更符合Java的编码规范。

注意事项

  • 图的表示: 以上代码假设图由 Graph、Vertex 和 Edge 类表示。 你需要根据你的实际图结构进行调整。
  • 边的方向: 确保 Edge 类包含正确的信息,指示边的方向。
  • 性能优化: 对于大型图,可以考虑使用更高级的数据结构和算法来优化搜索性能。 例如,可以使用优先级队列来实现 A* 搜索算法。
  • 环的检测: 在某些情况下,图中可能存在环。为了避免无限循环,需要在搜索过程中进行环的检测。

总结

通过为每个搜索方向维护独立的搜索树,并正确重建和合并路径,可以实现一个有效的双向路径搜索算法。 这种算法可以显著提高路径搜索的效率,尤其是在大型图中。 在实际应用中,需要根据具体的图结构和性能要求进行适当的调整和优化。 重要的是理解双向搜索的原理,并避免常见的实现错误。

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
edge是什么浏览器
edge是什么浏览器

Edge是一款由Microsoft开发的网页浏览器,是Windows 10操作系统中默认的浏览器,其目标是提供更快、更安全、更现代化的浏览器体验。本专题为大家提供edge浏览器相关的文章、下载、课程内容,供大家免费下载体验。

1415

2023.08.21

IE浏览器自动跳转EDGE如何恢复
IE浏览器自动跳转EDGE如何恢复

ie浏览器自动跳转edge的解决办法:1、更改默认浏览器设置;2、阻止edge浏览器的自动跳转;3、更改超链接的默认打开方式;4、禁用“快速网页查看器”;5、卸载edge浏览器;6、检查第三方插件或应用程序等等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

381

2024.03.05

如何解决Edge打开但没有标题的问题
如何解决Edge打开但没有标题的问题

若 Microsoft Edge 浏览器打开后无标题(窗口空白或标题栏缺失),可尝试以下方法解决: 重启 Edge:关闭所有窗口,重新启动浏览器。 重置窗口布局:右击任务栏 Edge 图标 → 选择「最大化」或「还原」。 禁用扩展:进入 edge://extensions 临时关闭插件测试。 重置浏览器设置:前往 edge://settings/reset 恢复默认配置。 更新或重装 Edge:检查最新版本,或通过控制面板修复

940

2025.04.24

c语言中null和NULL的区别
c语言中null和NULL的区别

c语言中null和NULL的区别是:null是C语言中的一个宏定义,通常用来表示一个空指针,可以用于初始化指针变量,或者在条件语句中判断指针是否为空;NULL是C语言中的一个预定义常量,通常用来表示一个空值,用于表示一个空的指针、空的指针数组或者空的结构体指针。

236

2023.09.22

java中null的用法
java中null的用法

在Java中,null表示一个引用类型的变量不指向任何对象。可以将null赋值给任何引用类型的变量,包括类、接口、数组、字符串等。想了解更多null的相关内容,可以阅读本专题下面的文章。

458

2024.03.01

treenode的用法
treenode的用法

​在计算机编程领域,TreeNode是一种常见的数据结构,通常用于构建树形结构。在不同的编程语言中,TreeNode可能有不同的实现方式和用法,通常用于表示树的节点信息。更多关于treenode相关问题详情请看本专题下面的文章。php中文网欢迎大家前来学习。

538

2023.12.01

C++ 高效算法与数据结构
C++ 高效算法与数据结构

本专题讲解 C++ 中常用算法与数据结构的实现与优化,涵盖排序算法(快速排序、归并排序)、查找算法、图算法、动态规划、贪心算法等,并结合实际案例分析如何选择最优算法来提高程序效率。通过深入理解数据结构(链表、树、堆、哈希表等),帮助开发者提升 在复杂应用中的算法设计与性能优化能力。

17

2025.12.22

深入理解算法:高效算法与数据结构专题
深入理解算法:高效算法与数据结构专题

本专题专注于算法与数据结构的核心概念,适合想深入理解并提升编程能力的开发者。专题内容包括常见数据结构的实现与应用,如数组、链表、栈、队列、哈希表、树、图等;以及高效的排序算法、搜索算法、动态规划等经典算法。通过详细的讲解与复杂度分析,帮助开发者不仅能熟练运用这些基础知识,还能在实际编程中优化性能,提高代码的执行效率。本专题适合准备面试的开发者,也适合希望提高算法思维的编程爱好者。

27

2026.01.06

俄罗斯Yandex引擎入口
俄罗斯Yandex引擎入口

2026年俄罗斯Yandex搜索引擎最新入口汇总,涵盖免登录、多语言支持、无广告视频播放及本地化服务等核心功能。阅读专题下面的文章了解更多详细内容。

158

2026.01.28

热门下载

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

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Kotlin 教程
Kotlin 教程

共23课时 | 3万人学习

C# 教程
C# 教程

共94课时 | 7.8万人学习

Java 教程
Java 教程

共578课时 | 52.6万人学习

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

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