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;