Adding prim implementation.
parent
106bc4367c
commit
a50034bc48
|
@ -0,0 +1,243 @@
|
|||
"use strict";
|
||||
|
||||
const fs = require('fs');
|
||||
const {EOL} = require('os');
|
||||
|
||||
function findPrimMST(graph) {
|
||||
let heap = [];
|
||||
// we need to make a heap and remove it
|
||||
// one by one. Approach bottom up as it's more
|
||||
// efficient when we create heap from scratch
|
||||
// not just adding single element
|
||||
|
||||
function testHeap() {
|
||||
console.log('Test', heap);
|
||||
for (let i = 0; i < heap.length; i++) {
|
||||
// console.log(`Testing ${i}`);
|
||||
if (2*i+1 < heap.length && heap[2*i+1].w < heap[i].w) {
|
||||
console.log(`Bad ${i} because ${2*i+1} has smaller value ${heap[i].w} > ${heap[2*i+1].w}`);
|
||||
return;
|
||||
}
|
||||
|
||||
if (2*i+2 < heap.length && heap[2*i+2].w < heap[i].w) {
|
||||
console.log(`Bad ${i} because ${2*i+2} has smaller value ${heap[i].w} > ${heap[2*i+2].w}`);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function heapInsert(el) {
|
||||
heap.push(el);
|
||||
let idx = heap.length - 1;
|
||||
let t;
|
||||
while (idx >= 1) {
|
||||
let parent = (idx - 1) >> 1;
|
||||
if (heap[parent].w > heap[idx].w) {
|
||||
t = heap[idx];
|
||||
heap[idx] = heap[parent];
|
||||
heap[parent] = t;
|
||||
idx = parent;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function popSmallest() {
|
||||
let val = heap[0];
|
||||
heap[0] = heap[heap.length - 1];
|
||||
heap.pop();
|
||||
// console.log('Popping first', val);
|
||||
|
||||
// we need to fix from top to bottom
|
||||
// we need to take smallest from descendents
|
||||
|
||||
let idx = 0;
|
||||
let t;
|
||||
while (idx < heap.length) {
|
||||
// console.log(`Checking idx ${idx}`);
|
||||
let smallest = heap[idx].w;
|
||||
if (2*idx + 1 < heap.length) {
|
||||
smallest = Math.min(smallest, heap[2*idx+1].w);
|
||||
}
|
||||
|
||||
if (2*idx + 2 < heap.length) {
|
||||
smallest = Math.min(smallest, heap[2*idx+2].w);
|
||||
}
|
||||
|
||||
// console.log(`Smallest ${smallest}, current: ${heap[idx].w}`);
|
||||
|
||||
if (smallest >= heap[idx].w) {
|
||||
return val; // we're good
|
||||
}
|
||||
|
||||
// we need to have something smaller we try first
|
||||
|
||||
if (smallest === heap[2*idx+1].w) {
|
||||
t = heap[2*idx+1];
|
||||
heap[2*idx+1] = heap[idx];
|
||||
heap[idx] = t;
|
||||
// console.log(`Smallest ${2*idx+1}`);
|
||||
idx = 2*idx+1;
|
||||
|
||||
} else {
|
||||
t = heap[2*idx+2];
|
||||
heap[2*idx+2] = heap[idx];
|
||||
heap[idx] = t;
|
||||
// console.log(`Smallest ${2*idx+2}`);
|
||||
idx = 2*idx+2;
|
||||
}
|
||||
}
|
||||
|
||||
return null; // it should never go here except empty
|
||||
}
|
||||
|
||||
// * TODO troubleshoot it adding bottom up
|
||||
// for (let u in graph.edges) {
|
||||
// for (let {v, w} of graph.edges[u]) {
|
||||
// heap.push({u, v, w}); // bottom up
|
||||
// heapInsert({u,v, w}); // top to bottom
|
||||
// }
|
||||
//}
|
||||
|
||||
// 0
|
||||
// 1 2 // left desc 2*i + 1, right 2*i + 2
|
||||
// 3 4 5 6
|
||||
|
||||
// parent (i-1) >> 1;
|
||||
|
||||
// console.log('Heap', heap);
|
||||
|
||||
/**
|
||||
let t;
|
||||
for (let i = heap.length - 1; i >= 1; i--) {
|
||||
let idx = (i - 1) >> 1; // divided by 2
|
||||
console.log(`i: ${i}, idx: ${idx}`);
|
||||
console.log(`Parent: ${heap[idx].w}, item: ${heap[i].w}`);
|
||||
if (heap[idx].w > heap[i].w) {
|
||||
console.log(`Replaced`);
|
||||
t = heap[idx];
|
||||
heap[idx] = heap[i];
|
||||
heap[i] = t;
|
||||
}
|
||||
}
|
||||
|
||||
for (let i = heap.length - 1; i >= 1; i--) {
|
||||
let idx = (i - 1) >> 1; // divided by 2
|
||||
console.log(`i: ${i}, idx: ${idx}`);
|
||||
console.log(`Parent: ${heap[idx].w}, item: ${heap[i].w}`);
|
||||
if (heap[idx].w > heap[i].w) {
|
||||
console.log(`Bad...`);
|
||||
}
|
||||
}
|
||||
**/
|
||||
// while (heap.length) {
|
||||
// console.log(popSmallest());
|
||||
// }
|
||||
|
||||
let remaining = new Set(graph.nodes);
|
||||
|
||||
console.log('Nodes', remaining);
|
||||
let mst = {};
|
||||
let sets = 1;
|
||||
|
||||
function addEdges(u) {
|
||||
// console.log(`Adding edges for ${u}`);
|
||||
for (let el of graph.edges[u]) {
|
||||
// console.log(`Edge`, el);
|
||||
if (typeof(mst[el.v]) === 'number') {
|
||||
continue;
|
||||
}
|
||||
heapInsert({u: u, v: el.v, w: el.w});
|
||||
}
|
||||
}
|
||||
|
||||
let sum = 0;
|
||||
while (remaining.size) {
|
||||
let u = null;
|
||||
for (let el of remaining) {
|
||||
u = el;
|
||||
break;
|
||||
}
|
||||
remaining.delete(u);
|
||||
mst[u] = sets;
|
||||
addEdges(u);
|
||||
while (true) {
|
||||
let r = popSmallest();
|
||||
console.log('Edge', r);
|
||||
if (!r) {
|
||||
break;
|
||||
}
|
||||
|
||||
let {u,v,w} = r;
|
||||
if (typeof(mst[v]) === 'number') {
|
||||
console.log('Already added v...');
|
||||
continue;
|
||||
}
|
||||
|
||||
mst[v] = sets;
|
||||
remaining.delete(v);
|
||||
sum += w;
|
||||
addEdges(v);
|
||||
}
|
||||
}
|
||||
|
||||
console.log(`Weight ${sum}`);
|
||||
console.log('MST', mst);
|
||||
console.log('Remaining', remaining);
|
||||
|
||||
|
||||
}
|
||||
|
||||
function processLine(graph, line) {
|
||||
// console.log(`Processing line ${line}`);
|
||||
let matches =
|
||||
line.match(/([a-zA-Z]+) - ([a-zA-Z]+): ([0-9.]+)/);
|
||||
let u = matches[1];
|
||||
let v = matches[2];
|
||||
let w = Number.parseFloat(matches[3]);
|
||||
graph.nodes.add(u);
|
||||
graph.nodes.add(v);
|
||||
// bidirectional graph
|
||||
let outEdges = graph.edges[u] || [];
|
||||
outEdges.push({v, w});
|
||||
graph.edges[u] = outEdges;
|
||||
|
||||
outEdges = graph.edges[v] || [];
|
||||
outEdges.push({v: u, w});
|
||||
graph.edges[v] = outEdges;
|
||||
}
|
||||
|
||||
function main() {
|
||||
let buffer = "";
|
||||
let graph = {
|
||||
nodes: new Set(), // mapping name to idx
|
||||
edges: {}
|
||||
};
|
||||
let inputPath = process.argv.length > 2 ? process.argv[2] : null;
|
||||
console.log(`Input path ${inputPath}...`);
|
||||
let is = inputPath ? fs.createReadStream(inputPath) : process.stdin;
|
||||
|
||||
is.on('data', (chunk) => {
|
||||
// console.log(`Reading chunk ${chunk}`);
|
||||
buffer += chunk;
|
||||
});
|
||||
|
||||
is.on('end', () => {
|
||||
// console.log('Got end of data...');
|
||||
while (buffer.length > 0) {
|
||||
let idx = buffer.indexOf(EOL);
|
||||
if (idx < 0) {
|
||||
idx = buffer.length;
|
||||
}
|
||||
let line = buffer.slice(0, idx);
|
||||
processLine(graph, line);
|
||||
buffer = buffer.slice(idx + EOL.length);
|
||||
}
|
||||
|
||||
is.close();
|
||||
findPrimMST(graph);
|
||||
});
|
||||
}
|
||||
|
||||
main();
|
|
@ -0,0 +1,11 @@
|
|||
A - B: 7
|
||||
A - D: 5
|
||||
B - C: 8
|
||||
B - E: 7
|
||||
B - D: 9
|
||||
C - E: 5
|
||||
D - E: 15
|
||||
D - F: 6
|
||||
E - F: 8
|
||||
E - G: 9
|
||||
F - G: 11
|
Loading…
Reference in New Issue