算法导论第三十二章-字符串匹配-Cpp代码实现

来源:互联网 发布:mac系统应用内存不足 编辑:程序博客网 时间:2024/05/03 10:25

算法导论第三十二章-字符串匹配-Cpp代码实现。

这里主要实现了4种字符串的匹配方法,包括朴素字符串匹配,Rabin-Karp算法,有限自动机和KMP算法。

Rabin-Karp算法有点类似于使用了hash方法。

有限自动机很巧妙使用当前匹配的字符数来作为状态,使得算法看起来简单易懂。

KMP算法是很经典的线性方法,速度很快,但是理解起来不是很容易。

string_matching.h

#pragma once/*************************************************Author:董小歪Date:2016-06-28Description:算法导论第三十二章-字符串匹配-Cpp代码实现**************************************************/#ifndef STRING_MATCHING_H#define STRING_MATCHING_H#include <iostream>#include <vector>#include <math.h>#include <unordered_map>#include <algorithm>using namespace std;class String_Matching{public:void naive_string_matcher(const vector<char> &T, const vector<char> &P);//朴素字符串匹配算法void rabin_karp_matcher(const vector<int> &T, const vector<int> &P, int d, int q);//Rabin-Karp算法void finite_automaton_matcher(const vector<char> &T, const vector<char> &P);//有限自动机匹配算法void kmp_matcher(const vector<char> &T, const vector<char> &P);//KMP匹配算法template <typename a, typename b> void show(const vector<a> &T, const vector<b> &P);//显示数组和模式private:bool rabin_karp_help(const vector<int> &T, const vector<int> &P, int s);//判断是否伪命中点bool finite_automaton_help(const vector<char> &P, int k, int q, char a);//判断是否为后缀void compute_transition_function(const vector<char> &P);//计算转移函数void compute_prefix_function(const vector<char> &P);//计算共同前后缀vector<unordered_map<char, int>> theta;//转移函数vector<int> pi;//共同前后缀};template <typename a, typename b>void String_Matching::show(const vector<a> &T, const vector<b> &P){cout << "数组为:";for (int i = 0; i < T.size(); ++i) cout << T[i] << ",";cout << endl << "模式为:";for (int i = 0; i < P.size(); ++i) cout << P[i] << ",";cout << endl << "匹配的结果为:" << endl;}#endif // !STRING_MATCHING_H

string_matching.cpp

#include "string_matching.h"void String_Matching::naive_string_matcher(const vector<char> &T, const vector<char> &P){int n = T.size();int m = P.size();int i, j;for (i = 0; i <= n - m; ++i){j = 0;while (j < m){if (T[i + j] != P[j])break;++j;}if (j == m)cout << "Pattern occurs with shift " << i << endl;}}void String_Matching::rabin_karp_matcher(const vector<int> &T, const vector<int> &P, int d, int q){int n = T.size();int m = P.size();int h = _Pow_int(d, m - 1) % q;int p = 0, t = 0;for (int i = 0; i < m; ++i){p = (d*p + P[i]) % q;t = (d*t + T[i]) % q;}for (int s = 0; s <= n - m; ++s){if (p == t){if (rabin_karp_help(T, P, s))cout << "Pattern occurs with shift " << s << endl;elsecout << "Pattern occurs with shift " << s << "是伪命中点" << endl;}if (s < n - m){int temp = (d*(t - T[s] * h) + T[s + m]) % q;if (temp < 0) temp += q; //这里注意,如果是负数要转变为正数t = temp;}}}bool String_Matching::rabin_karp_help(const vector<int> &T, const vector<int> &P, int s){for (int i = 0; i < P.size(); ++i)if (P[i] != T[i + s])return false;return true;}void String_Matching::finite_automaton_matcher(const vector<char> &T, const vector<char> &P){int n = T.size();int m = P.size();compute_transition_function(P);int q = 0;//q表示已经匹配的个数,或者是当前的状态for (int i = 0; i < n; ++i){q = theta[q][T[i]];//计算当前状态q的情况下,下一个字符是T[i],转换后的状态if (q == m)cout << "Pattern occurs with shift " << (i-m + 1) << endl;}}void String_Matching::compute_transition_function(const vector<char> &P){int m = P.size();theta.resize(m + 1);for (int q = 0; q <= m; ++q){for (char ch = 'a'; ch <= 'c'; ++ch)//这里简单的只有abc3个字符集{//q表示当前状态,k表示下一个状态。k最多只能是q+1或者m。m是结束状态,而最多往前进一个状态int k = min(m + 1, q + 2);do {--k;} while (k > 0 && finite_automaton_help(P, k, q, ch));theta[q][ch] = k;}}}//判断P的前k个字符是否是前q个字符+a的后缀bool String_Matching::finite_automaton_help(const vector<char> &P, int k, int q, char a){if (P[k-1] != a) return true;for (int i = k - 2, j = q - 1; i >= 0 && j >= 0; --i, --j){if (P[i] != P[j])return true;}return false;}void String_Matching::kmp_matcher(const vector<char> &T, const vector<char> &P){int n = T.size();int m = P.size();compute_prefix_function(P);//计算辅助共同前后缀int q = 0;//q表示当前已经匹配的个数for (int i = 0; i < n; ++i){while (q > 0 && P[q] != T[i])q = pi[q];if (P[q] == T[i])++q;if (q == m){cout << "Pattern occurs with shift " << (i - m + 1) << endl;q = pi[q];}} }void String_Matching::compute_prefix_function(const vector<char>& P){int m = P.size();pi.resize(m + 1);pi[1] = 0;int k = 0;for (int q = 2; q <= m; ++q){while (k > 0 && P[k] != P[q-1])k = pi[k];if (P[k] == P[q-1])++k;pi[q] = k;}}

