Chinaunix首页 | 论坛 | 博客
  • 博客访问: 691311
  • 博文数量: 109
  • 博客积分: 2033
  • 博客等级: 大尉
  • 技术积分: 1454
  • 用 户 组: 普通用户
  • 注册时间: 2011-03-11 13:26
文章分类

全部博文(109)

文章存档

2012年(5)

2011年(104)

分类: C/C++

2011-04-06 08:18:26

在C/C++语言编程过程中,一般的字符串搜索操作都是通过标准库的strstr()函数来完成的,这在通常的情况下,因为字符串的搜索操作不多,并不会产生效率问题。实际上,这个函数的时间复杂度不容乐观。如果要从长度为n的字符串中查找长度为m的子字符串,那么这个strstr()函数的最坏时间复杂度为O(n*m),可见,随着子字符串长度m的增大,strstr()函数的时间复杂度也相应地成倍增加,有没有更加高效的算法呢?
KMP(Knuth-Morris-Pratt)算法通过预先计算模式字符串中相应字符处的回溯索引,避免了模式匹配时不必要的回溯操作,从而提高了效率,将时间复杂度变成了O(m+n)。至于更加详细的内容,请教Google老师是个不错的主义,其中“KMP算法详解”这篇文章讲解的比较透彻,值得一看。
KMP算法因为要保存每个字符的回溯索引,所以空间复杂度会略微有所增加
sizeof(idx)*length(pattern)
另外,当n比较小时,建立回溯索引所引入的O(m)个时间复杂度也许并不轻松。这些条件致使KMP算法适用于n和m都比较大,且字符串搜索操作比较频繁的环境,例如:网络入侵检测系统和QoS系统等。
实际上Linux 2.6版内核从2.6.14开始就引入了名为string的iptables匹配(match)模块,他提供有KMP、BM(Boyer-Moore)和FSM(finite state machine)算法,可以实现基于关键字的网络过滤。
在学习这个算法的过程中,将Linux内核中的实现代码搬到了用户空间:

#include
#include
void kmp_init(const char *patn, int len, int *next)
{
int i, j;
assert(patn != NULL && len > 0 && next != NULL);
        next[0] = 0;
for (i = 1, j = 0; i < len; i ++) {
while (j > 0 && patn[j] != patn[i])
                        j = next[j - 1];
if (patn[j] == patn[i])
                        j ++;
                next[i] = j;
}
}
int kmp_find(const char *text, int text_len, const char *patn,
int patn_len, int *next)
{
int i, j;
assert(text != NULL && text_len > 0 && patn != NULL && patn_len > 0
&& next != NULL);
for (i = 0, j = 0; i < text_len; i ++ ) {
while (j > 0 && text[i] != patn[j])
                        j = next[j - 1];
if (text[i] == patn[j])
                        j ++;
if (j == patn_len)
return i + 1 - patn_len;
}
return -1;
}
int main(int argc, char *argv[])
{
int *next;
int i, pos, len = strlen(argv[2]);
if (argc < 3) {
printf("Usage: %s text pattern\n", argv[0]);
return 1;
}
        next = calloc(strlen(argv[2]), sizeof(int));
        kmp_init(argv[2], strlen(argv[2]), next);
printf("next array:\n");
for (i = 0; i < len; i ++)
printf("\t%c", argv[2][i]);
printf("\n");
for (i = 0; i < len; i ++)
printf("\t%d", next[i]);
printf("\n");
        pos = kmp_find(argv[1], strlen(argv[1]), argv[2], strlen(argv[2]), next);
printf("find result:\n");
if (pos < 0) {
printf("None found!\n");
} else {
printf("%s\n", argv[1]);
for (i = 0; i < pos; i ++)
printf(" ");
printf("^\n");
}
return 0;
}
 
本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/skyblooming/archive/2008/10/06/3022270.aspx
阅读(2040) | 评论(0) | 转发(0) |
0

上一篇:pointer targets

下一篇:fastsearch implementation

给主人留下些什么吧!~~