zoukankan      html  css  js  c++  java
  • 串的模式匹配算法RK

    这一节介绍一下由Rabin和Karp提出的RK算法。

    1,RK算法的基本思想

         HASH!

         如果两个字符串hash后的值不相同,则它们肯定不相同;如果它们hash后的值相同,它们不一定相同。

         RK算法的基本思想就是:将模式串P的hash值跟主串S中的每一个长度为|P|的子串的hash值比较。如果不同,则它们肯定不相等;如果相同,则再诸位比较之。

    2,RK算法的求解过程

        将我们用来比较的字符串的全集设为∑={a,b,…,z},设∑的长度为d=|∑|,则主串和模式串都可以看作是d进制数。例如只由数字组成的字符串,它的全集∑={0,1,2,3,4,5,6,7,8,9},d=10。

        设模式串为P,其长度为m,主串为S,其长度为n。则模式串P可以看作是一个m位的d进制数A,主串S可以看作是一个n位的d进制数。我们的模式匹配过程就是将A与主串中的每个长度为m的d进制数S[t…t+m-1] (t=0,1,2,…,n-m+1)的值做比较,所以整个模式匹配过程就变成了两个d进制数之间的比较过程。例如模式串为123,主串为65127451234,就是将十进制数123跟十进制数651, 512, 127, 274, 745, 451, 512, 123的逐个比较过程。

        明确了匹配过程,下面就是求解A和求解S[t…t+m-1] (t=0,1,2,…,n-m+1)的过程:

           1)求解A。根据多项式计算方法,A = P[m-1] + d * (P[m-2] + d * (P[m-3] + …+ d * (P[1] + d*P[0])…))

           2)求解S[t…t+m-1]。为了方便表示,我们设S[t…t+m-1] = St,则S[t+1…t+m] = St+1

                  假设已求得St,现在要求St+1,需要注意的是St+1是St去掉高位数据,其余的m-1位乘以d后再在最低位加一位得到。于是

                                                St+1 = d * (St – dm-1*S[t]) + S[t+m]

         公式比较晦涩,举个例子看看吧。比如上面例子中主串是65127451234。S2=127,那么S3=10×(127-102×1)+ 4 = 274

       

         现在的问题是,如果A的值太大,比较的过程会比较耗时,这个时候我们可以将这个大数mod q(q是一个大素数),同理,st也mod q,将两个取模之后的数相比较。

     

    3,RK算法的实现    

     1 #define q 144451
     2 #define d 26
     3 
     4 int isMatch(char *S, int i, char *P, int m)
     5 {
     6     int is, ip;
     7     for(is=i, ip=0; is != m && ip != m; is++, ip++)
     8         if(S[is] != P[ip])
     9             return 0;
    10     return 1;
    11 }
    12 
    13 /*
    14  * 字符串匹配的RK算法
    15  * Author:Rabin & Karp
    16  * 实现:CobbLiu
    17  * 若成功匹配返回主串中的偏移,否则返回-1
    18  */
    19 int RK(char *S, char *P)
    20 {
    21     int m  = strlen(P);
    22     int n  = strlen(S);
    23     unsigned int h   = 1
    24     unsigned int A   = 0;
    25     unsigned int St  = 0;
    26     int i;
    27 
    28     //初始化,算出最d进制下的最高位
    29     for(i = 0;i < m - 1;i++)
    30         h = (h*d) % q;
    31 
    32     for(i = 0; i != m; i++){
    33         A = (d*A + (P[i] - 'a')) % q;
    34         St = (d*St + (S[i] - 'a')) % q;
    35     }
    36 
    37     for(i = 0; i != n-m; i++){
    38         if(A == St)
    39             if(isMatch(S,i,P,m))
    40                 return i;
    41         St = (d*(St - h*(S[i]-'a'))+(S[i+m]-'a')) % q;
    42     }
    43 
    44     return -1;
    45 }

     

    4,算法的复杂度分析

      如果选择的素数q>=m, 则RK算法的期望运行时间为O(n+m), 如果m<<n,则算法的期望运行时间为O(n)。具体推理过程请参看《算法导论》第32章P562页。

     

  • 相关阅读:
    C++ 多线程 (4) 互斥量(mutex)与锁(lock)
    C++ 多线程(3)std::thread 详解
    c++ 多线程(2)创建线程对象的方法
    CMake解决c++11的phread库问题:undefined reference to `pthread_create’
    生成对抗网络--Generative Adversarial Networks (GAN)
    语义分割(semantic segmentation)——U-Net
    目标检测SSD: Single Shot MultiBox Detector
    基于内容的图像检索(CBIR) ——以图搜图
    去噪自动编码器
    利用Chrome开发者工具功能进行网页整页截图的方法
  • 原文地址:https://www.cnblogs.com/cobbliu/p/2517151.html
Copyright © 2011-2022 走看看