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

本文介绍了单源最短路径问题及其在图论和网络优化中的应用,详细讲解了迪杰斯特拉算法和贝尔曼-福特算法的原理、步骤和Java实现。这两种算法在处理无权重和有权重、包含负权重边的图时各有适用场景。
摘要由CSDN通过智能技术生成

单源最短路径问题是指在加权图中,找到从单个源点到其他所有点的最短路径的问题。这是图论和网络优化中的一个经典问题,具有广泛的应用,如网络路由、交通规划、社交网络分析等。解决单源最短路径问题的算法有很多,其中最著名的包括迪杰斯特拉算法(Dijkstra’s Algorithm)和贝尔曼-福特算法(Bellman-Ford Algorithm)。

迪杰斯特拉算法(Dijkstra’s Algorithm)

迪杰斯特拉算法是一种贪心算法,适用于没有负权重边的图。它通过维护一个优先队列来选择距离源点最近的未访问顶点,并更新其相邻顶点的距离。

算法步骤

  1. 初始化所有顶点的距离为无穷大,将源点的距离设为0。
  2. 将所有顶点加入优先队列。
  3. 从优先队列中取出距离最小的顶点。
  4. 更新该顶点的所有未访问邻居的距离。
  5. 将更新后的邻居顶点加入优先队列。
  6. 重复步骤3-5,直到所有顶点都被访问。

贝尔曼-福特算法(Bellman-Ford Algorithm)

贝尔曼-福特算法适用于包含负权重边的图,但它比迪杰斯特拉算法慢。它的核心思想是通过多次迭代,逐步放松所有边,直到找到最短路径或者检测到负权重循环。

算法步骤

  1. 初始化所有顶点的距离为无穷大,将源点的距离设为0。
  2. 对图中的所有边进行V-1次迭代(V是顶点的数量),每次迭代尝试更新顶点的距离。
  3. 在每次迭代中,对于每条边(u, v),如果dist[u] + weight(u, v) < dist[v],则更新dist[v]。
  4. 检测是否存在负权重循环。

示例代码 - 迪杰斯特拉算法(Java):

import java.util.*;

public class DijkstraAlgorithm {
    private final Map<Integer, Map<Integer, Integer>> graph;
    private final PriorityQueue<Vertex> minHeap;
    private final int[] distance;

    public DijkstraAlgorithm(Map<Integer, Map<Integer, Integer>> graph) {
        this.graph = graph;
        this.minHeap = new PriorityQueue<>();
        this.distance = new int[graph.size()];
    }

    public void findShortestPath(int source) {
        Arrays.fill(distance, Integer.MAX_VALUE);
        distance[source] = 0;
        minHeap.offer(new Vertex(source, 0));

        while (!minHeap.isEmpty()) {
            Vertex current = minHeap.poll();
            if (current.distance == distance[current.vertex]) {
                for (Map.Entry<Integer, Integer> neighbor : graph.get(current.vertex)) {
                    int newDistance = current.distance + neighbor.getValue();
                    if (newDistance < distance[neighbor.getKey()]) {
                        distance[neighbor.getKey()] = newDistance;
                        minHeap.offer(new Vertex(neighbor.getKey(), newDistance));
                    }
                }
            }
        }
    }

    public static void main(String[] args) {
        Map<Integer, Map<Integer, Integer>> graph = new HashMap<>();
        graph.put(1, Map.of(2, 7, 3, 9, 6, 14));
        graph.put(2, Map.of(1, 7, 3, 10, 5, 8));
        graph.put(3, Map.of(1, 9, 2, 10, 4, 15, 6, 4));
        // ... 添加更多顶点和边

        DijkstraAlgorithm dijkstra = new DijkstraAlgorithm(graph);
        dijkstra.findShortestPath(1);
        // 输出从顶点1到其他顶点的最短路径
    }

    private static class Vertex implements Comparable<Vertex> {
        int vertex;
        int distance;

        public Vertex(int vertex, int distance) {
            this.vertex = vertex;
            this.distance = distance;
        }

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

在面试中,了解并能够实现单源最短路径算法是非常重要的。通过这些问题和解决方案,面试官可以评估应聘者的算法理解和编程能力。希望这些信息能够帮助你更好地准备面试!单源最短路径问题是算法面试中的一个重要话题,尤其是在大厂的面试中。以下是三道可能出现在大厂面试中的与单源最短路径相关的编程题目,以及相应的Java源码实现。

题目 1:无权重的图的单源最短路径

描述
给定一个无权重的图,找到从单个源点到所有其他顶点的最短路径。

示例

输入: 图的邻接表表示,源点为 1
输出: [0, 1, 2, 3]

Java 源码(使用广度优先搜索):

import java.util.*;

public class UnweightedShortestPath {
    public List<Integer> shortestPathUnweighted(int[][] graph, int src) {
        int n = graph.length;
        List<Integer> distances = new ArrayList<>();
        for (int i = 0; i < n; i++) {
            distances.add(Integer.MAX_VALUE);
        }
        distances.set(src - 1, 0);

        Queue<Integer> queue = new LinkedList<>();
        queue.offer(src);

        while (!queue.isEmpty()) {
            int current = queue.poll();
            for (int neighbor : graph[current - 1]) {
                if (distances.set(neighbor - 1, Math.min(distances.get(neighbor - 1), distances.get(current - 1) + 1))) {
                    queue.offer(neighbor);
                }
            }
        }

        return distances;
    }

