字符串匹配算法(BF RK)
生活随笔
收集整理的這篇文章主要介紹了
字符串匹配算法(BF RK)
小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
文章目錄
- 1. BF(Brute Force)暴力匹配
- BF代碼
- 2. RK(Rabin-Karp)算法
- RK代碼
- 3. 思考題:(二維匹配)
1. BF(Brute Force)暴力匹配
BF算法的思想,在主串中,檢查起始位置分別是0、1、2…n-m且長度為m的n-m+1個(gè)子串,看有沒有跟模式串匹配的。最壞情況下每次都要對比m個(gè)字符,對比次數(shù)n-m+1次,復(fù)雜度O(m*n),適用小規(guī)模字符串匹配
BF代碼
/*** @description: BF暴力匹配* @author: michael ming* @date: 2019/6/17 20:11* @modified by: */ #include <string> #include <iostream> using namespace std; int str_BFM(string s, int pos, string t) {if(s.length()== 0 || t.length() == 0)return 0;int i = pos - 1, j = 0;while(i < s.length() && j < t.length()){if(s[i] == t[j]){i++;j++;}else//字符串匹配失敗,主串查找開始位置i+1,模式串從頭開始{i = i - j + 1;j = 0;}}if(j >= t.length())return i-j+1;elsereturn 0; } int main() {string a = "ababcabcacbab", b = "abcac";cout << a << "中第一次出現(xiàn)" << b << "的位置是:" << str_BFM(a,1,b) << endl;return 0; }2. RK(Rabin-Karp)算法
- 上面BF算法,每次檢查主串與子串是否匹配,需要逐次對比每個(gè)字符
- 引入哈希,降低復(fù)雜度
- RK算法思路:對n-m+1個(gè)子串分別求哈希值,然后與模式串的哈希值比較;如果某個(gè)子串的哈希值和模式串的哈希值匹配(需要考慮哈希沖突),比較數(shù)字是否相等是非常快的,所以效率比BF效率高
- But, 計(jì)算子串的哈希值的時(shí)候,需要遍歷每個(gè)字符;雖然比較效率高了,但是整體效率沒有提高
- 哈希算法設(shè)計(jì)技巧:K進(jìn)制數(shù)表示子串(無沖突)(K為字符集內(nèi)字符種數(shù))
- K進(jìn)制法,相鄰子串的哈希值計(jì)算公式有一定的關(guān)系:
- 26(m-1)可以提前算好存放在數(shù)組中,指數(shù)就是數(shù)組的下標(biāo),計(jì)算26的x次方時(shí),直接去數(shù)組下標(biāo)x位置讀取
- 復(fù)雜度,計(jì)算子串哈希值需要掃描一遍主串O(n);比較n-m+1個(gè)子串哈希值O(n);所以整體復(fù)雜度O(n)(取決于哈希函數(shù)沖突概率)
- 問題:如果模式串很長,子串的哈希值很大,超過計(jì)算機(jī)可表示的范圍,怎么辦?
針對哈希值范圍溢出,改造哈希函數(shù):
(1) 將a對應(yīng)1,以此類推z對應(yīng)26,將字符串每個(gè)字符對應(yīng)數(shù)字相加作為哈希值,值的范圍小了 (但是沖突概率有點(diǎn)大)
(2) 將每個(gè)字符對應(yīng)一個(gè)質(zhì)數(shù)(沖突概率降低) - 存在沖突的情況下,如果模式串和子串哈希值相等,再比較一下它兩真的相等否。
- 哈希算法沖突概率要比較低,否則RK算法復(fù)雜度退化,效率下降
RK代碼
/*** @description:RK匹配算法,計(jì)算子串哈希值,進(jìn)行對比* @author: michael ming* @date: 2019/6/17 22:40* @modified by: */ #include <string> #include <iostream> using namespace std; bool same(char* a, char* b, int m) {for(int i = 0; i < m; ++i){if(a[i] != b[i])return false;}return true; } int str_RK(string s, string t)//s是主串,t是模式串 {int n = s.length(), m = t.length();int table[26] = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43,47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101};//質(zhì)數(shù)表對應(yīng)a-zint i, j, hash_val, value = 0;for(i = 0; i < m; ++i) //計(jì)算模式串的hash值value{value += table[t[i]-'a'];}for(i = 0; i < n-m+1; ++i)//最多n-m+1次比較{hash_val = 0;for(j = i; j < m+i; ++j)//計(jì)算第i個(gè)子串的哈希值{hash_val += table[s[j]-'a'];}if(hash_val == value && same(&s[i],&t[0],m)){//如果子串哈希值等于模式串的,且"真的"字符串匹配(避免沖突帶來的假匹配)return i+1;//返回匹配位置,第i位開始,i從1開始}}return 0; } int main() {string a = "ababcabcacbab", b = "abcac";cout << a << "中第一次出現(xiàn)" << b << "的位置是:" << str_RK(a,b) << endl;return 0; }
如果不檢查沖突,刪除以下條件,匹配會出錯(cuò)
3. 思考題:(二維匹配)
對RK算法進(jìn)行改造得到答案
nr 主串行數(shù)
nc 主串列數(shù)
mr 模式串行數(shù)
mc 模式串列數(shù)
復(fù)雜度則為O((nr-mr+1)*(nc-mc+1)),簡寫為O(nr * nc)
總結(jié)
以上是生活随笔為你收集整理的字符串匹配算法(BF RK)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 在android添加数据采集,一种基于A
- 下一篇: 算法--排序--寻找数组内第K大的元素