//三向单词查找树
//node结构:{key:"",mid:node,left:node,right:node,val:""}
//在node下获取key对应的val,d是即将比较的字符串的索引,如d=2表示即将用key[2]与树对应的节点进行比较,下同
function get(node,key,d=0){
if(d>=key.length){return node}
if(node==undefined)return undefined
let k=key[d]
if(k>node.key)return get(node.right,key,d)
if(k<node.key)return get(node.left,key,d)
if(d<key.length-1)return get(node.mid,key,d+1)
return node
}
//在node下设置key对应的值是val,没有创建有就覆盖
function put(node,key,val,d=0){
if(d>=key.length){return node}
if(node==undefined){
var node={'key':key[d]}
}
let k=key[d]
if(k>node.key){
node.right=put(node.right,key,val,d)
}else if(k<node.key){
node.left=put(node.left,key,val,d)
}else if(d<key.length-1){
node.mid=put(node.mid,key,val,d+1)
}else{
node.val=val
}
return node
}
//keysWithPrefix_:返回node节点下以pre开头,如果pre是空字符串,则返回pre的下所有key。
//否则找到pre对应节点后node_pre,返回node_pre.mid下所有key,如果node_pre有val也一并返回。
function keysWithPrefix(node,pre){
if(node==undefined){return}
let list=[]
let node_pre=get(node,pre)
if(node_pre==undefined){return}
if(pre==''){
keysWithPrefix_(node_pre,pre,list)
}else{
if(node_pre.val!=undefined){list.push(node_pre.key)}
keysWithPrefix_(node_pre.mid,pre,list)
}
return list
}
//keysWithPrefix_:返回node节点下所有key,包括左右节点的
function keysWithPrefix_(node,pre,list=[]){
if(node==undefined){return}
let k=node.key
keysWithPrefix_(node.left,pre,list)
if (node.val!=undefined){
list.push(pre+k)
}
keysWithPrefix_(node.mid,pre+k,list)
keysWithPrefix_(node.right,pre,list)
}
//keysThatMatch:返回匹配的字符串,如果a.b对应a[a-z]b
function keysThatMatch(node,match,list=[],pre=""){
if(node==undefined||pre.length==match.length){return list}
let d=pre.length
let x=match[d]
let k=node.key
if(x=='.'){
list=keysThatMatch(node.left,match,list,pre)
if(pre.length==match.length-1&&node.val!=undefined){
list.push(pre+k)
}else{
list=keysThatMatch(node.mid,match,list,pre+k)
}
list=keysThatMatch(node.right,match,list,pre)
}else if(k<x){
list=keysThatMatch(node.right,match,list,pre)
}else if(k>x){
list=keysThatMatch(node.left,match,list,pre)
}else if(pre.length<match.length-1){
list=keysThatMatch(node.mid,match,list,pre+k)
}else if(node.val!=undefined){
list.push(pre+k)
}
return list
}
//longestPrefixOf:返回给定字符串最长公共前缀的key,d1是目前此key的索引,d2是即将比较的字符串的索引
function longestPrefixOf(node,match,d1=0,d2=0){
if(node==undefined||d2==match.length){return match.substr(0,d1)}
let x=match[d2]
let k=node.key
if(k<x){
return longestPrefixOf(node.right,match,d1,d2)
}else if(k>x){
return longestPrefixOf(node.left,match,d1,d2)
}else if(d2<match.length-1){
if(node.val!=undefined){d1=d2+1}
return longestPrefixOf(node.mid,match,d1,d2+1)
}else{return match.substr(0,d1+1)}
//这个else不能省略,不然d2==match.length且k==x的场合有bug
}
//delete:d是即将比较的字符串的长度,删除key对应节点后,需要把无子节点且没有val的节点也删除
function delete_(node,key,d=0){
if(node==undefined){
return undefined
}
if(d==key.length-1){
node.val=undefined
}else{
let x=key[d]
let k=node.key
if(k<x){
node.right=delete_(node.right,key,d)
}else if(k>x){
node.left=delete_(node.left,key,d)
}else{
node.mid=delete_(node.mid,key,d+1)
}
}
if(node.val!=undefined||node.mid!=undefined||node.left!=undefined||node.right!=undefined){return node}
}
var root=undefined
let j1=require('./1')
let mycount=1000
let mylength=5
randomWords=j1.getWords(mycount,1,mylength)
randomWords.forEach((x)=>{root=put(root,x,x+'Val')}) //put随机字符串到以root为根节点的树
console.log("\n\n\n\n\nrandomWords=\n",randomWords)
randomWords.forEach((x)=>{ //测试put是否生效
if(get(root,x).val!=x+"Val"){
console.log(x+'---->'+get(root,x))
}
})
console.log('\n\n\n-->test keysWithPrefix')
console.log(keysWithPrefix(root,"a")) //打印以'a'开头的字符串
//打印以所有字符串,这里lst是全局变量(在function里声明测试过)
console.log(lst=keysWithPrefix(root,""))
//Array.from(new Set(lst)是对数组去重。树的val个数应该和去重后的数组个数一样
//长度可能不到mylength,因为有重复的可以key:val
console.log(lst.length,Array.from(new Set(lst)).length)
let matchstr="a.."
console.log('\n\n\n-->test keysThatMatch '+matchstr)
console.log(keysThatMatch(root,matchstr))
let test_keysThatMatch_list=[]
//计算1到mylength位的字符串分别有多少,求和进行校验。
for(let i=1;i<=mylength;i++){
let matchstr_=''
for(j=1;j<=i;j++){
matchstr_=matchstr_+'.'
}
test_keysThatMatch_list.push(keysThatMatch(root,matchstr_).length)
}
//eval(test_keysThatMatch_list.join('+'))是对数组求和的一个方法
console.log(test_keysThatMatch_list,lst.length,eval(test_keysThatMatch_list.join('+')))
let prefixstr="aaaa"
console.log('\n\n\n-->test longestPrefixOf '+prefixstr)
console.log(longestPrefixOf(root,prefixstr))
console.log('\n\n\n-->test delete')
root=put(root,'aaaaaa','a6val')
root=put(root,'aaaaaaaa','a8val')
console.log(keysWithPrefix(root,""))
console.log(get(root,"aaaaaaaa"))
console.log(get(root,"aaaaaaa"))
console.log(get(root,"aaaaaa"))
console.log(get(root,"aaaaa"))
root=delete_(root,'aaaaaaaa')
root=delete_(root,'a')
console.log(keysWithPrefix(root,""))
console.log(get(root,"aaaaaaaa"))
console.log(get(root,"aaaaaaa"))
console.log(get(root,"aaaaaa"))
console.log(get(root,"aaaaa"))
//-=-------------------------------------------------------------------------------
exports.getWords=function getWords(maxcount=20,minlen=0,maxlen=11){
let words=[]
for (let j=0;j<maxcount;j++){
let arr=''
let len_=minlen+Math.floor(Math.random()*(maxlen-minlen+1))
for(let l=0;l<len_;l++){
arr = arr + String.fromCharCode(97+Math.floor(Math.random()*26))
}
words.push(arr)
}
return words
}
exports.char2int=(a)=>{
return a==''?-1:a.charCodeAt()
}
js版本三向单词查找树
最新推荐文章于 2022-03-15 15:28:51 发布