首页 > 编程语言 >Java最短路径算法知识点(含面试大厂题和源码)

Java最短路径算法知识点(含面试大厂题和源码)

时间:2024-04-03 21:59:10浏览次数:18  
标签:知识点 Java int 路径 算法 源码 顶点 new dist

最短路径算法是计算机科学和图论中的核心问题之一,它旨在找到从一个顶点到另一个顶点或在所有顶点之间的最短路径。这个问题在多种实际应用中都非常重要,如网络路由、交通规划、社交网络分析等。以下是一些与最短路径算法相关的知识点:

  1. Dijkstra算法:

    • 由荷兰计算机科学家艾兹赫尔·戴克斯特拉(Edsger W. Dijkstra)在1956年提出。
    • 适用于带权重的有向图和无向图,且所有权重必须为非负值。
    • 算法使用贪心策略,通过不断地扩展已知最短路径集合来找到从源点到其他所有点的最短路径。
    • 时间复杂度取决于所使用的数据结构,使用优先队列时可以达到O(|V|^2 + |E|log|V|),其中|V|是顶点数,|E|是边数。
  2. Bellman-Ford算法:

    • 可以处理带有负权重边的图,但不允许存在负权重循环。
    • 通过对所有边进行|V|-1次松弛操作来逐步找到最短路径。
    • 时间复杂度为O(|V||E|),在稀疏图中效率较低。
  3. Floyd-Warshall算法:

    • 一种动态规划算法,用于计算所有顶点对之间的最短路径。
    • 可以处理带有正权重或负权重(但不包含负权重循环)的图。
    • 时间复杂度为O(|V|^3),适用于稠密图。
  4. A*搜索算法:

    • 一种启发式搜索算法,用于在图中找到从起点到目标点的最短路径。
    • 通过评估函数(如曼哈顿距离或欧几里得距离)来估计从当前顶点到目标点的最短距离,并优先搜索估计距离最小的路径。
    • 适用于有向图和无向图,且通常用于路径查找问题,如地图导航。
  5. Yen’s K最短路径算法:

    • 用于在加权图中找到从单一源点到目标点的前K条最短路径。
    • 基于Dijkstra算法的扩展,通过维护一个优先队列来存储当前找到的K条最短路径。
    • 时间复杂度取决于K的大小,对于每条路径的搜索时间复杂度为O(|E|log|V|)。
  6. 数据结构:

    • 在实现最短路径算法时,选择合适的数据结构非常重要,如优先队列、堆、图的邻接矩阵或邻接表等。
    • 正确的数据结构可以显著提高算法的效率。
  7. 优化技巧:

    • 减少不必要的计算和比较次数,例如使用启发式信息来指导搜索方向,或者在Dijkstra算法中使用双向搜索。
    • 利用问题的特定性质,如对称性或稀疏性,来优化算法。
  8. 实际应用:

    • 了解最短路径问题在不同领域的应用可以帮助更好地理解算法的实际意义。
    • 例如,在网络路由中,最短路径算法可以帮助确定数据包的最佳传输路径;在交通规划中,可以用于找到从一个地方到另一个地方的最快路线。

通过深入理解上述知识点,你将能够更好地解决最短路径问题,并在面试中展示你的算法设计和分析能力。在准备面试时,建议通过实际编程练习来巩固这些概念,并准备好讨论不同算法的适用场景和限制。

题目 1:Dijkstra算法 - 找到从单个源点到图中所有其他顶点的最短路径

描述
给定一个加权图和一个源顶点,使用Dijkstra算法找到从该源顶点到图中所有其他顶点的最短路径。

要求

  • 图的边权重必须为非负值。
  • 返回一个包含每个顶点最短路径长度的数组。

Java代码示例

import java.util.*;

class Graph {
    private int V; // 顶点的数量
    private List<List<Edge>> adj; // 邻接表

    class Edge {
        int v;
        int weight;

        Edge(int v, int weight) {
            this.v = v;
            this.weight = weight;
        }
    }

    Graph(int V) {
        this.V = V;
        adj = new ArrayList<>();
        for (int i = 0; i < V; ++i)
            adj.add(new ArrayList<>());
    }

    void addEdge(int u, int v, int weight) {
        adj.get(u).add(new Edge(v, weight));
    }

    void dijkstra(int s) {
        boolean[] visited = new boolean[V];
        int[] shortestPath = new int[V];
        Arrays.fill(shortestPath, Integer.MAX_VALUE);
        PriorityQueue<Vertex> minHeap = new PriorityQueue<>();

        visited[s] = true;
        minHeap.offer(new Vertex(s, 0));

        while (!minHeap.isEmpty()) {
            Vertex current = minHeap.poll();
            int u = current.id;
            int dist = current.dist;

            if (dist <= shortestPath[u])
                continue;

            for (Edge e : adj.get(u)) {
                int v = e.v;
                int weight = e.weight;

                if (!visited[v] && dist + weight < shortestPath[v]) {
                    shortestPath[v] = dist + weight;
                    minHeap.offer(new Vertex(v, shortestPath[v]));
                }
            }
        }

        // 输出结果
        for (int i = 0; i < V; i++) {
            System.out.print("Vertex " + i + " shortest path from source: " + shortestPath[i] + "\n");
        }
    }
}

