字符串匹配算法之BM算法


  BM算法,全稱是Boyer-Moore算法,1977年,德克薩斯大學的Robert S. Boyer教授和J Strother Moore教授發明了一種新的字符串匹配算法。

BM算法定義了兩個規則:

1、壞字符規則:當文本串中的某個字符跟模式串的某個字符不匹配時,我們稱文本串中的這個失配字符為壞字符,此時模式串需要向右移動,移動的位數 = 壞字符在模式串中的位置 - 壞字符在模式串中最右出現的位置。此外,如果"壞字符"不包含在模式串之中,則最右出現位置為-1。
2、好后綴規則:當字符失配時,后移位數 = 好后綴在模式串中的位置 - 好后綴在模式串上一次出現的位置,且如果好后綴在模式串中沒有再次出現,則為-1。

關於壞字符規則和好后綴規則的具體講解,以及怎么移動,可以查看阮一峰老師的詳細講解:http://www.ruanyifeng.com/blog/2013/05/boyer-moore_string_search_algorithm.html

這里根據講解畫了兩張圖,方便自己理解壞字符規則:

 

 

 

 

 2019年11月14日15:38:41 修改

具體代碼如下:

  1     private static final int SIZE = 256; // 全局變量或者是局部變量
  2 
  3     /**
  4      * 壞字符規則哈希表構建方法
  5      * 
  6      * @param b
  7      *            模式串
  8      * @param m
  9      *            模式串的長度
 10      * @param bc
 11      *            散列表
 12      */
 13     private void generateBC(char[] b, int m, int[] bc) {
 14         for (int i = 0; i < SIZE; ++i) {
 15             bc[i] = -1; // 初始化bc
 16         }
 17 
 18         for (int i = 0; i < m; ++i) {
 19             int ascii = (int) b[i]; // 計算b[i]的ASCII值
 20             bc[ascii] = i;
 21         }
 22     }
 23 
 24     /**
 25      * 好后綴規則構建哈希表
 26      * 
 27      * @param b
 28      *            模式串
 29      * @param m
 30      *            模式串長度
 31      * @param suffix
 32      *            suffix數組的下標 k,表示后綴子串的長度,
 33      *            下標對應的數組值存儲的是,在模式串中跟好后綴{u}相匹配的子串{u*}的起始下標值
 34      * @param prefix
 35      *            記錄模式串的后綴子串是否能匹配模式串的前綴子串
 36      */
 37     private void generateGS(char[] b, int m, int[] suffix, boolean[] prefix) {
 38         for (int i = 0; i < m; ++i) { // 初始化
 39             suffix[i] = -1;
 40             prefix[i] = false;
 41         }
 42 
 43         for (int i = 0; i < m - 1; ++i) {
 44             int j = i;
 45             int k = 0; // 公共后綴子串長度
 46             while (j >= 0 && b[j] == b[m - 1 - k]) { // 與b[0, m-1]求公共后綴子串
 47                 --j;
 48                 ++k;
 49                 suffix[k] = j + 1; // j+1表示公共后綴在b[0,i]中的起始下標
 50             }
 51             if (j == -1) {
 52                 prefix[k] = true; // 如果公共后綴子串也是模式串的后綴子串
 53             }
 54         }
 55     }
 56 
 57     /**
 58      * 完整的BM算法 好后綴+壞字符
 59      * 
 60      * @param a
 61      *            主串
 62      * @param n
 63      *            主串的長度
 64      * @param b
 65      *            模式串
 66      * @param m
 67      *            模式串的長度
 68      * @return
 69      */
 70     public int bm(char[] a, int n, char[] b, int m) {
 71         int[] bc = new int[SIZE];
 72         generateBC(b, m, bc); // 構建壞字符哈希表
 73         int[] suffix = new int[m];
 74         boolean[] prefix = new boolean[m];
 75         generateGS(b, m, suffix, prefix); // 構建好字符哈希表
 76         int i = 0; // j 表示主串與模式串匹配的第一個字符
 77         while (i < n - m) {
 78             int j = 0;
 79             for (j = m - 1; j >= 0; --j) {// 模式串從后向前匹配
 80                 if (a[i + j] != b[j]) {
 81                     break; // 壞字符串
 82                 }
 83             }
 84             if (j < 0) {
 85                 return i;// 匹配成功,返回主串和模式串第一個匹配字符的位置
 86             }
 87             int x = j - bc[(int) a[i + j]];
 88             int y = 0;
 89             if (j < m - 1) { // 如果有好后綴的話
 90                 y = moveByGS(j, m, suffix, prefix);
 91             }
 92             i = i + Math.max(x, y);
 93         }
 94         return -1;
 95     }
 96 
 97     private int moveByGS(int j, int m, int[] suffix, boolean[] prefix) {
 98         int k = m - 1 - j; // 好后綴的長度
 99         if (suffix[k] != -1) {
100             return j - suffix[k] + 1;
101         }
102         for (int r = j + 2; r <= m - 1; ++r) {
103             if (prefix[m - r] == true) {
104                 return r;
105             }
106         }
107         return m;
108     }    

 現在再看BM算法,原來之前自己是一點也沒弄懂!只是當做文章簡單讀了一遍,阿西吧!

首先,那個壞字符的散列表的構建就沒有弄懂:

1、為什么在散列表數組中要初始化每一個值為-1?

這里是在壞字符匹配的時候,如果主串與模式串中字符沒有匹配上(把壞字符在模式串中下標記做xi),此時的xi=-1

2、你有沒有考慮過模式串中的相同的字符的ASCII碼是相同的,那樣循環處理的話,只是記錄模式串中相同字符中最后面的那個字符的下標,沒有問題嗎?

這個是沒有問題的!這里無非有兩種情況,就是壞字符與非壞字符:

壞字符:因為是從后向前倒序匹配,只需要知道后面的字符下標,就可以計算出移動距離

非壞字符:需要去尋找壞字符或者使用好后綴規則

2019年11月14日15:34:37 修改

 

此大部分內容來自極客時間專欄,王爭老師的《數據結構與算法之美》

極客時間:https://time.geekbang.org/column/intro/126


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM