算法导论第三十二章-字符串匹配-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
- 算法导论第三十二章-字符串匹配-Cpp代码实现
- 算法导论 第三十三章:字符串匹配
- 第三十二章 字符串匹配
- 算法导论第二章-算法基础-Cpp代码实现
- 算法导论第十六章-贪心算法-Cpp代码实现
- KMP字符串匹配(按照《算法导论》伪代码实现)
- 算法导论第六章-堆排序-Cpp代码实现
- 算法导论第七章-快速排序-Cpp代码实现
- 算法导论第八章-线性时间排序-Cpp代码实现
- 算法导论第四章-分治策略-Cpp代码实现
- 算法导论第十章-基本数据结构-Cpp代码实现
- 算法导论第十二章-二叉搜索树-Cpp代码实现
- 算法导论第十三章-红黑树-Cpp代码实现
- 算法导论第十五章-动态规划-Cpp代码实现
- 算法导论第十八章-B树-Cpp代码实现
- 算法导论第二十四章-单源最短路径-Cpp代码实现
- 【算法导论】字符串匹配
- 算法导论-字符串匹配
- 27个iOS开源库,让你的开发坐上火箭吧
- 我应该直接学 Swift,还是 Objective-C?
- platform总线设备实验
- 在消息tabBar上面添加小红点
- 打开IDE里XXX.rc文件夹的子项,显示“!加载失败”
- 算法导论第三十二章-字符串匹配-Cpp代码实现
- iOS dispatch_group_t
- Eclipse各版本代号一览表
- 注解
- 构建自己的Java Web框架(三)之JAVA反射机制
- 红烧毛豆
- iOS 图片模糊效果三种实现方式
- 在MyEclipse 8.5中创建一个maven项目
- pythong的logging模块