字符串匹配算法(KMP、BM和Sunday),及Python实现

主要对三种字符串匹配算法(KMP BM Sunday) 进行总结。这三种字符串匹配算法之间的主要区别在于:如果在匹配过程中遇到一个不匹配位,该用何种策略进行移位。例如,存在两个字符串,如下:

 

字符串:      ABCADAB ABCDABCDABD

搜索字符串:ABCDA

 

下面给出三种算法的例子

KMP:在此算法中当从前往后搜索时遇到第一个不匹配:A->D时,它将从搜索字符串入手决定移动多少位。在KMP算法的初始阶段会生成一张表,例如,上面搜索字符串生成的表为:pi[0,...,4] = {0,0,0,0,1}。这张表决定上面提到的移位。此时的移位为:3-pi[2](因为已经匹配了三个字符)。KMP算法的关键就是:匹配字符的初始生成表,而且是从前往后进行搜索。

BM:在此算法中,字符串搜索不是从头开始的,而是从末尾开始的,例如上面的例子中,首先比较的是DA,因为不相同,则在搜索字符中从后往前进行匹配查找,找到最右边的匹配字符后进行移位,如果找不到的话移位长度与匹配字符一样长,如下:

字符串:      ABCADAB ABCDABCDABD

搜索字符串:   ABCDA(移两位)

此时继续进行比较,不过此时的比较要考虑两方面以上上面提到的过程,还有一种情况就是已匹配的字符串中(DA),包含了搜索字符串的前缀(A),我们知道此时移动1~3位是没有意义的。所以BM算法的关键就是找到两种移位中的最大移位,进行以为。

Sunday:上面的两种字符串匹配算法都涉及到了对搜索字符的预处理,但Sunday算法预期完全不同。同样是上面的例子当搜到不匹配的字符串时,Sunday算法采用了一种完全不同的以为确定法。它会先找到字符串的第K+1个字符,K是搜索字符的长度。如果搜索字符串中不包含字符串中第K+1个字符,则直接移动K+1位。否则,按着BM算法移动搜索串中最右端的该字符到末尾的距离+1位。


    class StringPatternt(object):
        def __init__(self,chr,p):
            self.chr = chr;
            self.p = p;
            self.p_len = len(p);
            self.pi = [0 for i in range(self.p_len)];
        def set_pattern(self,p):
            self.p = p;
            self.p_len = len(p);
        def set_chr(self,chr):
            self.chr = chr;
            
        '''KMP'''
        def __kmp_partial_match_table__(self):
            k=0;q = 1;
            #self.pi[0] = 0;
            while q < self.p_len:
                while (k > 0) and (self.p[k] != self.p[q]):
                    k = self.pi[k-1];
                if self.p[k] == self.p[q]:
                    k = k+1;
                self.pi[q] = k;
                q = q+1;
            return 0;
        
        def string_pattern_kmp(self):
            self.__kmp_partial_match_table__();
            print(self.pi);
            list_size = len(self.chr);
            pi_len = len(self.pi);
            k=0;
            for q in range(list_size):
                while (k > 0) and (self.p[k] != self.chr[q]):
                    k = self.pi[k-1];
                if self.p[k] == self.chr[q]:
                    k = k+1;
                if k == pi_len:
                    return q-pi_len+1;
                #q = q+1;
            return 0;
        
        '''BM'''
        def __calc_match__(self,num):
            k=num;j=0;
            while k>=0:
                if self.p[-k] == self.p[j]:
                    k = k-1; j=j+1;
                    if k<=0:
                        self.pi[num-1] = num;
                        return 0;
                else:
                    if num == 1:
                        return 0;
                    self.pi[num-1] = self.pi[num-2];
                    return 0;
            
        def __init_good_table__(self):
            i=1;
            while i <= self.p_len:
                self.__calc_match__(i);
                i=i+1;
            print (self.pi);
            return 0;
        
        def __check_bad_table__(self,tmp_chr):
            i=1;
            while self.p_len-i >= 0:
                if self.p[-i] == tmp_chr:
                    return i;
                else:
                    i = i+1;
            return self.p_len+1;
        
        def __check_good_table__(self,num):
            if not num:
                return self.p_len;
            else:
                return self.pi[num];
        
        def string_pettern_bm(self):
            self.__init_good_table__();
            tmp_len = self.p_len;
            i = 1;
            while tmp_len <= len(self.chr):
                if self.p[-i]==self.chr[tmp_len-i]:
                    i = i+1;
                    if i > self.p_len:
                        return tmp_len-self.p_len;
                else:
                    tmp_bad = self.__check_bad_table__(self.chr[tmp_len-i])-i;
                    tmp_good= self.p_len-self.__check_good_table__(i-1);
                    tmp_len = tmp_len+ max(tmp_bad,tmp_good);
                    print(tmp_bad,tmp_good,tmp_len);
                    i=1;
            return 0;
        
        '''sunday'''
        def __check_bad_shift__(self,p):
            i=0;
            while i<self.p_len:
                if self.p[i] == p:
                    return i;
                else:
                    i = i+1;
            return -1;
        
        def string_pattern(self):
            #self.__init_good_table__();
            tmp_len = 0;
            tmp_hop = self.p_len;
            i=0;
            while tmp_hop <= len(self.chr):
                if self.p[i] == self.chr[tmp_len+i]:
                    i = i+1;
                    if i == self.p_len:
                        return tmp_len;
                else:
                    tmp_len = tmp_len+self.p_len-self.__check_bad_shift__(self.chr[tmp_hop]);
                    tmp_hop = tmp_len+self.p_len;
                    i=0;
            return 0;



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值