class Vertex implements Comparable<Vertex> {
    int id;
    int dist;

    Vertex(int id, int dist) {
        this.id = id;
        this.dist = dist;
    }

    @Override
    public int compareTo(Vertex other) {
        return Integer.compare(this.dist, other.dist);
    }
}

public class DijkstraExample {
    public static void main(String[] args) {
        Graph g = new Graph(5);
        g.addEdge(0, 1, 10);
        g.addEdge(0, 2, 3);
        g.addEdge(1, 2, 1);
        g.addEdge(1, 3, 2);
        g.addEdge(2, 1, 4);
        g.addEdge(2, 3, 8);
        g.addEdge(2, 4, 2);
        g.addEdge(3, 4, 7);
        g.dijkstra(0);
    }
}

题目 2:Floyd-Warshall算法 - 找到图中所有顶点对的最短路径

描述
给定一个加权图,使用Floyd-Warshall算法找到所有顶点对之间的最短路径。

要求

  • 图中可能包含负权重的边,但不允许存在负权重循环。
  • 返回一个二维数组,其中每个元素表示两个顶点之间的最短路径长度。

Java代码示例

public class FloydWarshallExample {
    public static void main(String[] args) {
        int V = 5;
        int[][] graph = {
            {0, 5, float.POSITIVE_INFINITY, 10, float.POSITIVE_INFINITY},
            {float.POSITIVE_INFINITY, 0, 3, float.POSITIVE_INFINITY, 8},
            {float.POSITIVE_INFINITY, 7, 0, 2, float.POSITIVE_INFINITY},
            {10, float.POSITIVE_INFINITY, float.POSITIVE_INFINITY, 0, 1},
            {float.POSITIVE_INFINITY, 8, float.POSITIVE_INFINITY, 7, 0}
        };

        for (int k = 0; k < V; k++) {
            for (int i = 0; i < V; i++) {
                for (int j = 0; j < V; j++) {
                    if (graph[i][k] + graph[k][j] < graph[i][j]) {
                        graph[i][j] = graph[i][k] + graph[k][j];
                    }
                }
            }
        }

        // 打印结果
        for (int i = 0; i < V; i++) {
            for (int j = 0; j < V; j++) {
                System.out.print(graph[i][j] + " ");
            }
            System.out.println();
        }
    }
}

题目 3:A*搜索算法 - 在图中找到从起点到目标点的最短路径

描述
给定一个图和一个启发式函数,使用A*搜索算法找到从起点到目标点的最短路径。

要求

  • 启发式函数应估计从当前顶点到目标点的最小成本。
  • 返回从起点到目标点的最短路径及其长度。

Java代码示例(简化版):

import java.util.PriorityQueue;
import java.util.Comparator;

class Node {
    int x, y;
    int g, h;

    Node(int x, int y, int g, int h) {
        this.x = x;
        this.y = y;
        this.g = g;
        this.h = h;
    }

    @Override
    public String toString() {
        return "(" + x + ", " + y + ")";
    }
}

public class AStarExample {
    public static void main(String[] args) {
        // 假设的地图和启发式函数
        int[][] map = {
            {0, 1, 0, 0, 0},
            {1, 1, 1, 1, 0},
            {0, 0, 0, 1, 0},
            {0, 1, 1, 1, 1},
            {0, 0, 0, 0, 0}
        };
        int start = 0; // 起点位置
        int goal = 14; // 目标位置(地图上的位置索引)

        // 启发式函数(曼哈顿距离)
        int[] dx = {1, 0, -1, 0};
        int[] dy = {0, 1, 0, -1};
        int h(int x, int y) {
            int d = Math.abs(x / 4 - goal / 4) + Math.abs(y / 4 - goal % 4);
            return d;
        }

        // A* 算法实现
        PriorityQueue<Node> queue = new PriorityQueue<>(Comparator.comparingInt(a -> a.g + a.h));
        queue.offer(new Node(start / 4, start % 4, 0, h(start / 4, start % 4)));

        while (!queue.isEmpty()) {
            Node current = queue.poll();
            if (current.x * 4 + current.y == goal) {
                System.out.println("Found path: " + current);
                break;
            }
            // 探索邻居节点
            for (int i = 0; i < 4; i++) {
                int nx = current.x + dx[i];
                int ny = current.y + dy[i];
                if (nx >= 0 && nx < 5 && ny >= 0 && ny < 5 && map[nx][ny] == 0) {
                    int ng = current.g + 1;
                    int nh = h(nx, ny);
                    queue.offer(new Node(nx, ny, ng, nh));
                }
            }
        }
    }
}

