• 学点字符串匹配——shiftAnd/shiftOr


      这个算法利用了位运算的优势速度很快,易于实现,缺点是模式串不能太长。据说在适用范围内速度是kmp的至少2倍。算法思想是用一个数字prefix的二进制去表示模式串的前缀,prefix的二进制第i位表示模式串的前缀0~i。如果这个前缀i是当前搜索到的匹配串的后缀时,将第i位至1。算法就是从匹配串的第0个字符到最后一个字符不断更新prefix的值每次更新后看最长的前缀(即模式串)的位是否被至1,如果是说明得到了一个匹配。

      下面说明下更新的过程。假如求出了比较匹配串第j位时的prefix,现在求比较j+1位的情况:prefix第i位为1当且仅当prefix第i-1位为1(匹配了i-1个字符),并且第i位所在字符和匹配串第j+1个字符相等。按下面实现来说,每次循环将prefix左移一位,第0位至一,在&上一个代表第i个字符是否匹配模式串某位的数字(这个通过初始化得到),就得到更新后的prefix。

      shiftAnd和shiftOr的思想一致。只是实现时存的是反码,因为prefix左移自然引入第0位的是0,为了减去或运算,才引入反码表示。

    上代码~

     1 //return a hashtable 代表字母表中的各个元素是否能成为模式串的后缀,用64位位压缩表示
     2 long long * initAlphbat(char *patternString)
     3 {
     4     long long *hash = (long long *) malloc(256 * sizeof(long long));
     5     unsigned int idx = 0;
     6     int psLen = strlen(patternString);
     7 
     8     if(hash == NULL) return NULL;
     9 
    10     memset(hash, 0, 256 * sizeof(long long));
    11     for(idx = 0; idx < psLen; ++idx)
    12     {
    13         hash[(unsigned int)patternString[idx]] |= ((long long)1 << idx); //表示patternString[idx]代表字符可以是在模式串的哪些位置
    14     }
    15 
    16     return hash;
    17 }
    18 
    19 //the patternString length must be less than 64
    20 MatchingInfo * ShiftAnd(char *patternString, char *dataString, unsigned int dsLen)
    21 {
    22     unsigned int idxDs = 0, psLen = strlen(patternString);
    23     long long *hash = initAlphbat(patternString);
    24 
    25     long long prefix = 0;  //每一位表示一个模式串的前缀,如果该位是1则表示当前该前缀被匹配上
    26 
    27     if(hash == NULL) return NULL;
    28 
    29     //匹配信息的初始化
    30     MatchingInfo *mi = (MatchingInfo *)malloc(sizeof(MatchingInfo));
    31     if(mi == NULL) return NULL;
    32     mi->indexOfMatch = (unsigned int *)malloc(sizeof(unsigned int));
    33     mi->numOfMatch = 0;
    34     mi->allocLen = 1;
    35 
    36     //下面的循环中动态更新prefix
    37     for(idxDs = 0; idxDs < dsLen; ++idxDs)
    38     {
    39         prefix = (prefix << 1) | 1;
    40         prefix &= hash[(unsigned int)dataString[idxDs]];
    41         if(prefix & ((long long)1 << (psLen - 1)))
    42         {
    43             //匹配上一个模式串
    44             if(mi->allocLen > mi->numOfMatch)
    45             {
    46                 //记录下标的内存够用
    47                 mi->indexOfMatch[mi->numOfMatch++] = idxDs - psLen + 1;
    48             }
    49             else
    50             {
    51                 //扩张匹配下标的内存
    52                 mi->indexOfMatch = (unsigned int *)realloc(mi->indexOfMatch, (mi->allocLen << 1) * sizeof(unsigned int));
    53                 mi->allocLen <<= 1;
    54                 mi->indexOfMatch[mi->numOfMatch++] = idxDs - psLen + 1;
    55             }
    56         }
    57     }
    58 
    59     free(hash);
    60     hash = NULL;
    61     return mi;
    62 }
  • 相关阅读:
    [五、交互操作]15使用DisclosureGroup视图实现点餐功能
    [五、交互操作]13使用AppStore Overlay向用户推荐其他的应用
    [五、交互操作]11预览视图在正常模式和黑暗模式下的效果
    [五、交互操作]10在预览窗口使用不同的模拟器预览用户界面
    [五、交互操作]8借助sizeCategory预览不同字体下的文本视图
    [五、交互操作]14使用fileExporter将文档导出到iCloud
    int(1) 和 int(10) 有什么区别?资深开发竟然都理解错了!
    Spring Boot 3.0 M1 发布,正式弃用 Java 8,最低要求 Java 17。。。
    发了 20w 年终奖,太激动了。。。
    头条面试官:如何设计群聊消息的已读未读功能?懵了。。
  • 原文地址:https://www.cnblogs.com/ACystalMoon/p/2839293.html
Copyright © 2020-2023  润新知