欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

AC自动机

程序员文章站 2022-07-05 11:04:57
AC自动机 js class ACNode { constructor(data){ this.data = data this.isEndingChar = false this.children = new Map() this.length = 0 this.fail = null } } c ......

ac自动机

AC自动机

1.根据字符构造trie树
2.构建失败匹配指针
   1.根节点的所以一代子孩子失败指针都指向root
   2.子节点匹配失败时,找到父节点的失败指针,找不到就一直找,直到找到root还匹配不到,直接指向root
3.文本串匹配
   1.如果已经匹配到完整的模式串或者压根匹配不到,根据失败指针切换线路继续向下查找
   2.如果匹配到了,那么就继续向下匹配
class acnode {
    constructor(data){
        this.data = data
        this.isendingchar = false
        this.children = new map()
        this.length = 0
        this.fail = null
    }
}

class actree {
    constructor(){
        this.root = new acnode('/')
    }
    insert(text){
        let node = this.root
        for(let char of text ){
            if(!node.children.get(char)){
                node.children.set(char,new acnode(char))
            }
            node = node.children.get(char)
        }
        node.isendingchar = true
        node.length = text.length
    }
    failurepointer(){
        let root = this.root
        let queue = []
        queue.push(root)
        while(queue.length > 0){
            let currentnode = queue.shift()
            for(let child of currentnode.children.values()){
                if(!child){
                    continue
                }

                if(currentnode == root){
                    child.fail = currentnode
                }else{
                    //不是一代子节点才指向
                    let grandfathernode = currentnode.fail
                    while(grandfathernode){
                        let failnode = grandfathernode.children.get(child.data)
                        if(failnode){
                            child.fail = failnode
                            //找到失败节点就不往下找了
                            break
                        }
                        grandfathernode = grandfathernode.fail
                    }
                    if(!grandfathernode){
                        child.fail = root
                    }
                }               
                queue.push(child)
            }
        }
    }
    match(text){
        let root = this.root
        let len =  text.length
        let currentnode
        for(let i = 0; i < len; i++){
            let char = text[i]

            if(!currentnode){
                currentnode = root
            }

            while(!currentnode.children.get(char) && currentnode != root){
                //匹配不到就换线
                currentnode = currentnode.fail
            }

            currentnode = currentnode.children.get(char)

            let tmp = currentnode
            while(tmp != root){
                if(tmp.isendingchar){
                    console.log(`from ${i - tmp.length + 1} length: ${tmp.length} str: ${text.substr(i - tmp.length + 1,tmp.length)}`)
                }
                //匹配到了就继续看看其他线有没有可以匹配成功的
                tmp = tmp.fail 
            }

        }
    }
}

function match(text,patterns){
    const autometa = new actree()
    for(pattern of patterns){
        autometa.insert(pattern)
    }
    autometa.failurepointer()
    autometa.match(text)
}

let patterns = ["at", "art", "oars", "soar"];
let text = "soarsoars";
match(text, patterns);

let patterns2 = ["fxtec pro1", "谷歌pixel"];
let text2 = "一家总部位于伦敦的公司fxtex在mwc上就推出了一款名为fxtec pro1的手机,该机最大的亮点就是采用了侧滑式全键盘设计。dxomark年度总榜发布 华为p20 pro/谷歌pixel 3争冠";
match(text2, patterns2);