请注意,上述代码示例是简化版的,实际面试中可能需要更详细的实现和解释。在准备面试时,你应该确保理解每个算法的原理,并能够根据面试官的要求编写完整的代码。此外,讨论算法的时间复杂度和空间复杂度,以及如何处理特殊情况(如负权重边或非常大的图)也是非常重要的。

标签:知识点,Java,int,路径,算法,源码,顶点,new,dist
From: https://blog.csdn.net/2302_80314137/article/details/137358723

相关文章

  • Java归并排序知识点(含面试大厂题和源码)
    归并排序是一种有效的排序算法,采用分治法(DivideandConquer)策略。它将数组分成两半,对每一半递归地进行排序,然后将两个有序的半部分合并成一个整体的有序数组。归并排序在最坏情况、平均情况和最好情况下都保持(O(n\logn))的时间复杂度,是一种稳定的排序算法。由于其分而治......
  • Java快速排序知识点(含面试大厂题含源码)
    快速排序是一种高效的排序算法,由C.A.R.Hoare在1960年提出。它的基本思想是分而治之(DivideandConquer)。快速排序的关键在于选取一个“基准值”(pivot),然后将数组分为两个子数组:一个包含所有小于基准值的元素,另一个包含所有大于基准值的元素。这个过程称为“分区”(partitio......
  • java八股——linux常见命令
    上一篇传送门:点我说说你知道的linux命令?1.ls:列出目录内容。示例:ls-l(以长格式显示目录内容,可以缩写成ll),ls-a(显示包括隐藏文件在内的所有文件)。2.cd:改变当前工作目录。示例:cd/home/user(切换到/home/user目录),cd…(切换到上一级目录)。3.pwd:显示当前工作目录的路径。4......
  • Java后端新手的第一次面试复盘
    昨天经历了第一次Java后端实习生面试,在无数次的简历投递后,很难得的一次面试机会,收获很多,也深刻感受到自己能力的不足(还需要继续沉淀半个学期),在此记录下收获和感悟,如有错误,欢迎指正!1.面试流程闲聊(5分钟):自我介绍+询问背景动机技术问答(45分钟):包括Java基础、数据库技......
  • java毕业设计二手书籍拍卖小程序[附源码]
    本系统(程序+源码)带文档lw万字以上  文末可领取本课题的JAVA源码参考系统程序文件列表系统的选题背景和意义选题背景:随着数字化时代的深入发展,人们对于信息的获取和物品的交易方式正经历着翻天覆地的变化。特别是在教育领域,电子书的普及使得纸质书籍逐渐被边缘化,这并不意......
  • Java Web实验四:Servlet应用开发
    实验四  Servlet应用开发一、实验目的1.学会使用Servlet获取表单数据;2.学会使用Servlet的跳转方法实现重定向;3.学会配置和获取应用初始化参数的方法。二、实验内容1.编写一个登录页面,根据登录验证结果,重定向到登录成功页面和登录失败页面;2.在Servlet中获取应用......
  • JavaWeb-01记录
    JWT令牌JSONWebToken作用:以json格式在各方之间安全传递信息,是数字签名的。格式:标头Header.有效载荷Payload.签名Signature前两部分用Base64编码,可以被前端翻译并理解。第三部分使用编码后的前两部分,加上一个密钥,用头部声明的加密算法进行签名,保证令牌没有被篡改。swagger生......
  • 操作系统知识点
    进程&线程进程不是程序。进程是动态的,有生命周期的。程序是指令的集合,是静态的。程序和进程的关系类似于类与对象的关系。线程是特殊的进程。PCB是常驻内存中的。Linux系统中fork()后父进程和子进程谁先执行?与具体操作系统有关,Ubuntu是先把父进程执行完。操作系统中共有n......
  • 关于openEuler系统的基本环境配置(包括nginx,mysql5.7和java1.8)
    关于openEuler系统的基本环境配置(包括nginx,mysql5.7和java1.8)观前BB:openEuler虽然是国产系统,但是本质还是centos的套壳系统,你可以通过(uname-a)命令得以观察出,而且系统更类似于centos8(这个还有待确认),这就导致了安装环境的时候经常会出现奇奇怪怪的错误(比如yum找不到源什么的),本......
  • Java的Scanner类、Random类、ArrayList类、String类的基本定义
    学习目标:学习Java中Scanner类、Random类、ArrayList类、String类基本定义学习内容:Scanner类Scanner功能简介用于获取外界输入,例如从键盘录入字符、数字等等…Scanner类使用前需要先导入Scanner包importjava.util.Scanner;导包后创建Scanner类对象,接上.使......