程序员必备的十大技能(进阶版)之高阶数据结构与算法(三)

简介: 教程来源 http://unbgv.cn/ 本节系统讲解图的核心算法:最短路径(Dijkstra、Bellman-Ford、Floyd-Warshall)、最小生成树(Kruskal、Prim)及拓扑排序(Kahn与DFS实现),涵盖适用条件、时间复杂度与Java代码实现,适用于算法学习与工程实践。

四、图的算法体系

4.1 最短路径算法全解析
Dijkstra算法(非负权图)

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

public class Dijkstra {

    // 标准实现 - 使用优先队列 O((V+E) log V)
    public int[] dijkstra(List<Edge>[] graph, int source) {
        int n = graph.length;
        int[] dist = new int[n];
        Arrays.fill(dist, Integer.MAX_VALUE);
        dist[source] = 0;

        // 优先队列:按距离排序
        PriorityQueue<int[]> pq = new PriorityQueue<>(Comparator.comparingInt(a -> a[1]));
        pq.offer(new int[]{source, 0});

        while (!pq.isEmpty()) {
            int[] curr = pq.poll();
            int u = curr[0];
            int d = curr[1];

            if (d > dist[u]) continue;  // 过时的条目,跳过

            for (Edge edge : graph[u]) {
                int v = edge.to;
                int newDist = dist[u] + edge.weight;
                if (newDist < dist[v]) {
                    dist[v] = newDist;
                    pq.offer(new int[]{v, newDist});
                }
            }
        }
        return dist;
    }
}

Bellman-Ford算法(支持负权边,可检测负环)

public class BellmanFord {

    // 时间复杂度 O(VE)
    public int[] bellmanFord(List<Edge>[] graph, int source, boolean[] hasNegativeCycle) {
        int n = graph.length;
        int[] dist = new int[n];
        Arrays.fill(dist, Integer.MAX_VALUE);
        dist[source] = 0;

        // 松弛操作,重复 V-1 次
        for (int i = 0; i < n - 1; i++) {
            boolean updated = false;
            for (int u = 0; u < n; u++) {
                if (dist[u] == Integer.MAX_VALUE) continue;
                for (Edge edge : graph[u]) {
                    int v = edge.to;
                    if (dist[u] + edge.weight < dist[v]) {
                        dist[v] = dist[u] + edge.weight;
                        updated = true;
                    }
                }
            }
            if (!updated) break;  // 提前终止
        }

        // 第V次松弛:检测负环
        for (int u = 0; u < n; u++) {
            if (dist[u] == Integer.MAX_VALUE) continue;
            for (Edge edge : graph[u]) {
                int v = edge.to;
                if (dist[u] + edge.weight < dist[v]) {
                    hasNegativeCycle[0] = true;
                    return dist;
                }
            }
        }
        return dist;
    }
}

Floyd-Warshall算法(全源最短路径)

public class FloydWarshall {

    // 时间复杂度 O(V³)
    public int[][] floydWarshall(int[][] graph) {
        int n = graph.length;
        int[][] dist = new int[n][n];

        // 初始化
        for (int i = 0; i < n; i++) {
            System.arraycopy(graph[i], 0, dist[i], 0, n);
        }

        // 动态规划:k 作为中间节点
        for (int k = 0; k < n; k++) {
            for (int i = 0; i < n; i++) {
                for (int j = 0; j < n; j++) {
                    if (dist[i][k] != Integer.MAX_VALUE && 
                        dist[k][j] != Integer.MAX_VALUE &&
                        dist[i][k] + dist[k][j] < dist[i][j]) {
                        dist[i][j] = dist[i][k] + dist[k][j];
                    }
                }
            }
        }
        return dist;
    }
}

4.2 最小生成树
Kruskal算法(贪心 + 并查集)

class UnionFind { /* 前面已实现 */ }

class Edge implements Comparable<Edge> {
    int u, v, weight;
    Edge(int u, int v, int weight) {
        this.u = u;
        this.v = v;
        this.weight = weight;
    }
    @Override
    public int compareTo(Edge other) {
        return Integer.compare(this.weight, other.weight);
    }
}

