js版本三向单词查找树

//三向单词查找树
//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()
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值