d11 theme
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

154 lines
4.3 KiB

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.isCircular = exports.countWords = exports.countNodes = exports.findNode = exports.has = exports.createTriFromList = exports.createRoot = exports.iteratorTrieWords = exports.iterateTrie = exports.walk = exports.orderTrie = exports.isWordTerminationNode = exports.insert = void 0;
const gensequence_1 = require("gensequence");
const TrieNode_1 = require("./TrieNode");
const walker_1 = require("./walker");
function insert(text, node = {}) {
if (text.length) {
const head = text[0];
const tail = text.slice(1);
node.c = node.c || new TrieNode_1.ChildMap();
node.c.set(head, insert(tail, node.c.get(head)));
}
else {
node.f = (node.f || 0) | TrieNode_1.FLAG_WORD;
}
return node;
}
exports.insert = insert;
function isWordTerminationNode(node) {
return ((node.f || 0) & TrieNode_1.FLAG_WORD) === TrieNode_1.FLAG_WORD;
}
exports.isWordTerminationNode = isWordTerminationNode;
/**
* Sorts the nodes in a trie in place.
*/
function orderTrie(node) {
if (!node.c)
return;
const nodes = [...node.c].sort(([a], [b]) => (a < b ? -1 : 1));
node.c = new Map(nodes);
for (const n of node.c) {
orderTrie(n[1]);
}
}
exports.orderTrie = orderTrie;
/**
* Generator an iterator that will walk the Trie parent then children in a depth first fashion that preserves sorted order.
*/
function walk(node) {
return gensequence_1.genSequence(walker_1.walker(node));
}
exports.walk = walk;
exports.iterateTrie = walk;
/**
* Generate a Iterator that can walk a Trie and yield the words.
*/
function iteratorTrieWords(node) {
return walk(node)
.filter((r) => isWordTerminationNode(r.node))
.map((r) => r.text);
}
exports.iteratorTrieWords = iteratorTrieWords;
function createRoot() {
return {};
}
exports.createRoot = createRoot;
function createTriFromList(words) {
const root = createRoot();
for (const word of words) {
if (word.length) {
insert(word, root);
}
}
return root;
}
exports.createTriFromList = createTriFromList;
function has(node, word) {
let h = word.slice(0, 1);
let t = word.slice(1);
while (node.c && node.c.has(h)) {
node = node.c.get(h);
h = t.slice(0, 1);
t = t.slice(1);
}
return !h.length && !!((node.f || 0) & TrieNode_1.FLAG_WORD);
}
exports.has = has;
function findNode(node, prefix) {
let h = prefix.slice(0, 1);
let t = prefix.slice(1);
let n = node;
while (h.length && n && n.c) {
n = n.c.get(h);
h = t.slice(0, 1);
t = t.slice(1);
}
return n;
}
exports.findNode = findNode;
function countNodes(root) {
const seen = new Set();
function walk(n) {
if (seen.has(n))
return;
seen.add(n);
if (n.c) {
[...n.c.values()].forEach((n) => walk(n));
}
}
walk(root);
return seen.size;
}
exports.countNodes = countNodes;
function countWords(root) {
const visited = new Map();
function walk(n) {
if (visited.has(n)) {
return visited.get(n);
}
let cnt = n.f ? 1 : 0;
// add the node to the set to avoid getting stuck on circular references.
visited.set(n, cnt);
if (!n.c) {
return cnt;
}
for (const c of n.c.values()) {
cnt += walk(c);
}
visited.set(n, cnt);
return cnt;
}
return walk(root);
}
exports.countWords = countWords;
function isCircular(root) {
const seen = new Set();
const inStack = new Set();
function walk(n) {
if (seen.has(n))
return { isCircular: false, allSeen: true };
if (inStack.has(n))
return { isCircular: true, allSeen: false };
inStack.add(n);
let r = { isCircular: false, allSeen: true };
if (n.c) {
r = [...n.c.values()].reduce((acc, n) => {
if (acc.isCircular)
return acc;
const r = walk(n);
r.allSeen = r.allSeen && acc.allSeen;
return r;
}, r);
}
if (r.allSeen) {
seen.add(n);
}
inStack.delete(n);
return r;
}
return walk(root).isCircular;
}
exports.isCircular = isCircular;
//# sourceMappingURL=util.js.map