public class Kruskal {

    // 时间复杂度 O(E log E)
    public List<Edge> kruskal(int n, List<Edge> edges) {
        List<Edge> mst = new ArrayList<>();
        Collections.sort(edges);
        UnionFind uf = new UnionFind(n);

        for (Edge edge : edges) {
            if (uf.find(edge.u) != uf.find(edge.v)) {
                uf.union(edge.u, edge.v);
                mst.add(edge);
                if (mst.size() == n - 1) break;
            }
        }
        return mst;
    }
}

Prim算法(优先队列优化)

public class Prim {

    // 时间复杂度 O(E log V)
    public int prim(List<Edge>[] graph) {
        int n = graph.length;
        boolean[] visited = new boolean[n];
        PriorityQueue<int[]> pq = new PriorityQueue<>(Comparator.comparingInt(a -> a[1]));

        // 从节点0开始
        pq.offer(new int[]{0, 0});
        int totalWeight = 0;
        int edgeCount = 0;

        while (!pq.isEmpty() && edgeCount < n) {
            int[] curr = pq.poll();
            int u = curr[0];
            int weight = curr[1];

            if (visited[u]) continue;

            visited[u] = true;
            totalWeight += weight;
            edgeCount++;

            for (Edge edge : graph[u]) {
                if (!visited[edge.to]) {
                    pq.offer(new int[]{edge.to, edge.weight});
                }
            }
        }
        return totalWeight;
    }
}

4.3 拓扑排序(有向无环图)

public class TopologicalSort {

    // Kahn算法(BFS)
    public List<Integer> kahnTopologicalSort(List<Integer>[] graph) {
        int n = graph.length;
        int[] inDegree = new int[n];

        // 计算入度
        for (int i = 0; i < n; i++) {
            for (int neighbor : graph[i]) {
                inDegree[neighbor]++;
            }
        }

        // 队列存储入度为0的节点
        Queue<Integer> queue = new LinkedList<>();
        for (int i = 0; i < n; i++) {
            if (inDegree[i] == 0) {
                queue.offer(i);
            }
        }

        List<Integer> result = new ArrayList<>();
        while (!queue.isEmpty()) {
            int u = queue.poll();
            result.add(u);

            for (int v : graph[u]) {
                inDegree[v]--;
                if (inDegree[v] == 0) {
                    queue.offer(v);
                }
            }
        }

        // 检查环
        if (result.size() != n) {
            throw new RuntimeException("图中存在环,无法进行拓扑排序");
        }
        return result;
    }

    // DFS方法
    public List<Integer> dfsTopologicalSort(List<Integer>[] graph) {
        int n = graph.length;
        boolean[] visited = new boolean[n];
        boolean[] onStack = new boolean[n];  // 用于检测环
        Stack<Integer> stack = new Stack<>();

        for (int i = 0; i < n; i++) {
            if (!visited[i]) {
                if (dfs(i, graph, visited, onStack, stack)) {
                    throw new RuntimeException("图中存在环");
                }
            }
        }

        List<Integer> result = new ArrayList<>();
        while (!stack.isEmpty()) {
            result.add(stack.pop());
        }
        return result;
    }

    private boolean dfs(int v, List<Integer>[] graph, boolean[] visited, 
                        boolean[] onStack, Stack<Integer> stack) {
        visited[v] = true;
        onStack[v] = true;

        for (int neighbor : graph[v]) {
            if (!visited[neighbor]) {
                if (dfs(neighbor, graph, visited, onStack, stack)) {
                    return true;
                }
            } else if (onStack[neighbor]) {
                return true;  // 发现环
            }
        }

        onStack[v] = false;
        stack.push(v);
        return false;
    }
}

来源:
http://htnus.cn/

