Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit f247d77

Browse files
committedMay 26, 2017
kruskal
1 parent 1e0ad5f commit f247d77

File tree

5 files changed

+251
-0
lines changed

5 files changed

+251
-0
lines changed
 

Diff for: ‎README.md

+35
Original file line numberDiff line numberDiff line change
@@ -194,4 +194,39 @@ console.log(scc.componentCount()); // display 5
194194
for (var v = 0; v < graph.V; ++v) {
195195
console.log('id[' + v + ']: ' + scc.componentId(v));
196196
}
197+
```
198+
199+
### Use Kruskal algorithm to find the minimum spanning tree of a weighted graph
200+
201+
The sample code below show how to obtain the minimum spanning tree from a weighted graph using Kruskal algorithm:
202+
203+
```javascript
204+
jsgraphs = require('js-graph-algorithms');
205+
var g = new jsgraphs.WeightedGraph(8);
206+
207+
g.addEdge(new jsgraphs.Edge(0, 7, 0.16));
208+
g.addEdge(new jsgraphs.Edge(2, 3, 0.17));
209+
g.addEdge(new jsgraphs.Edge(1, 7, 0.19));
210+
g.addEdge(new jsgraphs.Edge(0, 2, 0.26));
211+
g.addEdge(new jsgraphs.Edge(5, 7, 0.28));
212+
g.addEdge(new jsgraphs.Edge(1, 3, 0.29));
213+
g.addEdge(new jsgraphs.Edge(1, 5, 0.32));
214+
g.addEdge(new jsgraphs.Edge(2, 7, 0.34));
215+
g.addEdge(new jsgraphs.Edge(4, 5, 0.35));
216+
g.addEdge(new jsgraphs.Edge(1, 2, 0.36));
217+
g.addEdge(new jsgraphs.Edge(4, 7, 0.37));
218+
g.addEdge(new jsgraphs.Edge(0, 4, 0.38));
219+
g.addEdge(new jsgraphs.Edge(6, 2, 0.4));
220+
g.addEdge(new jsgraphs.Edge(3, 6, 0.52));
221+
g.addEdge(new jsgraphs.Edge(6, 0, 0.58));
222+
g.addEdge(new jsgraphs.Edge(6, 4, 0.93));
223+
224+
var kruskal = new jsgraphs.KruskalMST(g);
225+
var mst = kruskal.mst;
226+
for(var i=0; i < mst.length; ++i) {
227+
var e = mst[i];
228+
var v = e.either();
229+
var w = e.other(v);
230+
console.log('(' + v + ', ' + w + '): ' + e.weight);
231+
}
197232
```

Diff for: ‎src/jsgraphs.js

+142
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,17 @@
11
var jsgraphs = jsgraphs || {};
22

33
(function(jss){
4+
5+
jss.less = function(a1, a2, compare) {
6+
return compare(a1, a2) < 0;
7+
};
8+
9+
jss.exchange = function(a, i, j) {
10+
var temp = a[i];
11+
a[i] = a[j];
12+
a[j] = temp;
13+
};
14+
415
var StackNode = function (value) {
516
this.value = value;
617
this.next = null;
@@ -133,6 +144,102 @@ var jsgraphs = jsgraphs || {};
133144

134145
jss.Queue = Queue;
135146

147+
var MinPQ = function(compare) {
148+
this.s = [];
149+
this.N = 0;
150+
if(!compare) {
151+
compare = function(a1, a2) {
152+
return a1 - a2;
153+
};
154+
}
155+
this.compare = compare;
156+
};
157+
158+
MinPQ.prototype.enqueue = function(item) {
159+
while(this.s.lengh <= this.N+1) {
160+
this.s.push(0);
161+
}
162+
this.s[++this.N] = item;
163+
this.swim(this.N);
164+
};
165+
166+
MinPQ.prototype.swim = function(k) {
167+
while (k > 1){
168+
var parent = Math.floor(k / 2);
169+
if(jss.less(this.s[k], this.s[parent], this.compare)){
170+
jss.exchange(this.s, k, parent);
171+
k = parent;
172+
} else {
173+
break;
174+
}
175+
}
176+
};
177+
178+
MinPQ.prototype.delMin = function() {
179+
if(this.N == 0) {
180+
return undefined;
181+
}
182+
183+
var item = this.s[1];
184+
jss.exchange(this.s, 1, this.N--);
185+
this.sink(1);
186+
return item;
187+
};
188+
189+
MinPQ.prototype.sink = function(k) {
190+
while(k * 2 <= this.N) {
191+
var child = 2 * k;
192+
if(child < this.N && jss.less(this.s[child+1], this.s[child], this.compare)){
193+
child++;
194+
}
195+
if(jss.less(this.s[child], this.s[k], this.compare)){
196+
jss.exchange(this.s, child, k);
197+
k = child;
198+
} else {
199+
break;
200+
}
201+
}
202+
};
203+
204+
MinPQ.prototype.size = function(){
205+
return this.N;
206+
};
207+
208+
MinPQ.prototype.isEmpty = function() {
209+
return this.N == 0;
210+
};
211+
212+
jss.MinPQ = MinPQ;
213+
214+
var QuickUnion = function(V) {
215+
this.id = [];
216+
for (var v = 0; v < V; ++v) {
217+
this.id.push(v);
218+
}
219+
};
220+
221+
QuickUnion.prototype.union = function(v, w) {
222+
var q = this.root(v);
223+
var p = this.root(w);
224+
225+
if(p != q) {
226+
this.id[p] = q;
227+
}
228+
};
229+
230+
QuickUnion.prototype.root = function(q) {
231+
while(this.id[q] != q) {
232+
q = this.id[q];
233+
}
234+
return q;
235+
};
236+
237+
QuickUnion.prototype.connected = function(v, w) {
238+
return this.root(v) == this.root(w);
239+
};
240+
241+
jss.QuickUnion = QuickUnion;
242+
136243
var Graph = function (V) {
137244
this.V = V;
138245
this.adjList = [];
@@ -433,6 +540,41 @@ var jsgraphs = jsgraphs || {};
433540
};
434541

435542
jss.StronglyConnectedComponents = StronglyConnectedComponents;
543+
544+
var KruskalMST = function(G) {
545+
var V = G.V;
546+
var pq = new jss.MinPQ(function(e1, e2){
547+
return e1.weight - e2.weight;
548+
});
549+
for(var v = 0; v < G.V; ++v){
550+
var adj_v = G.adj(v);
551+
for (var i = 0; i < adj_v.length; ++i) {
552+
var e = adj_v[i];
553+
if(e.either() != v) {
554+
continue;
555+
}
556+
pq.enqueue(e);
557+
}
558+
}
559+
560+
this.mst = [];
561+
562+
var uf = new jss.QuickUnion(V);
563+
while (!pq.isEmpty() && this.mst.length < V-1) {
564+
var e = pq.delMin();
565+
var v = e.either();
566+
var w = e.other(v);
567+
568+
if(!uf.connected(v, w)){
569+
uf.union(v, w);
570+
this.mst.push(e);
571+
}
572+
}
573+
};
574+
575+
576+
577+
jss.KruskalMST = KruskalMST;
436578

437579
})(jsgraphs);
438580

Diff for: ‎test/kruskal-spec.js

+34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
var expect = require('chai').expect;
2+
var jsgraphs = require('../src/jsgraphs');
3+
4+
describe('Kruskal Minimum Spanning Tree', function(){
5+
it('should generate the minimum spanning tree', function(){
6+
var g = new jsgraphs.WeightedGraph(8);
7+
8+
g.addEdge(new jsgraphs.Edge(0, 7, 0.16));
9+
g.addEdge(new jsgraphs.Edge(2, 3, 0.17));
10+
g.addEdge(new jsgraphs.Edge(1, 7, 0.19));
11+
g.addEdge(new jsgraphs.Edge(0, 2, 0.26));
12+
g.addEdge(new jsgraphs.Edge(5, 7, 0.28));
13+
g.addEdge(new jsgraphs.Edge(1, 3, 0.29));
14+
g.addEdge(new jsgraphs.Edge(1, 5, 0.32));
15+
g.addEdge(new jsgraphs.Edge(2, 7, 0.34));
16+
g.addEdge(new jsgraphs.Edge(4, 5, 0.35));
17+
g.addEdge(new jsgraphs.Edge(1, 2, 0.36));
18+
g.addEdge(new jsgraphs.Edge(4, 7, 0.37));
19+
g.addEdge(new jsgraphs.Edge(0, 4, 0.38));
20+
g.addEdge(new jsgraphs.Edge(6, 2, 0.4));
21+
g.addEdge(new jsgraphs.Edge(3, 6, 0.52));
22+
g.addEdge(new jsgraphs.Edge(6, 0, 0.58));
23+
g.addEdge(new jsgraphs.Edge(6, 4, 0.93));
24+
25+
var kruskal = new jsgraphs.KruskalMST(g);
26+
var mst = kruskal.mst;
27+
for(var i=0; i < mst.length; ++i) {
28+
var e = mst[i];
29+
var v = e.either();
30+
var w = e.other(v);
31+
console.log('(' + v + ', ' + w + '): ' + e.weight);
32+
}
33+
});
34+
});

Diff for: ‎test/min-pq-spec.js

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
var expect = require('chai').expect;
2+
var jsgraphs = require('../src/jsgraphs');
3+
4+
describe('MinPQ', function(){
5+
it('should function as min priority queue', function(){
6+
var pq = new jsgraphs.MinPQ();
7+
8+
pq.enqueue(10);
9+
pq.enqueue(9);
10+
pq.enqueue(7);
11+
pq.enqueue(8);
12+
pq.enqueue(3);
13+
pq.enqueue(4);
14+
pq.enqueue(5);
15+
pq.enqueue(2);
16+
pq.enqueue(1);
17+
pq.enqueue(6);
18+
19+
expect(pq.isEmpty()).to.equal(false);
20+
for( var i = 1; i <= 10; ++i) {
21+
expect(pq.delMin()).to.equal(i);
22+
expect(pq.size()).to.equal(10 - i);
23+
}
24+
expect(pq.isEmpty()).to.equal(true);
25+
});
26+
});

Diff for: ‎test/quick-union-spec.js

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
var expect = require('chai').expect;
2+
var jsgraphs = require('../src/jsgraphs');
3+
4+
describe('Quick Union', function(){
5+
it('should work as union find', function(){
6+
var uf = new jsgraphs.QuickUnion(10);
7+
expect(uf.connected(0, 3)).to.equal(false);
8+
uf.union(0, 3);
9+
expect(uf.connected(0, 3)).to.equal(true);
10+
uf.union(0, 7);
11+
expect(uf.connected(0, 7)).to.equal(true);
12+
expect(uf.connected(3, 7)).to.equal(true);
13+
});
14+
});

0 commit comments

Comments
 (0)
Please sign in to comment.