• 4.【ac自动机】模式串匹配


    ANSI编码的中英文16叉模式串匹配自动机

    1.构造模式串树

    void insert(char* s, in* trie) {
    
        long u = 1, len = strlen(s);//每来一个模式串
        for (long i = 0; i < len * 2; i++) {
            if (i % 2 == 0) {
                uint8_t vv = (uint8_t)s[i / 2];
                uint8_t v = vv >> 4;
                if (!trie[u].son[v])
                    trie[u].son[v] = ++cnt;
                u = trie[u].son[v];
            }
            else {
                uint8_t vv = ((uint8_t)s[i / 2] << 4);
                uint8_t v = vv >> 4;//s[i]后四位
                if (!trie[u].son[v])
                    trie[u].son[v] = ++cnt;
                u = trie[u].son[v];
            }
        }
        
        trie[u].patternNum++;
        if (strcmp(trie[u].strInfo, s)) {
            strcat(trie[u].strInfo, s);  if (u % 100000 == 0)printf("建树中... %d
    ", u);  //不可使用指针!
        }
        
    }

    2.得到fail指针

    void getFail(in* trie) {
        long u, y;
        for (long i = 0; i < 16; i++) {
            trie[0].son[i] = 1;          //初始化0的所有儿子都是1 所有的树型有限自动机都有一个共同的特点,即对任何输入字符a, 都有g(0, a) != 0。
    
        }
        queue_push(&q, 1); trie[1].fail = 0;               //将根压入队列
        while (!queue_empty(&q)) {
            queue_front(&q, &u); queue_pop(&q, &y);
            for (long i = 0; i < 16; i++) {              //遍历所有儿子
                long v = trie[u].son[i];           //处理u的i儿子的fail,这样就可以不用记父亲了
                long Fail = trie[u].fail;          //就是fafail,trie[Fail].son[i]就是和v值相同的点
                if (!v) { trie[u].son[i] = trie[Fail].son[i]; continue; }  //不存在该节点,第二种情况
                trie[v].fail = trie[Fail].son[i]; //第三种情况,直接指就可以了
                //printf("%d    %d
    ", v, trie[Fail].son[i]);
                queue_push(&q, v);                      //存在实节点才压入队列
            }
        }
    }

    3.主串查询(不回溯)

    long query(char* s, long len, in* trie) {
    
        long u = 1;
        for (long i = 0; i < len * 2; i++) {
            long k = 0;
            if (i % 2 == 0) {
                uint8_t vv = (uint8_t)s[i / 2];
                uint8_t v = vv >> 4;
                k = trie[u].son[v];
                while (k > 1) {
                    count++;
                    if (count % 10000000 == 0) printf("查询中...%lld
    ", count/1000);
                    if (trie[k].strInfo[0] !='') {
                        trie[k].flag++;
                    }
                    k = trie[k].fail;
                }
                u = trie[u].son[v];
    
            }
            else {
                uint8_t vv = ((uint8_t)s[i / 2] << 4);
                uint8_t v = vv >> 4;
                k = trie[u].son[v];
                while (k > 1) {
                    count++;
                    if (count % 10000000 == 0) printf("查询中...%lld
    ", count/1000);
                    if (trie[k].strInfo[0] != '') {
                        trie[k].flag++;
                    }
                    k = trie[k].fail;   //继续跳Fail
                }
                u = trie[u].son[v];//到下一个儿子
            }
        }
        return count;
    }

    4.堆排

    void HeapAdjust(txt* data, int s, int m)//s=3,m=7 s=2 s是广义上的根  (下一根 ) 
    {
        txt temp; int  i;
        temp = data[s];//a[3]    
        for (i = 2 * s + 1; i <= m; i = i * 2 + 1)//i=7;i<=7; i=5  i为根s的子树结点 
        {  //printf("k%d",a[i+1]);
            if (i<m && data[i].appearNum>data[i + 1].appearNum)        //i为小子树 
                i++;
            if (!(temp.appearNum > data[i].appearNum))            //初始根根和小子树比较,根小于等于小子树,退出 ; 这个temp根是初始根,并非下一根 子树可能是儿子或孙子... 
                break;
            data[s] = data[i];//初始根大于 小子树值 (这里并不一定是父子比较,第二次可能是爷孙比较)s广义根变小子树值
            s = i;//继续判断下一根 直到叶子结点 
        }
        data[s] = temp;//叶子结点值变初始根值 
    }
    void HeapSort(txt* data, int size)
    {
        int i, j;
        txt temp;
        for (i = (size - 1) / 2; i >= 0; i--)//i=(8-1)/2=3
            HeapAdjust(data, i, size - 1);//a,3,7 a,2,7  a,1,7 a,0,7 循环调整 建立小根堆 
        for (i = size - 1; i > 0; i--)
        {
            temp = data[0];
            data[0] = data[i];
            data[i] = temp;
            HeapAdjust(data, 0, i - 1);
    
        }
    
    }

    5.问题:中文2字节编码后,拆成4个16进制,会出现杂糅问题。例如你好(C4E3BAC3)可能识别出愫(E3BA),模式串越短错误率越高,尤其是单字母的英文模式串。但词组错误率几乎为零。256叉树可解决此问题

  • 相关阅读:
    OpenStack安装及监控配置视频教程
    具有可视化的功能的一款开源软件Gource
    Ubuntu 12.04使用演示
    VisualRoute for Mac OS 体验
    P1006-传纸条
    Leetcode-1157 Online Majority Element In Subarray(子数组中占绝大多数的元素)
    Leetcode-1156 Swap For Maximum Repeated Substring(单字符重复子串的最大长度)
    Leetcode-1155 Number of Dice Rolls With Target Sum(掷骰子的N种方法)
    Leetcode-1154 Ordinal Number Of Date(一年中的第几天)
    P1508-Likecloud-吃、吃、吃
  • 原文地址:https://www.cnblogs.com/apo2019/p/11957488.html
Copyright © 2020-2023  润新知