有向圖的拓撲排序的理解和簡單實現(Java)


如果圖中存在環(回路),那么該圖不存在拓撲排序,在這里我們討論的都是無環的有向圖。

什么是拓撲排序

一個例子

對於一部電影的制作過程,我們可以看成是一個項目工程。所有的工程都可以分為若干個"活動"的自工程。在這些活動之間,通常會受到一定的條件約束,如其中某些活動必須在另一些活動完成之后才能開始。比如,電影制作不可能在人員到位進駐場地時,導演還沒有找到,也不可能在拍攝過程中,場地都沒有。這些聽起來就很荒謬。

在一個表示工程的有向圖中,用頂點表示活動,用弧表示活動之間的優先關系,這樣的有向圖為頂點表示活動的網,稱為AOV網(Activity On Vertex Network)。
AOV網中的弧表示活動之間存在的某種制約關系。

設G={V, E}是一個具有n個頂點的有向圖,V中的頂點序列 v 1 v_1 v 2 v_2 ,…, v n v_n 滿足若從頂點 v i v_i v j v_j 有一條路徑,則在頂點序列中頂點 v i v_i 必在頂點 v j v_j 之前。則我們成這樣的頂點序列為一個拓撲序列。
摘自:《大話數據結構》

那么拓撲排序,其實就是對一個有向圖構造拓撲序列的過程。構造時有兩個結果:

  1. 如果此網的全部頂點都被輸出,說明該網是不存在環的AOV網
  2. 如果輸出的頂點數少了,說明這個網存在環,不是一個AOV網

算法思路

從AOV網中選擇一個入度為0的頂點輸出,然后刪去此頂點,並刪除以此頂點為尾的弧。繼續重復此步驟,直到輸出全部頂點或者AOV網中不存在入度為0的頂點為止。

算法實現

數據結構

由於拓撲排序中,需要刪除頂點,那么采用鄰接矩陣的方式就不太合適,我們可以使用鄰接表,這樣會更方便。
在算法運行過程中,始終要查找入度為0的頂點,我們在原來頂點表結構的基礎上,增加一個入度域in,表示該頂點入度的數字。
邊表節點結構體:

public class EdgeNode {

	int adjevex;
	int weight;
	EdgeNode next;
	
	public EdgeNode(int adjevex, EdgeNode next) {
		this.adjevex = adjevex;
		this.next = next;
	}
}

頂點表節點結構體:

public class VertexNode {

	int in;
	Object data;
	EdgeNode firstedge;
	
	public VertexNode(Object data, int in, EdgeNode firstedge) {
		this.data = data;
		this.in = in;
		this.firstedge = firstedge;
	}
}

示例AOV圖:
在這里插入圖片描述
對應的鄰接表為:
在這里插入圖片描述
在算法中,我們還需要使用到一個,用來存儲處理過程中入度為0的頂點下標,目的是為了避免每次查找時都需要遍歷頂點表找有沒有入度為0的頂點。

拓撲算法代碼實現:

package 拓撲排序;

import java.util.Stack;

public class TopologySort {

	static VertexNode[] adjList;
	Stack stack = new Stack();
	
	public String ToplogicalSort() {
		EdgeNode e;
		int k, gettop;
		int count = 0;
		for (int i = 0; i < adjList.length; i++) {
			if(adjList[i].in  == 0) {
				stack.push(i);
			}
		}
		while(!stack.empty()) {
			gettop = (int) stack.pop();
			System.out.print(adjList[gettop].data + "->");
			count++;
			for (e = adjList[gettop].firstedge; e != null; e = e.next) {
				k = e.adjevex;
				if((--adjList[k].in) == 0) {   //將其入度減少一位,目的是將頂點上的弧刪除
					stack.push(k);
				}
			}
		}
		System.out.println();
		return count < adjList.length ? (String) "ERROR" : (String) "OK";
	}
	
	public static EdgeNode getAdjvex(VertexNode node) {
		EdgeNode e = node.firstedge;
		while(e != null) {
			if(e.next == null) break;
			else
				e = e.next;
		}
		return e;
	}
	
	
	public static void main(String[] args) {
		int[] ins = {0, 0, 2, 0, 2,3,1,2,2,1,1,2,1,2};
		int[][] adjvexs = {
				{11, 5, 4},
				{8,4,2},
				{9, 6, 5},
				{13, 2},
				{7},
				{12, 8},
				{5},
				{},
				{7},
				{11, 10},
				{13},
				{},
				{9},
				{}
		};
		adjList = new VertexNode[ins.length];
		for (int i = 0; i < ins.length; i++) {
			adjList[i] = new VertexNode("V"+i, ins[i],null);
			if(adjvexs[i].length > 0) {
				for (int j = 0; j < adjvexs[i].length; j++) {
					if(adjList[i].firstedge == null) 
						adjList[i].firstedge = new EdgeNode(adjvexs[i][j], null);
					else {
						getAdjvex(adjList[i]).next = new EdgeNode(adjvexs[i][j], null);
					} 	
				}
			}
		}
		TopologySort t = new TopologySort();
		
		System.out.println(t.ToplogicalSort());
		
	}
	
}

該算法的時間復雜度為O(n+e)。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM