如果一个图中所有点都是联通的,求最小树可以将图遍历完成,这里的最小是指边最少,跟边长没有关系。
算法利用深度优先遍历,记载每个遍历过的节点,将节点按照遍历顺序记录下来就是所谓的最小树。
关于深度优先遍历请参见深度优先遍历。
不过这里奇怪的是:
假如所有节点之间是双向联通的,只用生成一个数组,装入所有的节点,例如{'a','b','c','d','d'}
然后每两个点之间的线段就是最小树的结果,即a --> b, b --> c, c --> d, d --> e
似乎不用图这样复杂的结构支撑。
不过这里还是给出了按照图来产生最小树的办法。
Graph.mst:返回最小树。
Graph.main:提供简单测试。
代码如下:
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) { //从指定下标的节点开始生成最小数
60 if(vertexs[index] == null) return new Object[0]; //如果图中没有指定下标节点,则退出
61
62 Stack s = new Stack(vertexs.length); //创建栈记载访问过的节点的下标
63 Object[] result = new Object[pos+1]; //返回的结果
64 int i = 0;
65 vertexs[index].visit(); //访问0节点
66 result[i++] = vertexs[index].value();
67 s.push(index); //记录0节点
68
69 while(!s.isEmpty()) { //如果还有记录的节点则继续
70 index = findNeighbor(s.peek()); //寻找栈顶节点的未访问过的邻居
71 if(index != -1) { //如果找到
72 vertexs[index].visit(); //访问该节点
73 result[i++] = vertexs[index].value();
74 s.push(index); //记录该节点
75 } else s.pop(); //没有未访问过的节点,则出栈
76 } //如果栈未空则代表遍历完成
77 clean(); //清除所有访问标致
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 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) { //从指定下标的节点开始生成最小数
60 if(vertexs[index] == null) return new Object[0]; //如果图中没有指定下标节点,则退出
61
62 Stack s = new Stack(vertexs.length); //创建栈记载访问过的节点的下标
63 Object[] result = new Object[pos+1]; //返回的结果
64 int i = 0;
65 vertexs[index].visit(); //访问0节点
66 result[i++] = vertexs[index].value();
67 s.push(index); //记录0节点
68
69 while(!s.isEmpty()) { //如果还有记录的节点则继续
70 index = findNeighbor(s.peek()); //寻找栈顶节点的未访问过的邻居
71 if(index != -1) { //如果找到
72 vertexs[index].visit(); //访问该节点
73 result[i++] = vertexs[index].value();
74 s.push(index); //记录该节点
75 } else s.pop(); //没有未访问过的节点,则出栈
76 } //如果栈未空则代表遍历完成
77 clean(); //清除所有访问标致
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}