返回

图的拓扑排序:解析Kahn算法,深入理解步骤及Java实现

后端

图的拓扑排序及其应用

在图论中,拓扑排序是指将有向无环图(DAG)的顶点排列成一个线性序列,使得对于图中任何一条有向边,从前一个顶点到后一个顶点。拓扑排序在计算机科学中有着广泛的应用,包括项目管理、任务调度和软件依赖管理等领域。

Kahn算法原理及步骤

Kahn算法是一种经典的拓扑排序算法,它利用有向无环图中顶点的入度(即指向该顶点的边的数目)来进行排序。算法的主要步骤如下:

  1. 初始化一个空队列Q,用于存储拓扑序列的顶点。
  2. 遍历图中的所有顶点,并计算每个顶点的入度。
  3. 将入度为0的顶点加入队列Q中。
  4. 重复以下步骤,直到队列Q为空:
    • 从队列Q中取出一个顶点v。
    • 将顶点v添加到拓扑序列中。
    • 遍历顶点v的所有出边,并将其连接到的顶点的入度减1。
    • 如果某个顶点的入度变为0,则将其加入队列Q中。

Java代码实现

基于邻接矩阵和邻接表的图对Kahn算法的Java实现如下:

import java.util.*;

public class TopologicalSort {

    // 基于邻接矩阵的实现
    public static List<Integer> topologicalSort_matrix(int[][] graph) {
        int n = graph.length;
        int[] inDegree = new int[n]; // 顶点的入度
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < n; j++) {
                if (graph[i][j] > 0) {
                    inDegree[j]++;
                }
            }
        }

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

        List<Integer> result = new ArrayList<>(); // 存储拓扑序列
        while (!queue.isEmpty()) {
            int v = queue.poll();
            result.add(v);

            for (int i = 0; i < n; i++) {
                if (graph[v][i] > 0) {
                    inDegree[i]--;
                    if (inDegree[i] == 0) {
                        queue.offer(i);
                    }
                }
            }
        }

        return result;
    }

    // 基于邻接表的实现
    public static List<Integer> topologicalSort_list(List<List<Integer>> graph) {
        int n = graph.size();
        int[] inDegree = new int[n]; // 顶点的入度
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < graph.get(i).size(); j++) {
                inDegree[graph.get(i).get(j)]++;
            }
        }

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

        List<Integer> result = new ArrayList<>(); // 存储拓扑序列
        while (!queue.isEmpty()) {
            int v = queue.poll();
            result.add(v);

            for (int i = 0; i < graph.get(v).size(); i++) {
                int next = graph.get(v).get(i);
                inDegree[next]--;
                if (inDegree[next] == 0) {
                    queue.offer(next);
                }
            }
        }

        return result;
    }

    public static void main(String[] args) {
        // 创建一个有向无环图
        int[][] graph_matrix = new int[][]{
                {0, 1, 0, 0},
                {0, 0, 1, 0},
                {0, 0, 0, 1},
                {0, 0, 0, 0}
        };

        List<List<Integer>> graph_list = new ArrayList<>();
        for (int i = 0; i < 4; i++) {
            graph_list.add(new ArrayList<>());
        }
        graph_list.get(0).add(1);
        graph_list.get(1).add(2);
        graph_list.get(2).add(3);

        // 基于邻接矩阵进行拓扑排序
        List<Integer> result_matrix = topologicalSort_matrix(graph_matrix);
        System.out.println("基于邻接矩阵的拓扑序列:" + result_matrix);

        // 基于邻接表进行拓扑排序
        List<Integer> result_list = topologicalSort_list(graph_list);
        System.out.println("基于邻接表的拓扑序列:" + result_list);
    }
}

结束语

图的拓扑排序是图论中一项重要的技术,Kahn算法是一种高效的拓扑排序算法,本文对该算法的原理、步骤和Java实现进行了详细介绍。掌握拓扑排序的技术不仅能增强您的算法技能,还能在实际应用中解决许多问题。