• prim
1
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
function prim(data, source) {
// dist存放路径距离,path存放父顶点,visit存放访问过的顶点
var mst = [], dist = [], visit = [], sum = 0;
var len = data.length;
// 初始化
for (var i = 0; i < len; i++) {
dist[i] = data[source][i]; // 源点到相邻顶点的权值
visit[i] = false;
}
dist[source] = 0;
visit[source] = true;
for (var i = 1; i < len; i++) { // 除去源点的各顶点
// 寻找已存在顶点到各顶点最小的路径;
var min = {idx: -1, weight: Infinity}; // 下标,权重
for (var j = 0; j < len; j++) {
if ( false == visit[j] && dist[j] < min.weight ) {
min = {idx: j, weight: dist[j]};
}
}
if ( min.idx === -1 )
continue;
visit[ min.idx ] = true;
mst.push(min);
sum += min.weight;
for (var k = 0; k < len; k++) {
if ( false !== visit[j]
&& data[min.idx][k] != 0
&& data[min.idx][k] < dist[k] ) {
dist[k] = data[min.idx][k];
}
}
}
console.log(mst, sum)
}
var m = [
[0, 7, Infinity, 5, Infinity, Infinity, Infinity],
[7, 0, 8, 9, 7, Infinity, Infinity],
[Infinity, 8, 0, Infinity, 5, Infinity, Infinity],
[5, 9, Infinity, 0, 15, 6, Infinity],
[Infinity, 7, 5, 15, 0, 8, 9],
[Infinity, Infinity, Infinity, 6, 9, 0, 11],
[Infinity, Infinity, 8, Infinity, 9, 11, 0],
];
prim(m, 3)
  • kruskal
1
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
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
//快速排序 数组a由对象组成 key为排序的参照指标 quickSort(0,a.length-1,a,'key')
function quickSort(left, right, a, key) {
if (left > right)
return;
var i = left;
var j = right;
var benchMark = a[i];
var temp;
while (i != j) {
//移动 j
while (a[j][key] >= benchMark[key] && i < j)
j--;
//移动 i
while (a[i][key] <= benchMark[key] && i < j)
i++;
if (i < j) {
temp = a[i];
a[i] = a[j];
a[j] = temp;
}
}
a[left] = a[i];
a[i] = benchMark;
quickSort(left, i - 1, a, key);
quickSort(i + 1, right, a, key);
}
var MakeSet = (function() {
let set = new Set();
return function(x) {
x.parent = x;
x.rank = 0;
if (!set.has(x)) set.add(x);
return set;
}
})();
//体会两个 Find 方法的不同
// function Find(x) {
// if (x.parent != x)
// Find(x.parent);
// return x.parent;
// }
function Find(x) {
if (x.parent != x)
x.parent = Find(x.parent);
return x.parent;
}
function Union(u, v) {
let uRoot = Find(u);
let vRoot = Find(v);
// 如果 u 和 v 在同一颗树
if (uRoot == vRoot) return;
// 如果 u 和 v 不在同一颗树中,合并它们
// 如果 uRoot 的层级比 vRoot 的小,将 uRoot 作为 vRoot 前驱节点
if (uRoot.rank < vRoot.rank) uRoot.parent = vRoot;
// 如果 uRoot 的层级比 vRoot 的大,将 vRoot 作为 uRoot 前驱节点
else if (uRoot.rank > vRoot.rank) vRoot.parent = uRoot;
//任选一个作为根节点
else {
vRoot.parent = uRoot;
uRoot.rank = uRoot.rank + 1;
}
}
function Kruskal(G) {
let A = []; //A用于存放最小生成数所包含的边
for(let x of G.V) {
MakeSet(x);
}
//对G.E按照边的权中从小到大排序
for(let e of G.E) {
quickSort(0, G.E.length-1, G.E, 'w');
}
for(let e of G.E) {
let u = G.V[G.refer.get(e.u)];
let v = G.V[G.refer.get(e.v)];
if(Find(u)!=Find(v)) {
A.push(e);
Union(u, v);
}
}
return A;
}
function Vertex() {
if (!(this instanceof Vertex))
return new Vertex();
this.edges = null; //由顶点发出的所有边
this.id = null; //节点的唯一标识
this.data = null; //存放节点的数据
}
//数据结构 邻接链表-边
function Edge() {
if (!(this instanceof Edge))
return new Edge();
this.index = null; //边所依附的节点的位置
this.sibling = null;
this.w = null; //保存边的权值
}
//数据结构 图-G
function Graph() {
if (!(this instanceof Graph))
return new Graph();
this.V = []; //节点集
this.E = [];
this.refer = new Map(); //字典 用来映射标节点的识符和数组中的位置
}
Graph.prototype = {
constructor: Graph,
//这里加进来的已经具备了边的关系
//创建图的 节点
initVertex: function(vertexs) {
//创建节点并初始化节点属性 id
for (let v of vertexs) {
let vertex = Vertex();
vertex.id = v.id;
this.V.push(vertex);
}
//初始化 字典
for (let i in this.V) {
this.refer.set(this.V[i].id, i);
}
},
//建立图中 边 的关系
initEdge: (function() {
//创建链表,返回链表的第一个节点
function createLink(index, len, edges, refer) {
if (index >= len) return null;
let edgeNode = Edge();
edgeNode.index = refer.get(edges[index].id); //边连接的节点 用在数组中的位置表示 参照字典
edgeNode.w = edges[index].w; //边的权值
edgeNode.sibling = createLink(++index, len, edges, refer); //通过递归实现 回溯
return edgeNode;
}
return function(edges) {
for (let field in edges) {
let index = this.refer.get(field); //从字典表中找出节点在 V 中的位置
let vertex = this.V[index]; //获取节点
vertex.edges = createLink(0, edges[field].length, edges[field], this.refer);
}
}
}()),
storageEdge: function(edges) {
this.E = edges;
}
}
//测试数据
var vertexs = [{id:'a'}, {id:'b'}, {id:'c'}, {id:'d'}, {id:'e'}];
var edges = [
{u:'a',v:'b',w:3},
{u:'a',v:'c',w:1},
{u:'b',v:'a',w:3},
{u:'b',v:'c',w:4},
{u:'b',v:'d',w:5},
{u:'c',v:'a',w:1},
{u:'c',v:'b',w:4},
{u:'c',v:'d',w:6},
{u:'c',v:'e',w:7},
{u:'d',v:'b',w:5},
{u:'d',v:'c',w:6},
{u:'d',v:'e',w:2},
{u:'e',v:'c',w:7},
{u:'e',v:'d',w:6}
]
var g = Graph();
g.initVertex(vertexs);
g.storageEdge(edges);
var A = Kruskal(g);
console.log(A);

ps:kruskal:https://segmentfault.com/a/1190000012649227