jsketcher/web/app/utils/graph.js
2022-08-15 23:47:20 -07:00

148 lines
No EOL
2.8 KiB
JavaScript

import {HashTable} from './hashmap'
/** @constructor */
function Graph(data) {
this.connections = function(e) {
return data[e];
};
this.at = function(index) {
return index;
};
this.size = function() {
return data.length;
};
}
Graph.findAllLoops = function(graph, hashCode, equals) {
let loops = [];
const visited = new HashTable(hashCode, equals);
function step(vertex, comesFrom, path) {
let i;
visited.put(vertex, true);
for (i = path.length - 1; i >= 0; --i) {
if (equals(vertex, path[i])) {
loops.push(path.slice(i));
return;
}
}
const next = graph.connections(vertex);
path.push(vertex);
let needClone = false;
for (i = 0; i < next.length; i++) {
const v = next[i];
if (equals(v, comesFrom)) {
continue;
}
const p = needClone ? path.slice(0) : path;
needClone = true;
step(v, vertex, p);
}
path.pop();
}
for (i = 0; i < graph.size(); i++) {
const vertex = graph.at(i);
if (visited.get(vertex) !== true) {
step(vertex, -1, []);
}
}
//filter duplicates
function sameLoop(a, b) {
const first = a[0];
let bShift;
for (bShift = 0; bShift < a.length; bShift++) {
if (equals(b[bShift], first)) {
break;
}
}
if (bShift == a.length) {
return false;
}
for (let i = 0; i < a.length; i++) {
const bUp = (bShift + i) % a.length;
let bDown = bShift - i;
if (bDown < 0) {
bDown = a.length + bDown;
}
// console.log("up: " + bUp + "; down: " + bDown);
const curr = a[i];
if ( !equals(curr, b[bUp]) && !equals(curr, b[bDown]) ) {
return false;
}
}
return true;
}
let i, duplicates = 0;
for (i = 0; i < loops.length; i++) {
const a = loops[i];
if (a == null) continue;
for (let j = i + 1; j < loops.length; j++) {
const b = loops[j];
if (b == null || a.length !== b.length) {
continue;
}
if (sameLoop(a, b)) {
loops[j] = null;
++ duplicates;
}
}
}
if (duplicates != 0) {
const filtered = [];
for (i = 0; i < loops.length; i++) {
if (loops[i] != null) filtered.push(loops[i]);
}
loops = filtered;
}
return loops;
};
const test = function() {
const data = [
[],
[2],
[1, 3, 9],
[2, 4],
[3, 9, 5, 8],
[4, 6],
[5, 8, 7],
[6],
[4, 6],
[2, 4]
];
const graph = new Graph(data);
console.log(Graph.findAllLoops(graph));
};
const test0 = function() {
const data = [
[3, 1],
[0, 2, 8],
[1, 3, 7, 5],
[0, 2, 4],
[3, 5],
[4, 2, 6],
[5, 7],
[2, 6, 8],
[1, 7]
];
const graph = new Graph(data);
console.log(Graph.findAllLoops(graph));
};
export {Graph}