- 蛮力查找
通过穷尽遍历的方式查询,效率最低。
int force_search(char * s, int sl, char * p, int pl) { int i(0); while ( i + pl <= sl) { int j(i), k(0); while (k < pl) if (s[j] == p[k]) (j ++, k ++); else break; if (k == pl) return i; ++ i; } return -1; }
- kmp查找
kmp算法尽管只有几句代码,但是非常难理解,昨天跟代码走了好几遍,才渐渐晓得主要思想:
首先分析模式字符串,针对所有的前缀字符串(和全串)获取其所有前缀与后缀字符串的最大公共长度,借助这个长度(即nexts数组)在匹配的时候进行偏移;
void get_nexts(char * p, int pl, int * nexts) { int j(0), k(-1); nexts[0] = -1; while (j < pl) if (p[j] == p[k] || k == -1) nexts[++ j] = ++ k; else k = nexts[k]; }
对nexts数组进行优化,充分利用当前不匹配的字符,尽最大可能右移nexts数组;
void get_nexts2(char * p, int pl, int * nexts) { int j(0), k(-1); nexts[0] = -1; while (j < pl) if (p[j] == p[k] || k == -1) { (++ j, ++ k); nexts[j] = (p[j] != p[k]) ? k : nexts[k]; } else k = nexts[k]; }
然后逐字符比较,遇到不匹配的只是移动模式字符串的指针(或者int型的索引,指示当前待比较的字符),而主串只是一直往后走;
int kmp_search(char * s, int sl, char * p, int pl) { int * nexts = new int[pl + 1]; get_nexts2(p, pl, nexts); int i(0), j(0); int indexbegin(0); while (j < pl && i < sl) if (s[i] == p[j]) (++ i, ++ j); else { indexbegin = i - nexts[j]; 0 == j ? ++ i :j = nexts[j]; } delete[] nexts; return j == pl ? indexbegin : -1; }
- 测试
1 char * mstr = "aaabacaabacaabacabaabb"; 2 char * pstr = "abacab"; 3 4 5 cout << "========================" << endl; 6 cout 7 << force_search(mstr, strlen(mstr), pstr, strlen(pstr)) 8 << endl; 9 cout 10 << kmp_search(mstr, strlen(mstr), pstr, strlen(pstr)) 11 << endl; 12 13 for (int i = 0; i < 18; ++ i) 14 { 15 pstr = mstr + i; 16 cout << "========================" << endl; 17 cout 18 << force_search(mstr, strlen(mstr), pstr, strlen(pstr)) 19 << endl; 20 cout 21 << kmp_search(mstr, strlen(mstr), pstr, strlen(pstr)) 22 << endl; 23 }