圖-最小樹
如果一個(gè)圖中所有點(diǎn)都是聯(lián)通的,求最小樹可以將圖遍歷完成,這里的最小是指邊最少,跟邊長沒有關(guān)系。
算法利用深度優(yōu)先遍歷,記載每個(gè)遍歷過的節(jié)點(diǎn),將節(jié)點(diǎn)按照遍歷順序記錄下來就是所謂的最小樹。
關(guān)于深度優(yōu)先遍歷請(qǐng)參見深度優(yōu)先遍歷。
不過這里奇怪的是:
假如所有節(jié)點(diǎn)之間是雙向聯(lián)通的,只用生成一個(gè)數(shù)組,裝入所有的節(jié)點(diǎn),例如{'a','b','c','d','d'}
然后每兩個(gè)點(diǎn)之間的線段就是最小樹的結(jié)果,即a --> b, b --> c, c --> d, d --> e
似乎不用圖這樣復(fù)雜的結(jié)構(gòu)支撐。
不過這里還是給出了按照?qǐng)D來產(chǎn)生最小樹的辦法。
Graph.mst:返回最小樹。
Graph.main:提供簡單測(cè)試。
代碼如下:
1
class Stack {
2
private int[] values;
3
private int pos = -1;
4
Stack(int size) {
5
values = new int[size];
6
}
7
void push(int value) { values[++pos] = value; }
8
int pop() { return values[pos--]; }
9
int peek() { return values[pos]; }
10
boolean isEmpty() { return pos == -1; }
11
}
12
13
class Vertex {
14
private Object value;
15
private boolean isVisited;
16
Vertex(Object value) {
17
this.value = value;
18
}
19
20
void visit() { isVisited = true; }
21
void clean() { isVisited = false; }
22
boolean isVisited() { return isVisited; }
23
Object value() { return value; }
24
}
25
26
class Graph {
27
private Vertex[] vertexs;
28
private int[][] adjMat;
29
private int pos = -1;
30
31
Graph(int size) {
32
vertexs = new Vertex[size];
33
adjMat = new int[size][size];
34
}
35
36
void add(Object value) {
37
assert pos < vertexs.length;
38
vertexs[++pos] = new Vertex(value);
39
}
40
41
void connect(int from, int to) {
42
adjMat[from][to] = 1;
43
adjMat[to][from] = 1;
44
}
45
46
void connectAll() {
47
for(int i=0; i<= pos; i++)
48
for(int j=0; j<= pos; j++)
49
adjMat[i][j] = i^j&1;
50
51
}
52
int findNeighbor(int index) {
53
for(int i=0; i<=pos; i++) {
54
if(adjMat[index][i] == 1 && !vertexs[i].isVisited()) return i;
55
}
56
return -1;
57
}
58
59
Object[] mst(int index) { //從指定下標(biāo)的節(jié)點(diǎn)開始生成最小數(shù)
60
if(vertexs[index] == null) return new Object[0]; //如果圖中沒有指定下標(biāo)節(jié)點(diǎn),則退出
61
62
Stack s = new Stack(vertexs.length); //創(chuàng)建棧記載訪問過的節(jié)點(diǎn)的下標(biāo)
63
Object[] result = new Object[pos+1]; //返回的結(jié)果
64
int i = 0;
65
vertexs[index].visit(); //訪問0節(jié)點(diǎn)
66
result[i++] = vertexs[index].value();
67
s.push(index); //記錄0節(jié)點(diǎn)
68
69
while(!s.isEmpty()) { //如果還有記錄的節(jié)點(diǎn)則繼續(xù)
70
index = findNeighbor(s.peek()); //尋找棧頂節(jié)點(diǎn)的未訪問過的鄰居
71
if(index != -1) { //如果找到
72
vertexs[index].visit(); //訪問該節(jié)點(diǎn)
73
result[i++] = vertexs[index].value();
74
s.push(index); //記錄該節(jié)點(diǎn)
75
} else s.pop(); //沒有未訪問過的節(jié)點(diǎn),則出棧
76
} //如果棧未空則代表遍歷完成
77
clean(); //清除所有訪問標(biāo)致
78
return result;
79
}
80
81
void clean() { for(Vertex v: vertexs) if(v != null)v.clean(); }
82
83
public static void main(String[] args) {
84
Graph g = new Graph(20);
85
g.add('a');
86
g.add('b');
87
g.add('c');
88
g.add('d');
89
g.add('e');
90
g.connectAll();
91
Object[] result = g.mst(0);
92
for(int i=0; i<result.length-1; i++) {
93
System.out.println(result[i] + " --> " + result[i+1]);
94
}
95
}
96
}

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96