相关文章
|
14天前
|
前端开发 JavaScript 容器
前端组件库 ——LayUI 知识点大全(三)
教程来源 https://bncne.cn LayUI基础元素丰富实用:按钮支持多色、多尺寸及图标组合;图标为矢量字体,可自由缩放变色;表单模块集成验证与交互;layer弹层、table表格、laydate日期、upload上传等核心模块,让后台开发简洁高效。
|
14天前
|
前端开发 JavaScript 开发者
前端组件库 ——LayUI 知识点大全(四)
教程来源 https://zlpow.cn LayUI 2.8+/3.0 支持 CSS 变量主题定制、深浅色切换;提供移动端专用版本;支持按需引入与模块化加载;可开发自定义模块及集成 ECharts 等第三方插件,兼顾简洁性与扩展性,适合快速构建后台系统。
|
21天前
|
前端开发 JavaScript 数据可视化
前端组件库 ——Three.js 知识点大全(一)
教程来源 https://www.vhjpe.cn/ Three.js 是基于 WebGL 的主流 JavaScript 3D 库,封装底层图形接口,让开发者用简洁代码快速构建网页级 3D 场景。涵盖场景、相机、渲染器三大核心,支持几何体、材质、光照、动画等完整管线,广泛应用于数据可视化、虚拟展厅与智慧园区等领域。
|
14天前
|
前端开发 JavaScript API
前端组件库 ——LayUI 知识点大全(一)
教程来源 http://oplhc.cn LayUI是由国内开发者“贤心”于2016年推出的经典模块化前端UI框架,MIT开源。不依赖Vue/React等现代框架,零配置、低门槛、开箱即用,尤受后端开发者与中小项目青睐。2026年仍持续更新,最新版2.11+强化组件与工程化支持。
|
19天前
|
Web App开发 前端开发 数据可视化
前端组件库 ——ECharts 知识点大全(一)
教程来源 https://bgnno.cn/ ECharts 是 Apache 顶级开源可视化库,由百度于2013年发起,支持50+图表类型、千万级数据渲染、Canvas/SVG双引擎及深度交互。兼容主流浏览器与移动端,广泛应用于商业、政务与科研领域。
|
18小时前
|
搜索推荐 程序员
初级程序员必备的十大技能之问题排查与自学能力(一)
教程来源 http://qeext.cn/ 本文系统讲解程序员两大终极能力:问题排查与自学方法。涵盖六步调试法、二分/排除/对比定位技巧、错误解读、高效搜索、文档阅读及结构化学习路径,助你从“能写代码”进阶为“稳解难题、快学新技术”的高价值工程师。
|
18小时前
|
监控 安全 程序员
初级程序员必备的十大技能之基础 Linux 命令(四)
教程来源 http://ltglu.cn/ 本节介绍五大核心网络工具:SSH(远程登录、命令执行与端口转发)、SCP(安全文件传输)、cURL(HTTP请求、API调试与下载)、Wget(断点续传与递归下载)及netstat/ss(网络连接与端口监控),涵盖常用命令与实用技巧。
|
16小时前
|
设计模式 SQL Java
程序员必备的十大技能(进阶版)之精通主流框架与源码思想(二)
教程来源 http://qeext.cn/ 本文深入解析Spring框架中四大核心设计模式(工厂、模板方法、适配器、观察者)的实战应用,并详解Spring Boot自动配置原理:从@SpringBootApplication组合注解、spring.factories机制、条件化加载(@Conditional系列),到手写Starter实践,助你由源码理解走向约定优于配置的开发范式。
|
17小时前
|
程序员 开发工具 git
初级程序员必备的十大技能之规范编码与团队协作(三)
教程来源 http://qcycj.cn/ 本节系统阐述高效团队协作核心实践:从精准提问、高效会议、知识共享到冲突化解,并配套自动化工具链(Prettier/ESLint/Husky/Commitlint/GitHub Actions),全面提升研发协同质量与工程规范性。
|
16小时前
|
算法 Java 程序员
程序员必备的十大技能(进阶版)之高阶数据结构与算法(二)
教程来源 http://xcfsr.cn/ 本节深度解析四大经典树形结构:红黑树(保障O(log n)性能,支撑Java/C++有序容器);B/B+树(数据库索引核心,优化磁盘I/O与范围查询);线段树(高效处理区间查询/更新,支持懒标记);前缀树(Trie,专精字符串匹配与自动补全)。附核心代码与时间复杂度分析。