测试代码:

main_entrance.cpp

#include "string_matching.h"int main(){String_Matching sm;vector<char> T1 = { 'a','c','a','a','b','c' };vector<char> P1 = { 'a','a','b' };cout << "朴素字符串匹配算法:" << endl;sm.show(T1, P1);sm.naive_string_matcher(T1, P1);vector<int> T2 = { 2,3,5,9,0,2,3,1,4,1,5,2,6,7,3,9,9,2,1 };vector<int> P2 = { 3,1,4,1,5 };cout << endl << "Rabin-Karp算法:" << endl;sm.show(T2, P2);sm.rabin_karp_matcher(T2, P2, 10, 13);vector<char> T3 = { 'a','b','a','b','a','b','a','c','a','b','a' };vector<char> P3 = { 'a','b','a','b','a','c','a' };cout << endl << "有限自动机匹配算法:" << endl;sm.show(T3, P3);sm.finite_automaton_matcher(T3, P3);vector<char> T4 = { 'b','a','c','b','a','b','a','b','a','b','a','b','a','c','a' };vector<char> P4 = { 'a','b','a','b','a','c','a' };cout << endl << "KMP匹配算法:" << endl;sm.show(T4, P4);sm.kmp_matcher(T4, P4);system("pause");}


测试结果:



0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 睡觉时有窒息感怎么办 孕妇左边胯骨疼怎么办 怀孕了肋骨疼怎么办 孕妇左侧肋骨疼怎么办 宝宝睡觉质量差怎么办 晚上睡觉作梦怎么办 猫打呼噜很大声怎么办 一睡觉就做梦怎么办 脑子里老是幻觉怎么办 严重认床睡不着怎么办 认床导致睡不着怎么办 碰到打呼噜的人怎么办 打呼吵得睡不着怎么办 打呼太吵睡不着怎么办 睡觉时舍友说话怎么办 夜晚醒了睡不着怎么办 夜晚怕黑睡不着怎么办 宝宝不愿意盖被子怎么办 白天睡觉晚上睡不着怎么办 晚上睡觉不安神怎么办 晚上经常睡不着觉怎么办 老是睡不着觉怎么办啊 小孩睡觉不安稳怎么办 睡觉时动不了怎么办 特别累还睡不着怎么办 又累又睡不着怎么办 干活累的睡不着怎么办 狗一有动静就叫怎么办 楼上天天闹动静怎么办 喝了奶茶失眠怎么办 失眠一宿第二天怎么办 睡觉外面噪音大怎么办 怀孕早期晚上睡不着怎么办 短发发尾翘怎么办 很累就是睡不着怎么办 人累但是睡不着怎么办 如果晚上睡不着该怎么办 晚上睡不着觉该怎么办 晚上睡不着该怎么办呢 晚上失眠睡不着该怎么办 晚上一直睡不着该怎么办