當每個任務有前后置關系時,需要找到一種滿足前后置關系的路線,將任務完成。
如果將每個任務看成一個節點,任務之間的前后置關系表示為有向圖時,這種路線順序叫做為圖進行拓撲排序。也叫關鍵路徑分析。
這里的圖用鄰接矩陣法表示,算法的關鍵是:
1 找到一個沒有后繼的頂點
2 在圖中刪除它,放入結果數組中
3 重復 步驟 1 ,步驟 2 直到圖中沒有多余的節點。
如果圖中出現環裝結構,則算法無法進行,因為此時任務之間循環成為前置。
關于鄰接矩陣法請參見:Graph 圖-鄰接表法。
要注意的是:滿足前后置關系的路徑可能不止一條。這里僅僅得到其中的一條。
關鍵API:
int noNext():返回沒有后繼的節點的下標。
remove(int index):刪除指定下標的節點,同時在鄰接矩陣中刪除相對應的行與列。
main:提供簡單的測試。
代碼如下:
1
class Vertex
{ //圖中的節點
2
private Object value;
3
Vertex(Object value)
{
4
this.value = value;
5
}
6
Object value()
{ return value; }
7
@Override public String toString()
{ return "" + value; }
8
}
9
10
class Topology
{ //用鄰接矩陣法表示的圖
11
private Vertex[] vertexs;
12
private Object[][] adjMat; //記載是否聯通
13
private int length = 0;
14
private static Object CONN = new Object(); //標致是否聯通
15
16
Topology(int size)
{
17
vertexs = new Vertex[size];
18
adjMat = new Object[size][size];
19
}
20
21
void add(Object value)
{
22
assert length <= vertexs.length;
23
vertexs[length++] = new Vertex(value);
24
}
25
26
void connect(int from, int to)
{
27
assert from < length;
28
assert to < length;
29
adjMat[from][to] = CONN; //標志聯通
30
}
31
32
void remove(int index)
{ //移除指定的頂點
33
remove(vertexs,index); //在頂點數組中刪除指定位置的下標
34
for(Object[] bs: adjMat) remove(bs,index); //鄰接矩陣中刪除指定的列
35
remove(adjMat,index); //在鄰接矩陣中刪除指定的行
36
length--;
37
}
38
39
private void remove(Object[] a, int index)
{ //在數組中移除指定的元素,后面的元素補上空位
40
for(int i=index; i<length-1; i++) a[i] = a[i+1];
41
}
42
43
int noNext()
{ //尋找沒有后繼的節點
44
int result = -1;
45
OUT:
46
for(int i=0; i<length; i++)
{
47
for(int j=0; j<length; j++)
{
48
if(adjMat[i][j] == CONN)continue OUT; //如果有后繼則從外循環繼續尋找
49
}
50
return i; //如果沒有與任何節點相連,則返回該節點下標
51
}
52
return -1; //否則返回-1
53
}
54
55
Object[] topo()
{
56
Object[] result = new Object[length]; //準備結果數組
57
int index;
58
int pos = length;
59
while(length > 0)
{
60
index = noNext(); //找到第一個沒有后繼的節點
61
assert index != -1 : "圖中存在環";
62
result[--pos] = vertexs[index]; //放入結果中
63
remove(index); //從圖中把它刪除
64
}
65
return result;
66
}
67
68
public static void main(String[] args)
{
69
Topology g = new Topology(20);
70
g.add('a');
71
g.add('b');
72
g.add('c');
73
g.add('d');
74
g.add('e');
75
g.add('f');
76
g.add('g');
77
g.add('h');
78
79
g.connect(0,3);
80
g.connect(0,4);
81
g.connect(1,4);
82
g.connect(2,5);
83
g.connect(3,6);
84
g.connect(4,6);
85
g.connect(5,7);
86
g.connect(6,7);
87
88
for(Object o: g.topo()) System.out.print(o + " ");
89
System.out.println();
90
}
91
}