Files
ZYZ/shared/pubUtils/trie.ts

160 lines
6.5 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
function Trie(this: any) {
this.root = new TrieNode(null);
this.hitStr = '';
}
function TrieNode(this: any, key) {
this.key = key; // 节点字符
this.children = []; // 子节点集合
this.end = false;
}
Trie.prototype = {
insertData: function (stringData) {
this.insert(stringData, this.root);
// console.log(JSON.stringify(this.root, null, 2))
},
// 递归判断插入
insert: function (stringData, node) {
if (stringData == '') {
return;
}
let children = node.children;
let haveData = null;
for (let i in children) {
if (children[i].key == stringData[0]) {
haveData = children[i];
}
}
if (haveData) {
this.insert(stringData.substring(1), haveData); //说明找到了对应的节点
if (stringData.substring(1).length == 0) haveData.end = true;
} else { //那如果没有找到则插入
if (children.length == 0) { //当前节点没有子节点
let node = new TrieNode(stringData[0]);
children.push(node);
this.insert(stringData.substring(1), node); //将该字符节点插入节点的children中
if (stringData.substring(1).length == 0) node.end = true;
} else { //当前节点存在子节点,需要查找一个合适的位置去插入新节点
let validPosition = 0;
for (let j in children) {
if (children[j].key < stringData[0]) {
validPosition++;
}
}
let node = new TrieNode(stringData[0]);
children.splice(validPosition, 0, node);
this.insert(stringData.substring(1), node); //将该字符节点插入节点的children中
if (stringData.substring(1).length == 0) node.end = true;
}
}
},
// 查询字符串
search: function (queryData) {
if (queryData == '' || this.root.children.length == 0) {
return false;
}
for (let j = 0; j < queryData.length; j++) {
for (let i in this.root.children) {
this.hitStr = '';
if (this.searchNext(this.root.children[i], queryData.substring(j))) {
console.log('hitStr:' + this.hitStr);
return true;
}
}
}
return false;
},
// 获取命中的关键词
getHitStr: function (queryData) {
this.hitStr = '';
this.search(queryData)
return this.hitStr;
},
// 递归查询判断
searchNext: function (node, stringData) {
// 若字符与节点key不相等则不匹配
if (stringData[0] != node.key) {
return false;
} else { // 若与key相等继续判断
this.hitStr += node.key;
let children = node.children;
if (children.length == 0) { // 叶子节点,最后一个字符,则完全匹配
// if (children.length == 0) { // 叶子节点,最后一个字符,则完全匹配
return true;
} else if (node.end) {
return true;
} else if (children.length > 0 && stringData.length > 1) { // 既不是叶子节点,也不是最后一个字符,则继续递归查找
for (let i in children) {
if (children[i].key == stringData[1]) {
return this.searchNext(children[i], stringData.substring(1)); // 记得return 递归函数否则获取的返回值为undefined
}
}
} else { // C1叶子节点C2最后一个字符若只满足其中一个条件则不匹配
return false;
}
}
},
// 删除字符串
delete: function (stringData) {
if (this.search(stringData)) { // 判断是否存在该单词(字符串)
for (let i in this.root.children) {
if (this.delNext(this.root, i, stringData, stringData)) {
return;
}
}
}
return this;
},
/**
* 先递归查找到字符串的叶子节点,然后从字符串的叶子节点逐级向根节点递归删除叶子节点,直到删除字符串
* @param parent 父节点
* @param index 子节点在父节点children数组中的索引位置
* @param stringData 递归遍历中的字符串
* @param delStr 调用delete方法时的原始字符串
*/
delNext: function (parent, index, stringData, delStr) {
//当前节点对象
let node = parent.children[index];
// 若字符与节点key不相等则不匹配
if (stringData[0] != node.key) {
return false;
} else { // 若与key相等继续判断
let children = node.children;
if (children.length == 0 && stringData.length == 1) { // 叶子节点,最后一个字符,则完全匹配
// 删除叶子节点,利用父节点删除子节点原理
parent.children.splice(index, 1);
// 字符串从尾部移除一个字符后,继续遍历删除方法
this.delete(delStr.substring(0, delStr.length - 1));
} else if (children.length > 0 && stringData.length > 1) { // 既不是叶子节点,也不是最后一个字符,则继续递归查找
for (let i in children) {
if (children[i].key == stringData[1]) {
return this.delNext(node, i, stringData.substring(1), delStr); // 记得return 递归函数否则获取的返回值为undefined
}
}
}
}
},
// 打印字符串
printData: function () {
for (let i in this.root.children) {
this.printHelper(this.root.children[i], [this.root.children[i].key]);
}
},
// 递归输出字符串
printHelper: function (node, data) {
if (node.children.length == 0) {
console.log('>', data.join(''));
return;
}
for (let i in node.children) {
data.push(node.children[i].key);
this.printHelper(node.children[i], data);
// if (node.end) console.log(data);
data.pop(); // 注意,找打一个单词后,返回下一个初始节点继续遍历
}
}
}
export default Trie;