字符串匹配算法
#include <stdio.h> #include <stdlib.h> #include <string.h> #define ASCII_SIZE 256 /*一个字符一个字符移动比较*/ //暴力匹配BF算法 int BF_BruteForce(char *dest, char *src) { int i, j; if (NULL == dest || NULL == src) { return -1; } int n = (int)strlen(dest); int m = (int)strlen(src); if (n > m) { return -2; } for (i = 0; i <= m - n; i++) { if (dest[0] == src[i]) { for (j = 0; j <= n; j++) { if (dest[j] != src[j + i]) { break; } else if (dest[j + 1] == '\0') { return 1; } } } } return 0; } //RK算法:利用哈希表,每个子字符串为一个哈希值,做比较 //BM算法 /*创建坏点哈希表*/ void BM_CreatBadSpotHash(char dest[], int n, int b[]) { int i; for (i = 0; i < ASCII_SIZE; i++) { b[i] = -1; } /* 哈希表存储每个字符最后出现的下标 */ for (i = 0; i < n; i++) { int asc = (int)dest[i]; b[asc] = i; } } int BM_BoyerMoore_BadSpot(char dest[], int n, char src[], int m) { int i, j; int b[ASCII_SIZE]; BM_CreatBadSpotHash(dest, n, b); i = 0; while (i < m - n) { for (j = n - 1; j >= 0; j--) { if (dest[j] != src[i + j]) { break; } } if (j < 0) { return i; } else { //计算移动的距离 i = i + (j - b[(int)src[i + j]]); } } } //创建后缀哈希表 //suffix 存储字符串后缀字符在前面最后一次出现的下标, prefix 存储后缀字符串是否有前缀字符串与之相同 void BM_CreatSuffixHash(char dest[], int n, int suffix[], int prefix[]) { int i, j; int k; for (i = 0; i < n; i++) { suffix[i] = -1; prefix[i] = 0; } //从前往后寻找相同后缀 for (i = 0; i < n - 1; i++) { k = 0; j = i; while ((j >= 0) && (dest[j] == dest[n - k - 1])) { j--; k++; suffix[k] = j + 1; } if (-1 == j) { prefix[k] = 1; } } // for (k = 1; k <= n - 1; k++) // { // printf("%d, %d\n", suffix[k], prefix[k]); // } } //根据后缀哈希表移动,j表示坏点的下标,n为子串的长度 int BM_BoyerMoore_GoodSuffix(int j, int n, int suffix[], int prefix[]) { int i; //计算后缀个数 int k = n - j - 1; if (suffix[k] != -1) { //加1表示从坏点后移一个,移动到后缀的第一个字母的下标 return j - suffix[k] + 1; } else { //如果没有后缀,则依次看前缀有几个字符能和后缀匹配上 for (i = j + 2; i < n - 1; i++) { if (1 == prefix[n - i])//如果后缀的n - i个字符有对应前缀 { return i; } } } } int max(int a, int b) { return a > b ? a : b; } int BM_BoyerMoore(char a[], int n, char b[], int m) { int i, j; int x, y; int bad_spot_hash[ASCII_SIZE]; BM_CreatBadSpotHash(a, n, bad_spot_hash); int suffix[n]; int prefix[n]; BM_CreatSuffixHash(a, n, suffix, prefix); i = 0; while (i < m - n) { for (j = n - 1; j >= 0; j--) { if (a[j] != b[i + j]) { break; } } if (j < 0) { return i; } x = (j - bad_spot_hash[(int)b[i + j]]); y = 0; if (j < n - 1) { y = BM_BoyerMoore_GoodSuffix(j, n, suffix, prefix); } i = i + max(x, y); } return -1; } #define A_SIZE 4 #define B_SIZE 10 /* 在排序中可以不用坏点排序,直接用后缀,但是用坏点可以提高一定效率 后缀的本质和坏点相同,只不过是按字符串来移动 */ int main() { char a[A_SIZE] = "baaa"; char b[B_SIZE] = "baaaaaaaaa"; printf("%d\n", BM_BoyerMoore(a, A_SIZE, b, B_SIZE)); //int s[A_SIZE]; //int p[B_SIZE]; //BM_CreatSuffixHash(a, A_SIZE, s, p); return 0; }
参考链接: