返回

成功在华为OD机试中扬名立万:拓扑排序保驾护航

前端

拓扑排序:让项目管理更井然有序

什么是拓扑排序?

拓扑排序是一种算法,可用于对非循环有向图(DAG)中的顶点进行排序。DAG 是一种特殊类型的有向图,其中不存在环。拓扑排序的目标是找到一种顶点排列,使得每个顶点都出现在其所有后继顶点之前。

为什么拓扑排序很重要?

拓扑排序在许多领域都有着广泛的应用,包括:

  • 项目管理: 确定项目任务的正确顺序,以确保任务按正确顺序完成。
  • 任务调度: 为计算机上的任务分配适当的资源,以优化执行时间。
  • 软件依赖管理: 确保软件组件以正确的顺序构建和部署。

Java 代码示例

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;

public class TopologicalSort {

    private List<Integer> sortedList;
    private int[] inDegrees;
    private List<List<Integer>> adjList;

    public TopologicalSort(int numVertices) {
        sortedList = new ArrayList<>();
        inDegrees = new int[numVertices];
        adjList = new ArrayList<>();
        for (int i = 0; i < numVertices; i++) {
            adjList.add(new ArrayList<>());
        }
    }

    public void addDirectedEdge(int source, int destination) {
        adjList.get(source).add(destination);
        inDegrees[destination]++;
    }

    public List<Integer> topologicalSort() {
        Queue<Integer> zeroInDegreeVertices = new LinkedList<>();
        for (int i = 0; i < inDegrees.length; i++) {
            if (inDegrees[i] == 0) {
                zeroInDegreeVertices.add(i);
            }
        }

        while (!zeroInDegreeVertices.isEmpty()) {
            int currentVertex = zeroInDegreeVertices.poll();
            sortedList.add(currentVertex);

            for (int adjacentVertex : adjList.get(currentVertex)) {
                inDegrees[adjacentVertex]--;
                if (inDegrees[adjacentVertex] == 0) {
                    zeroInDegreeVertices.add(adjacentVertex);
                }
            }
        }

        return sortedList;
    }

    public static void main(String[] args) {
        TopologicalSort topologicalSort = new TopologicalSort(6);
        topologicalSort.addDirectedEdge(0, 1);
        topologicalSort.addDirectedEdge(0, 2);
        topologicalSort.addDirectedEdge(1, 3);
        topologicalSort.addDirectedEdge(1, 4);
        topologicalSort.addDirectedEdge(2, 5);
        topologicalSort.addDirectedEdge(3, 5);
        topologicalSort.addDirectedEdge(4, 5);

        List<Integer> sortedOrder = topologicalSort.topologicalSort();
        System.out.println(sortedOrder); // 输出:[0, 2, 1, 3, 4, 5]
    }
}

JS 代码示例

class TopologicalSort {
  constructor(numVertices) {
    this.sortedList = [];
    this.inDegrees = new Array(numVertices).fill(0);
    this.adjList = Array.from({ length: numVertices }, () => []);
  }

  addDirectedEdge(source, destination) {
    this.adjList[source].push(destination);
    this.inDegrees[destination]++;
  }

  topologicalSort() {
    const zeroInDegreeVertices = [];
    for (let i = 0; i < this.inDegrees.length; i++) {
      if (this.inDegrees[i] === 0) {
        zeroInDegreeVertices.push(i);
      }
    }

    while (zeroInDegreeVertices.length > 0) {
      const currentVertex = zeroInDegreeVertices.shift();
      this.sortedList.push(currentVertex);

      for (const adjacentVertex of this.adjList[currentVertex]) {
        this.inDegrees[adjacentVertex]--;
        if (this.inDegrees[adjacentVertex] === 0) {
          zeroInDegreeVertices.push(adjacentVertex);
        }
      }
    }

    return this.sortedList;
  }
}

const topologicalSort = new TopologicalSort(6);
topologicalSort.addDirectedEdge(0, 1);
topologicalSort.addDirectedEdge(0, 2);
topologicalSort.addDirectedEdge(1, 3);
topologicalSort.addDirectedEdge(1, 4);
topologicalSort.addDirectedEdge(2, 5);
topologicalSort.addDirectedEdge(3, 5);
topologicalSort.addDirectedEdge(4, 5);

const sortedOrder = topologicalSort.topologicalSort();
console.log(sortedOrder); // 输出:[0, 2, 1, 3, 4, 5]

常见问题解答

  1. 拓扑排序如何检测环形依赖关系?
    拓扑排序无法检测环形依赖关系,因为它假设图中不存在环。如果图中存在环,则拓扑排序将无法找到顶点的正确顺序。
  2. 在哪些情况下拓扑排序不适用?
    拓扑排序仅适用于 DAG。如果图中存在环,则无法进行拓扑排序。
  3. 如何优化拓扑排序算法?
    可以使用 Kahn 算法对拓扑排序进行优化。Kahn 算法使用一个队列来存储具有 0 入度的顶点,并在队列非空时执行拓扑排序。
  4. 拓扑排序有哪些替代方法?
    拓扑排序的替代方法包括深度优先搜索和 Kosaraju 算法。
  5. 拓扑排序的优势是什么?
    拓扑排序的主要优势在于它是一种简单、有效且易于理解的算法。它可以用于解决各种实际问题,例如项目管理、任务调度和软件依赖管理。