1. 程式人生 > >圖解拓撲排序(Topological sort)

圖解拓撲排序(Topological sort)

一、什麼是拓撲排序

  下圖就是拓撲排序

 

拓撲排序其實是一個線性排序。——若圖中存在一條有向邊從u指向v,則在拓撲排序中u一定出現在v前面

維基百科拓撲排序的定義

topological sort or topological ordering of a directed graph is a linear ordering of its vertices such that for every directed edge uv

 from vertex u to vertex vucomes before v in the ordering. 

 

二、圖解拓撲排序

演算法思路:

1. 從圖中選擇一個沒有前驅(即入度為0)的頂點並輸出。
2. 從圖中刪除該頂點和所有以它為起點的有向邊。
重複 1 和 2 直到圖為空或當前圖中不存在無前驅的頂點為止。

 

偽碼:

 

例子:

. 1.  選入度為0的節點A,  輸出A。  刪除AB AC的邊(B入度為1-1=0,C入度為2-1=1)

   2.  選入度為0的節點B, 輸出B。刪除BC,BE的邊(C入度為1-1=0,E入度-1)

   3.   選入度為0的節點C, 輸出C。刪以C開始的邊(對應節點入度-1)

。。。。。。。。。。。繼續重複。。。。。。。。。。

   注: 拓撲排序結果不唯一(同時有多個入度為0)。

   

 

三、Code in Java

import java.util.*;

// data structure to store graph edges
class Edge
{
	int source, dest;

	public Edge(int source, int dest) {
		this.source = source;
		this.dest = dest;
	}
};

// class to represent a graph object
class Graph
{
	// An array of Lists to represent adjacency list
	List<List<Integer>> adjList = null;

	// stores indegree of a vertex
	List<Integer> indegree = null;

	// Constructor
	Graph(List<Edge> edges, int N) {
		adjList = new ArrayList<>(N);
		for (int i = 0; i < N; i++) {
			adjList.add(i, new ArrayList<>());
		}

		// initialize indegree of each vertex by 0
		indegree = new ArrayList<>(Collections.nCopies(N, 0));

		// add edges to the undirected graph
		for (int i = 0; i < edges.size(); i++)
		{
			int src = edges.get(i).source;
			int dest = edges.get(i).dest;

			// add an edge from source to destination
			adjList.get(src).add(dest);

			// increment in-degree of destination vertex by 1
			indegree.set(dest, indegree.get(dest) + 1);
		}
	}
}

class Main
{
	// performs Topological Sort on a given DAG
	public static List<Integer> doTopologicalSort(Graph graph, int N)
	{
		// list to store the sorted elements
		List<Integer> L = new ArrayList<>();

		// get indegree information of the graph
		List<Integer> indegree = graph.indegree;

		// Set of all nodes with no incoming edges
		Stack<Integer> S = new Stack<>();
		for (int i = 0; i < N; i++) {
			if (indegree.get(i) == 0) {
				S.add(i);
			}
		}

		while (!S.isEmpty())
		{
			// remove a node n from S
			int n = S.pop();

			// add n to tail of L
			L.add(n);

			for (int m : graph.adjList.get(n))
			{
				// remove edge from n to m from the graph
				indegree.set(m, indegree.get(m) - 1);

				// if m has no other incoming edges then
				// insert m into S
				if (indegree.get(m) == 0) {
					S.add(m);
				}
			}
		}

		// if graph has edges then graph has at least one cycle
		for (int i = 0; i < N; i++) {
			if (indegree.get(i) != 0) {
				return null;
			}
		}

		return L;
	}

	public static void main(String[] args)
	{
		// vector of graph edges as per above diagram
		List<Edge> edges = Arrays.asList(
							new Edge(0, 6), new Edge(1, 2), new Edge(1, 4),
							new Edge(1, 6), new Edge(3, 0), new Edge(3, 4),
							new Edge(5, 1), new Edge(7, 0), new Edge(7, 1)
						);

		// Set number of vertices in the graph
		final int N = 8;

		// create a graph from edges
		Graph graph = new Graph(edges, N);

		// Perform Topological Sort
		List<Integer> L = doTopologicalSort(graph, N);

		if (L != null) {
			System.out.print(L);	// print topological order
		} else {
			System.out.println("Graph has at least one cycle. " +
							 "Topological sorting is not possible");
		}
	}
}

 

四、演算法分析

          時間複雜度: O(n + e),其中n為圖中的結點數目,e為圖中的邊的數目

          空間複雜度:O(n)

         也可以用深度優先遍歷DFS和 廣度優先遍歷BFS 實現拓撲排序。