毫秒查询9位数qq号码是否存在-BitMap算法应用

实现详情请查看博客园

https://www.cnblogs.com/caoke/p/10793885.html

  

随机注册10万个放入BitMap,然后查询qq号码是否已存在,算法复杂度O(1).

//BitMap算法demo,查询9位数字
const b=new BitMap('[0~9][0~9][0~9][0~9][0~9][0~9][0~9][0~9][0~9]')

//设置
console.time('设置时间')
for(let i=0;i<b.length;i=i+1000){
    b.set(b.toString(i));
    i=0|Math.random()*1000+i;
}
// b.set('123456783')
// b.set('123456783')
// b.set('223456783')
b.set('323456783')
console.timeEnd('设置时间')

console.time('查询时间')
console.log(b.has('123456783'))
console.log(b.has('433456783'))
console.log(b.has('243456783'))
console.log(b.has('453456783'))
console.log(b.has('323456783'))
console.log(b.has('423456783'))
console.timeEnd('查询时间')

  

/usr/local/bin/node /Users/caoke/go/bitmap.js
设置时间: 3212.917ms
false
false
false
false
true
false
查询时间: 0.629ms

Process finished with exit code 0

 

源码

/*
*  ckHash函数类,将字符串映射成数字,同时可以将数字映射成字符串,
*  用于数据压缩,加密解密,以及bitMap大数据查询,去重
*  作者:caoke
* */

class ckHash{
    //输入密钥
    constructor(secretKey){
        this.secretKey=secretKey;

        this.regexp=new RegExp(secretKey.replace(/[([^[]+?)]/g,function (m) {
            return '('+m.replace(/-/g,'\-').replace(/~/g,'-')+')'
        }).replace(/[\^:.?+]/g,'\$&'));

        this.lenArr=[];
        this.dataArr=[];
        secretKey.replace(/[([^[]+?)]/g,(m,p1)=>{
            const arr=[];
            for(let i=0;i<p1.length;i++){
                if(p1[i]==='~'){
                    arr.push('~')
                }else{
                    arr.push(p1[i].charCodeAt(0));
                }
            }
            let length=0;
            for(let i=0;i<arr.length;i++){
                if(arr[i]==='~'){
                    length=length+arr[i+1]-arr[i-1];
                    i++;
                }else{
                    length=length+1;
                }
            }
            this.lenArr.push(length)
            this.dataArr.push(arr)
        })
        this.length=this.lenArr.reduce((x,y)=>x*y)
    }
    //将数字映射成字符串
    toString(number){
        const arr=[];
        for(let i=this.lenArr.length-1;i>0;i--){
            const n1=number%this.lenArr[i];
            arr.unshift(n1)
            number=Math.floor(number/this.lenArr[i]);
        }
        arr.unshift(number)


        const codeArr=[]
        for(let i=0;i<arr.length;i++){
            const dataArr=this.dataArr[i];
            let len= arr[i];

            let code;
            for(let j=0;j<dataArr.length;j++){
                if(dataArr[j]==='~'){
                    if(len<dataArr[j+1]-dataArr[j-1]){
                        code=dataArr[j-1]+len+1;
                        break;
                    }else{
                        len=len-(dataArr[j+1]-dataArr[j-1]);
                        j++;
                    }
                }else if(len===0){
                    code=dataArr[j]
                    break;
                }else{
                    len--;
                }
            }
            codeArr.push(String.fromCharCode(code))
        }
        let index=0;
        return this.secretKey.replace(/[([^[]+?)]/g,(m,p1)=>{
            return codeArr[index++];
        })
    }
    //将字符串映射成数字
    toNumber(string){
        if(this.regexp.test(string)){
            const arr=[]
            string.replace(this.regexp,function (m,p1) {
                for(let i=1;i<arguments.length-2;i++){
                    arr.push(arguments[i].charCodeAt(0))
                }
            });

            const lenArr=[]
            for(let i=0;i<arr.length;i++){
                const dataArr=this.dataArr[i];
                let len= 0;
                for(let j=0;j<dataArr.length;j++){
                    if(dataArr[j]===arr[i]){
                        break;
                    }else if(dataArr[j]==='~'){
                        if(arr[i]<=dataArr[j+1]&&arr[i]>dataArr[j-1]){
                            len=len+arr[i]-dataArr[j-1]-1;
                            break;
                        }else{
                            len=len+dataArr[j+1]-dataArr[j-1];
                            j++;
                        }
                    }else{
                        len++;
                    }
                }
                lenArr.push(len)
            }
            let number=0;
            let jz=1;
            for(let i=lenArr.length-1;i>=0;i--){
                number=number+jz*lenArr[i];
                jz=jz*this.lenArr[i]
            }

            return number;

        }else{
            throw string +' 不在匹配范围内';
        }
    }
}


//BitMap算法,大数据查询,算法复杂度O(1)
class BitMap {
    constructor(secretKey){
        this.hashFunc=new ckHash(secretKey);
        this.length=this.hashFunc.length
        this.buffer=Buffer.alloc(this.length);
    }
    has(num){
        if(typeof num ==='string'){
            num=this.toNumber(num);
        }
        const n=num>>3;
        const k=num%8;
        return (this.buffer[n]&1<<k)!==0
    }
    toString(num){
        return this.hashFunc.toString(num);
    }
    toNumber(str){
        return this.hashFunc.toNumber(str);
    }
    set(num){
        if(typeof num ==='string'){
            num=this.toNumber(num);
        }
        const n=num>>3;
        const k=num%8;
        this.buffer[n]=this.buffer[n]|(1<<k);
    }
    del(num){
        if(typeof num ==='string'){
            num=this.toNumber(num);
        }
        const n=num>>3;
        const k=num%8;
        this.buffer[n]=this.buffer[n]&~(1<<k);
    }
}

  

  

原文地址:https://www.cnblogs.com/caoke/p/10795336.html