• javascript实现多字符查询之AC算法


    首先简要介绍一下AC自动机:Aho-Corasick automation,该算法在1975年产生于贝尔实验室,是著名的多模匹配算法之一。一个常见的例子就是给出n个单词,再给出一段包含m个字符的文章,让你找出有多少个单词在文章里出现过。要搞懂AC自动机,先得有模式树(字典树)Trie和KMP模式匹配算法的基础知识。KMP算法是单模式串的字符匹配算法,AC自动机是多模式串的字符匹配算法。

    一、原理

    AC自动机算法详解 》》 https://www.cnblogs.com/cmmdc/p/7337611.html

    二、JavaScript代码

    //javascript实现字典树trie,简单的实现下
    class TrieNode {
        constructor(value){
            this.value = value; //value为单个字符
            this.num=1;
            this.deep=0;//根节点默认0
            this.son=[];
            this.isEnd=false;
        }
        findNode(value){
            for(let i=0;i<this.son.length;i++){
                const node=this.son[i]
                if(node.value == value){
                    return node;
                }
            }
            return null;
        }
    }
    class Trie {
        constructor(){
            this.root=new TrieNode(null);
            this.size=1;//一开始的时候只有根节点这一个节点
        }
        insert(str){
            let node=this.root;
            for(let c of str){
                let snode = node.findNode(c);
                if(snode==null){
                    snode=new TrieNode(c)
                    snode.deep=node.deep+1;
                    node.son.push(snode);
                }else{
                    snode.num++;//有N个字符串经过它
                }
                node=snode;
    
            }
            //如果当前的node已经是一个word,则不需要添加
            if (!node.isEnd) {
                this.size++;
                node.isEnd = true;
            }
        }
        has(str){
            let node=this.root;
            for(let c of str){
                const snode=node.findNode(c)
                if(snode){
                    node=snode;
                }else{
                    return false;
                }
            }
            return node.isEnd;
        }
    }
    //构建字典树失败指针
    function build_ac_automation(root){
        root.fail=null;
        const queue=[root]
        let i=0;
        while(i<queue.length){
            const temp=queue[i];
            for(let j=0;j<temp.son.length;j++){
                const node=temp.son[j]
                if(temp===root){
                    node.fail=root;
                }else{
                    node.fail=temp.fail.findNode(node.value)||root;
                }
                queue.push(node);
            }
            i++
        }
    }
    //ac算法多字符查询
    function acSearch(arr,str) {
        //生成字典树
        const tr=new Trie()
        arr.forEach(function (item) {
            tr.insert(item)
        })
        //构造字典树的失败指针
        build_ac_automation(tr.root)
        let node=tr.root;
    
        const data=[];
        for(let i=0;i<str.length;i++){
    
            let cnode=node.findNode(str[i])
            //匹配不到字符,进入失败匹配,
            while(!cnode&&node!==tr.root){
                node=node.fail;
    
                cnode=node.findNode(str[i])
            }
            if(cnode){
                node=cnode;
            }
            if(node.isEnd){
                data.push({
                    start:i+1-node.deep,
                    len:node.deep,
                    str:str.substr(i+1-node.deep,node.deep),
                    num:node.num,
                })
            }
        }
        return data;
    }
    
    //test
    const result=acSearch(['she','shr','her','her'],'sher');
    console.log(result);
    
    /**
     * [ { start: 0, len: 3, str: 'she', num: 1 },
     { start: 1, len: 3, str: 'her', num: 2 } ]
     */
    

      

      

      

  • 相关阅读:
    Flask第31课——include标签
    flask第30篇——宏macro和import标签
    HTML第三课——css盒子
    HTML第二课——css【2】
    HTML第二课——css
    HTML第一课——基础知识普及【2】
    转一篇数据库面试题
    自创建数字证书,安装到浏览器
    【转】Base64算法详解
    【转】二维码生成原理
  • 原文地址:https://www.cnblogs.com/caoke/p/10895032.html
Copyright © 2020-2023  润新知