Java 拓扑排序算法设计指南

在计算机科学中,拓扑排序是一种对有向无环图(DAG)中的顶点进行线性排序的算法,使得对于每一条有向边 u -> v,顶点 u 在顶点 v 之前。拓扑排序广泛应用于例如编译器中的任务调度、课程安排等场景。

本文将逐步引导你实现一个简单的 Java 拓扑排序算法。我们将通过一个表格展示整个流程,并细致说明每个步骤所需的代码。

拓扑排序设计流程

步骤 描述
1 定义一个图的结构
2 添加顶点和边
3 进行拓扑排序的实现
4 测试算法

第一步:定义一个图的结构

在这一步,我们需要定义一个图的结构。我们将使用邻接表来表示图。

import java.util.*;

class Graph {
    private int vertices; // 顶点的数量
    private List<List<Integer>> adjacencyList; // 邻接表

    // 构造函数
    public Graph(int vertices) {
        this.vertices = vertices; // 初始化顶点数量
        adjacencyList = new ArrayList<>(vertices); // 初始化邻接表
        for (int i = 0; i < vertices; i++) {
            adjacencyList.add(new ArrayList<>()); // 为每个顶点创建一个列表
        }
    }
    
    // 添加边的方法
    public void addEdge(int source, int destination) {
        adjacencyList.get(source).add(destination); // 向邻接表中添加边
    }

    // 获取邻接表
    public List<List<Integer>> getAdjacencyList() {
        return adjacencyList;
    }
}

第二步:添加顶点和边

在这一步,我们将创建一个图,添加一些顶点和边。

public class Main {
    public static void main(String[] args) {
        Graph graph = new Graph(6); // 创建一个包含6个顶点的图
        graph.addEdge(5, 2); // 添加边 5 -> 2
        graph.addEdge(5, 0); // 添加边 5 -> 0
        graph.addEdge(4, 0); // 添加边 4 -> 0
        graph.addEdge(4, 1); // 添加边 4 -> 1
        graph.addEdge(2, 3); // 添加边 2 -> 3
        graph.addEdge(3, 1); // 添加边 3 -> 1
    }
}

第三步:进行拓扑排序的实现

接下来,我们将实现拓扑排序方法。我们可以使用 Kahn 算法或深度优先搜索(DFS)来完成这一步,这里我们采用 Kahn 算法。

public List<Integer> topologicalSort(Graph graph) {
    int vertices = graph.getAdjacencyList().size(); // 获取顶点数量
    int[] inDegree = new int[vertices]; // 初始化入度数组
    for (List<Integer> neighbors : graph.getAdjacencyList()) {
        for (int neighbor : neighbors) {
            inDegree[neighbor]++; // 更新每个顶点的入度
        }
    }

    Queue<Integer> queue = new LinkedList<>(); // 创建一个队列来存储入度为 0 的顶点
    for (int i = 0; i < vertices; i++) {
        if (inDegree[i] == 0) {
            queue.offer(i); // 将入度为 0 的顶点加入队列
        }
    }

    List<Integer> topologicalOrder = new ArrayList<>(); // 存储拓扑排序的结果
    while (!queue.isEmpty()) {
        int vertex = queue.poll(); // 从队列中取出顶点
        topologicalOrder.add(vertex); // 添加到拓扑序列中
        
        for (int neighbor : graph.getAdjacencyList().get(vertex)) {
            inDegree[neighbor]--; // 将其邻接节点的入度减 1
            if (inDegree[neighbor] == 0) {
                queue.offer(neighbor); // 如果入度为零,加入队列
            }
        }
    }

    if (topologicalOrder.size() != vertices) {
        throw new IllegalStateException("图中存在环,无法进行拓扑排序!"); // 如果结果顶点数不等于原图的顶点数,说明图中存在环
    }
    return topologicalOrder; // 返回拓扑序列
}

第四步:测试算法

最后,我们需要测试我们的拓扑排序算法。

public class Main {
    public static void main(String[] args) {
        Graph graph = new Graph(6);
        graph.addEdge(5, 2);
        graph.addEdge(5, 0);
        graph.addEdge(4, 0);
        graph.addEdge(4, 1);
        graph.addEdge(2, 3);
        graph.addEdge(3, 1);

        List<Integer> topologicalOrder = topologicalSort(graph);
        System.out.println("拓扑排序结果: " + topologicalOrder); // 输出拓扑排序的结果
    }

    // 这里放置前面的 topologicalSort 方法
}

旅行图

journey
    title 拓扑排序的步骤
    section 步骤一:定义图
      实例化图的结构: 5: 5: 5: 6
      创建邻接表: 4: 4: 4: 6
    section 步骤二:添加边
      添加边 5->2: 5: 5: 5
      添加边 5->0: 4: 4: 4
    section 步骤三:拓扑排序
      计算入度: 4: 4: 4: 4
      获取入度为零的节点: 2: 2: 2
    section 步骤四:返回排序
      输出排序结果: 5: 5: 5: 6

类图

classDiagram
    class Graph {
        +int vertices
        +List<List<Integer>> adjacencyList
        +addEdge(int source, int destination)
        +getAdjacencyList()
    }
    class Main {
        +static void main(String[] args)
        +List<Integer> topologicalSort(Graph graph)
    }

结论

本文介绍了如何在 Java 中实现拓扑排序算法的详细步骤。我们定义了图的结构,添加了顶点和边,并实现了基于 Kahn 算法的拓扑排序方法,最后通过测试验证了算法的可行性。希望这些知识能帮助你在未来的开发过程中更好地理解和应用拓扑排序算法。如果你有进一步的问题或需要更深入的分析,欢迎在评论区留言交流!