日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

字符串匹配算法(BF RK)

發(fā)布時(shí)間:2024/7/5 编程问答 35 豆豆
生活随笔 收集整理的這篇文章主要介紹了 字符串匹配算法(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ò)

same(&s[i],&t[0],m)

3. 思考題:(二維匹配)


對RK算法進(jìn)行改造得到答案
nr 主串行數(shù)
nc 主串列數(shù)
mr 模式串行數(shù)
mc 模式串列數(shù)
復(fù)雜度則為O((nr-mr+1)*(nc-mc+1)),簡寫為O(nr * nc)

/*** @description: 2維字符串匹配* @author: michael ming* @date: 2019/6/18 0:07* @modified by: */ #include <iostream> #define nr 5 //主串行數(shù) #define nc 5 //主串列數(shù) #define mr 2 //模式串行數(shù) #define mc 2 //模式串列數(shù) int cal_hash_t(int* table, int r, int c, char ch[][mc]) {int i, j, value = 0;for (i = 0; i < r; ++i) //計(jì)算2d模式串的hash值value{for(j = 0; j < c; ++j)value += table[ch[i][j]-'a'];}return value; } int cal_hash_s_child(int* table, int i0, int j0, int r, int c, char ch[][nc]) {int i, j, hash_value = 0;for (i = i0; i < r; ++i) //計(jì)算2d子串的hash值value{for(j = j0; j < c; ++j)hash_value += table[ch[i][j]-'a'];}return hash_value; } bool same(char s[][nc], char t[][mc], int i0, int j0) {int x = i0, y = j0, i, j;for(i = 0; i < mr; ++i,++x){for(j = 0, y = j0; j < mc; ++j,++y)//記得寫y=j0,換行后y復(fù)位{if(s[x][y] != t[i][j])return false;}}return true; } bool str_RK_2d(char s[][nc], char t[][mc])//s是主串,t是模式串 {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;value = cal_hash_t(table,mr,mc,t);//計(jì)算2d模式串哈希值for(i = 0; i < nr-mr+1; ++i)//行最多nr-mr+1次比較{for(j = 0; j < nc-mc+1; ++j)//列最多nc-mc+1次比較{hash_val = cal_hash_s_child(table,i,j,mr+i,mc+j,s);//計(jì)算2d子串哈希值if(hash_val == value && same(s,t,i,j)){//如果2d子串哈希值等于模式串的,且"真的"字符串匹配(避免沖突帶來的假匹配)std::cout << "找到模式矩陣,其左上角在 " << i+1 << " 行," << j+1 << " 列." << std::endl;return true;}}}return false; }int main() {char s[ ][nc] = {{ 'a', 'b', 'a', 'b', 'a' },{ 'a', 'b', 'a', 'b', 'a' },{ 'a', 'b', 'b', 'a', 'a' },{ 'a', 'b', 'a', 'a', 'b' },{ 'b', 'b', 'a', 'b', 'a' }};char t[ ][mc] = {{ 'a', 'b' },{ 'b', 'a' }};str_RK_2d(s,t);char a[ ][nc] = {{ 'd', 'a', 'b', 'c' },{ 'e', 'f', 'a', 'd' },{ 'c', 'c', 'a', 'f' },{ 'd', 'e', 'f', 'c' },{ 'b', 'b', 'a', 'b' }};char b[ ][mc] = {{ 'c', 'a' },{ 'e', 'f' }};str_RK_2d(a,b);return 0; }



總結(jié)

以上是生活随笔為你收集整理的字符串匹配算法(BF RK)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。