码迷,mamicode.com
首页 > 编程语言 > 详细

字符串匹配暴力算法 与 字符串匹配的KMP算法

时间:2015-04-03 09:31:26      阅读:178      评论:0      收藏:0      [点我收藏+]

标签:算法   kmp   字符串匹配   

声明:先看一下阮一峰的网络日志关于字符串的KMP算法的讲解。本文图片均引用于这篇日志。

在先前的笔试中遇到了关于字符串匹配的问题,一时脑袋卡壳没写好算法。现在就来分析分析

暴力算法和KMP算法各自原理,以及代码实现之间差异,并且总结一下好算法的一般思路

===========================================================================

各自原理:

暴力算法:

1.

技术分享

我们把长的字符串做为一个文本字符串,命名为strText,把短的字符串称为目标串,命名为strTarget。

文本串"BBC ABCDAB ABCDABCDABDE"的第一个字符‘B’与目标串"ABCDABD"的第一个字符‘A’

比较不产生匹配,在整个过程中,我们假设红色虚线是固定的。因此,文本串向左边移动一个字符。

2.

技术分享

字符‘B’与‘A’不产生匹配,文本串继续左移。

3.

技术分享

直到这里,此时出现第一个匹配,程序中将文本串和目标串都向左移动,并且记录下此时文本串出来比较

的那个元素(就是字符‘A’)的位置

4.

技术分享

继续比较,又是一个匹配,继续移动。

5.

技术分享

此时出现不匹配,比较重新归位,根据前面记录的‘A’的位置文本串进入下一个字符‘B’,而目标串的下标重新开始,

继续比较。

6.

技术分享

这个就是暴力算法的大致原理分析过程。

KMP算法:

7.

技术分享

一个基本事实是,当空格与D不匹配时,你其实知道前面六个字符是"ABCDAB"。KMP算法的想法是,设法利用这个已知信息,

不要把"搜索位置"移回已经比较过的位置,继续把它向后移,这样就提高了效率。

8.

技术分享

怎么做到这一点呢?可以针对目标串,算出一张《部分匹配表》(Partial Match Table)。这张表是如何产生的,后面再介绍,

这里只要会用就可以了。

9.

技术分享

已知空格与D不匹配时,前面六个字符"ABCDAB"是匹配的。查表可知,最后一个匹配字符B对应的"部分匹配值"为2,因此按照

下面的公式算出向后移动的位数:

移动位数 = 已匹配的字符数 - 对应的部分匹配值

6 - 2 = 4;所以移动 4 个字符。

10.

技术分享

移动后就来到了这里,空格与字符‘C’不匹配,再次利用《部分匹配表》查询移动位数。2 - 0 = 2;因此移动2个字符。

11.

技术分享

再次移动后来到了这里,空格与字符‘A’不匹配,再次利用《部分匹配表》查询移动位数。1 - 0 = 1;因此移动1个字符。

12.

技术分享

一一对比完后到了D字符,发现文本串的字符‘C’与目标串字符‘D’不匹配,查询移动位数。6 - 2 = 4;因此移动4个字符。

13.

技术分享

移动后就来到这了,一一比较完后发现全部匹配。目标串匹配成功!

14.

关于《部分匹配表》

技术分享

下面介绍《部分匹配表》是如何产生的。
首先,要了解两个概念:"前缀"和"后缀"。 

"前缀"指除了最后一个字符以外,一个字符串的全部头部组合;

"后缀"指除了第一个字符以外,一个字符串的全部尾部组合。如上图所示。

15.

技术分享

"部分匹配值"就是"前缀"和"后缀"的最长的共有元素的长度。以"ABCDABD"为例,

技术分享

16.

技术分享

"部分匹配"的实质是,有时候,字符串头部和尾部会有重复。比如,"ABCDAB"之中有两个"AB",那么它的"部分匹配值"就是2("AB"的长度)。

搜索词移动的时候,第一个"AB"向后移动4位(字符串长度-部分匹配值),就可以来到第二个"AB"的位置。

分析了这么详细,正如那句话,Talk is cheap, show me the code.来写一写代码吧!

代码实现:

暴力算法:

void
SViolence( const char strText[ ], const char strSearch[ ] )
{
    int lengthOfstrText, lengthOfstrSearch;
    int i, j, ii;

    lengthOfstrText = strlen( strText );
    lengthOfstrSearch = strlen( strSearch );

    /*for( i = 0, j = 0, ii = 0; i < lengthOfstrText && j < lengthOfstrSearch; )*/
    for( i = 0, j = 0, ii = 0; j < lengthOfstrSearch; )
    {
        if( strText[ i ] == strSearch[ j ] )
        {
            j++;
            i++;
            continue;

        }
        else
        {
            i = ii;
            i++;
            ii = i;
            j = 0;/* make a clear */
            continue;
        }
    }

    if( j == lengthOfstrSearch )
        printf( "Existence!" );
    else
        printf( "No Existence!" );
}

在程序中的ii变量就是记录位置的。理解这个算法的运行过程可以很清楚的知道在算法中做了很多重复的比较工作。

时间复杂度分析:咋一看这个程序感觉很(hen)快(man)啊,只有一个for循环而已嘛。呵呵,其实你有所不知,这个for循环与众不同,它的结束不只是依赖于for循环条件而已,而是有循环条件和循环体的i,j,ii,等变量共同决定的。我们记lengthOfText = m,lengthOfSearch = n;所以这个算法的时间复杂度大概为:T( n )= O( m * n )这个级别已经是我们所唾弃的了。

KMP算法:


字符串匹配暴力算法 与 字符串匹配的KMP算法

标签:算法   kmp   字符串匹配   

原文地址:http://blog.csdn.net/oimchuan/article/details/44836541

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!