    public static void main(String[] args) {
        UnweightedShortestPath solution = new UnweightedShortestPath();
        int[][] graph = {
            {2, 3},
            {1, 3},
            {1, 4},
            {2, 4}
        };
        int src = 1;
        List<Integer> result = solution.shortestPathUnweighted(graph, src);
        System.out.println("Shortest paths from " + src + ": " + result);
    }
}

题目 2:有权重的图的单源最短路径

描述
给定一个有权重的图,找到从单个源点到所有其他顶点的最短路径。

示例

输入: 图的邻接表表示,源点为 1,边的权重为数组
输出: [0, 6, 8, 11]

Java 源码(使用迪杰斯特拉算法):

import java.util.*;

public class WeightedShortestPath {
    public List<Integer> shortestPathWeighted(int[][] graph, int src) {
        int n = graph.length;
        List<Integer> distances = new ArrayList<>();
        for (int i = 0; i < n; i++) {
            distances.add(Integer.MAX_VALUE);
        }
        distances.set(src - 1, 0);

        PriorityQueue<Vertex> minHeap = new PriorityQueue<>();
        for (int i = 0; i < n; i++) {
            minHeap.offer(new Vertex(i + 1, distances.get(i)));
        }

        while (!minHeap.isEmpty()) {
            Vertex current = minHeap.poll();
            for (int[] edge : graph[current.vertex - 1]) {
                int neighbor = edge[0], weight = edge[1];
                if (distances.get(current.vertex - 1) + weight < distances.get(neighbor - 1)) {
                    distances.set(neighbor - 1, distances.get(current.vertex - 1) + weight);
                    minHeap.offer(new Vertex(neighbor, distances.get(neighbor - 1)));
                }
            }
        }

        return distances;
    }

    static class Vertex implements Comparable<Vertex> {
        int vertex;
        int distance;

        Vertex(int vertex, int distance) {
            this.vertex = vertex;
            this.distance = distance;
        }

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

    public static void main(String[] args) {
        WeightedShortestPath solution = new WeightedShortestPath();
        int[][] graph = {
            {2, 7}, {3, 9}, {4, 10},
            {1, 6}, {3, 15}, {4, 6},
            {1, 8}, {2, 11}, {4, 7}
        };
        int src = 1;
        List<Integer> result = solution.shortestPathWeighted(graph, src);
        System.out.println("Shortest paths from " + src + ": " + result);
    }
}

题目 3:存在负权重边的图的单源最短路径

描述
给定一个可能包含负权重边的图,找到从单个源点到所有其他顶点的最短路径。如果存在负权重循环,则报告错误。

示例

输入: 图的邻接表表示,源点为 1,边的权重为数组
输出: [0, 5, -3, 9]

Java 源码(使用贝尔曼-福特算法):

import java.util.*;

public class NegativeWeightShortestPath {
    public List<Integer> shortestPathNegativeWeight(int[][] graph, int src) {
        int n = graph.length;
        int[] distances = new int[n];
        Arrays.fill(distances, Integer.MAX_VALUE);
        distances[src - 1] = 0;

        for (int i = 0; i < n - 1; i++) {
            for (int j = 0; j < graph.length; j++) {
                for (int[] edge : graph[j]) {
                    int neighbor = edge[0], weight = edge[1];
                    if (distances[j] + weight < distances[neighbor - 1]) {
                        distances[neighbor - 1] = distances[j] + weight;
                    }
                }
            }
        }

        for (int i = 0; i < graph.length; i++) {
            for (int[] edge : graph[i]) {
                int neighbor = edge[0], weight = edge[1];
                if (distances[i] + weight < distances[neighbor - 1]) {
                    throw new IllegalArgumentException("Graph contains a negative-weight cycle");
                }
            }
        }

        return Arrays.asList(distances);
    }

    public static void main(String[] args) {
        NegativeWeightShortestPath solution = new NegativeWeightShortestPath();
        int[][] graph = {
            {1, -1}, {2, 4},
            {1, 3}, {3, 2}, {3, -3},
            {2, 2}, {4, 3}
        };
        int src = 1;
        try {
            List<Integer> result = solution.shortestPathNegativeWeight(graph, src);
            System.out.println("Shortest paths from " + src + ": " + result);
        } catch (IllegalArgumentException e) {
            System.out.println(e.getMessage());
        }
    }
}

这些题目和源码展示了单源最短路径问题的不同变体以及如何在实际编程中解决它们。在面试中,能够根据问题的特点选择合适的算法并实现其解决方案是非常重要的。希望这些示例能够帮助你更好地准备面试!

  • 3
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值