Skip to content

Commit 2f90ba9

Browse files
author
Mauro Bringolf
committed
Raw implementation and test case from wikipedia
1 parent 15f784e commit 2f90ba9

File tree

2 files changed

+134
-0
lines changed

2 files changed

+134
-0
lines changed

src/graphs/spanning-trees/kruskal.js

+81
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
// Kruskal's algorithm for minimal spanning tree implemented with the UnionFind datastructure.
2+
3+
(function(exports) {
4+
'use strict';
5+
6+
var QuickUnion = require('../../sets/quickunion').QuickUnion;
7+
var mergeSort = require('../../sorting/mergesort').mergeSort;
8+
exports.Vertex = require('../../data-structures/vertex').Vertex;
9+
exports.Edge = require('../../data-structures/edge').Edge;
10+
11+
exports.Graph = function (edges) {
12+
this.edges = edges || [];
13+
}
14+
15+
exports.Graph.prototype.kruskal = (function () {
16+
var qunion;
17+
var spanningTree;
18+
var indexes;
19+
20+
/**
21+
* Used for sorting the edges
22+
*
23+
* @private
24+
* @param {Vertex} a First operand of the comparison.
25+
* @param {Vertex} b Second operand of the comparison.
26+
* @return {number} Number which which is equal, greater or
27+
* less then zero and indicates whether the first vertex is
28+
* "smaller" than the second.
29+
*/
30+
function compareEdges(a, b) {
31+
return a.distance - b.distance;
32+
}
33+
34+
/**
35+
* Initialize the algorithm.
36+
*
37+
* @private
38+
*/
39+
function init() {
40+
var edge;
41+
var i = 0;
42+
43+
mergeSort(this.edges, compareEdges);
44+
spanningTree = [];
45+
indexes = {};
46+
47+
// Create links from vertices to QuickUnion elements
48+
for (edge of this.edges) {
49+
if (!(edge.from.id in indexes)) {
50+
indexes[edge.from.id] = i;
51+
i += 1;
52+
}
53+
if (!(edge.to.id in indexes)) {
54+
indexes[edge.to.id] = i;
55+
i += 1;
56+
}
57+
}
58+
59+
qunion = new QuickUnion(i);
60+
}
61+
62+
return function () {
63+
init.call(this);
64+
65+
var edge;
66+
67+
for (edge of this.edges) {
68+
var from = indexes[edge.from.id];
69+
var to = indexes[edge.to.id];
70+
if (!qunion.connected(from, to)) {
71+
qunion.union(from, to);
72+
spanningTree.push(edge);
73+
}
74+
}
75+
76+
return new exports.Graph(spanningTree);
77+
}
78+
79+
})();
80+
81+
})(typeof window === 'undefined' ? module.exports : window);
+53
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
var kruskal = require('../../../src/graphs/spanning-trees/kruskal');
2+
3+
describe('Kruskal', function() {
4+
'use strict';
5+
6+
it('should define a function', function () {
7+
expect(kruskal).toBeDefined();
8+
expect(typeof kruskal).toBe('object');
9+
expect(typeof kruskal.Graph).toBe('function');
10+
expect(typeof kruskal.Edge).toBe('function');
11+
expect(typeof kruskal.Vertex).toBe('function');
12+
});
13+
14+
it('should work with an empty graph', function() {
15+
var graph = new kruskal.Graph([], 0);
16+
var spanningTree = graph.kruskal();
17+
18+
expect(spanningTree.edges.length).toEqual(0);
19+
});
20+
21+
it('should correctly compute general example', function() {
22+
var nodes = [];
23+
var edges = [];
24+
var i;
25+
for (i = 0; i < 7; i += 1) {
26+
nodes[i] = new kruskal.Vertex(i);
27+
}
28+
29+
edges.push(new kruskal.Edge(nodes[0], nodes[1], 7));
30+
edges.push(new kruskal.Edge(nodes[1], nodes[2], 8));
31+
edges.push(new kruskal.Edge(nodes[2], nodes[4], 5));
32+
edges.push(new kruskal.Edge(nodes[4], nodes[6], 9));
33+
edges.push(new kruskal.Edge(nodes[5], nodes[6], 11));
34+
edges.push(new kruskal.Edge(nodes[3], nodes[5], 6));
35+
edges.push(new kruskal.Edge(nodes[0], nodes[3], 5));
36+
edges.push(new kruskal.Edge(nodes[1], nodes[4], 7));
37+
edges.push(new kruskal.Edge(nodes[1], nodes[3], 9));
38+
edges.push(new kruskal.Edge(nodes[3], nodes[4], 15));
39+
edges.push(new kruskal.Edge(nodes[4], nodes[5], 8));
40+
41+
var graph = new kruskal.Graph(edges);
42+
var spanningTree = graph.kruskal();
43+
44+
expect(spanningTree.edges.length).toEqual(6);
45+
46+
var sum = spanningTree.edges.reduce(function(acc, edge) {
47+
return acc += edge.distance;
48+
}, 0);
49+
50+
expect(sum).toEqual(39);
51+
52+
})
53+
});

0 commit comments

Comments
 (0)