Sunday算法(字符串查找、匹配)

 

  字符串查找算法中,最著名的兩個是KMP算法(Knuth-Morris-Pratt)和BM算法(Boyer-Moore)。兩個算法在最壞狀況下均具備線性的查找時間。可是在實用上,KMP算法並不比最簡單的c庫函數strstr()快多少,而BM算法則每每比KMP算法快上3-5倍。可是BM算法還不是最快的算法,這裏介紹一種比BM算法更快一些的查找算法。
  例如咱們要在"substring searching algorithm"查找"search",剛開始時,把子串與文本左邊對齊,html

substring searching algorithm
search
^算法

  結果在第二個字符處發現不匹配,因而要把子串日後移動。可是該移動多少呢?這就是各類算法各顯神通的地方了,最簡單的作法是移動一個字符位置;KMP是利用已經匹配部分的信息來移動;BM算法是作反向比較,並根據已經匹配的部分來肯定移動量。這裏要介紹的方法是看緊跟在當前子串以後的那個字符(上圖中的'i')函數

  顯然,無論移動多少,這個字符是確定要參加下一步的比較的,也就是說,若是下一步匹配到了,這個字符必須在子串內。因此,能夠移動子串,使子串中的最右邊的這個字符與它對齊。如今子串'search'中並不存在'i',則說明能夠直接跳過一大片,從'i'以後的那個字符(即‘n’)開始做下一步的比較,以下圖:spa

substring searching algorithm
           search
         ^指針

  比較的結果,第一個字符就不匹配,再看子串後面的那個字符,是'r',它在子串中出如今倒數第三位,因而把子串向前移動三位,使兩個'r'對齊,以下:code

substring searching algorithm
              search

  哈!此次匹配成功了!回顧整個過程,咱們只移動了兩次子串就找到了匹配位置,是否是很神啊?!能夠證實,用這個算法,每一步的移動量都比BM算法要大,因此確定比BM算法更快。htm


下面是這個算法的c代碼。注意我假設了每一個字符的值都介於0-127之間(即純ascii碼)。blog

 

 1 #ifndef SUNDAY_H
 2 #define SUNDAY_H
 3 
 4 /********************************************************
 5 Sunday算法:
 6     假設源字符串爲src,匹配串爲pattern。
 7     若是src的某字符不匹配:
 8     (1)該字符在pattern中,且在pattern中最右邊的位置爲n。那麼
 9     下次匹配直接移動pattern使得n的位置和該字符的位置對應的地方。
10     (2)該字符不在pattern中,顯然沒有比較的意義,則直接跳過去,
11     將pattern的頭部移到與該字符下一個字符對應的位置。
12 *********************************************************/
13 
14 #include <string.h>
15 #include <stdio.h>
16 
17 // 假設出現的字符都是0~127範圍內的,即都是ascii字符
18 char *sunday(const char *src, char *pattern) {
19     if (NULL == src)
20         return NULL;
21     if (NULL == pattern)
22         return (char *)src;
23 
24     int len1, len2, shift[128];
25 
26     len1 = strlen(src);
27     len2 = strlen(pattern);
28 
29     // construct shitf table
30     for (int i = 0; i < 128; i++)
31         shift[i] = len2 + 1;  // 默認是移動len2+1,即直接跳過
32             
33     // adjust shift table
34     const char *p;
35     for (p = pattern; *p; p++)
36         shift[*p] = len2 - (p - pattern); // p-pattern爲字符相對於第一個元素的偏移量,len2-(p-pattern)則表示從右往左數的偏移量,即要移動的步數
37 
38     const char *s, *pSrc = src;
39     // start search
40     while (pSrc + len2 <= src + len1) { // 若是pSrc + len2不越界(若越界,則說明src剩餘未匹配的字符數量小於pattern的長度,則確定不會匹配成功)
41         for (p = pattern, s = pSrc; *p; ++p, ++s) 
42             if (*p != *s) // mistach
43                 break;// break內循環            
44         
45         if ('\0' == *p)  // found it!
46             return (char *)pSrc;
47 
48         pSrc += shift[pSrc[len2]]; // pSrc[len2]取出下一個須要匹配的字符,shift[pSrc[len2]]取出該字符須要讓指針移動多少步
49     }
50 
51     return NULL;
52 }
53 
54 #endif

 

 

 

 下面是main:ci

 1 #include "Sunday.h"
 2 
 3 int main() {
 4     char *src = "123456789", *patt = "234";
 5     char *ret = sunday(src, patt);
 6 
 7     printf("%s\n", ret);
 8 
 9     return 0;
10 }

 

  代碼最後:pSrc += shift[pSrc[len2]];這裏。字符串

舉個例子來理解下,好比:

123456789

  237

那麼4和7不匹配,len2就表示'5'這個位置,因此pSrc[len2]表示取出'5'這個字符。

因此pSrc下次就移動到'5'這個位置從新開始匹配了。

 

 

ref:http://operatingfocus.bokee.com/3557609.html

相關文章
相關標籤/搜索