Kmp字符串匹配算法

上一篇文章,已经讲过了Horspool匹配算法,确实Horspool是一种优秀的算法,它实现了θ(n)的一般效率对文本串的查找,但也有一种算法——Kmp,它也能实现这种效率


先看一下该算法执行的移动过程(即模式串的next数组的值)

先声说明:本人认为该算法在移动值的求法比Horspool不好理解,对于初次接触的人理解会有点难度,不过给予点耐心,还是可以看得懂的

另外下面的 i ,j 变量在下面的函数shiftTable中,请结合理解

未改进:

下标01234567
模式串abaabcac
next-10011201

归纳:

其实next的求法就是:1)如果匹配跳动变量j在下表为0时,遍历变量i和匹配跳动变量j都+1,且next[i] = j;

                                    2)匹配跳动变量j 和遍历变量 i 变量所对应字符一样,便利变量i和匹配跳动变量j都+1,且next[i] = j;

                                    3)以上两种情况不满足,则j = next[j],继续和遍历变量i比较


改进:

下标01234567
模式串abaabcac
next-10-1102-11
       

归纳:其实改进后的算法和为改进相差不是很多,不过时间效率就提高了,就是在第2种情况下,加上:如果遍历变量i和匹配跳动变量j在+1之后在比较,如果两者 = ,那说明i位置不符合时,j位置也不符合,所以只能next[i] = next[j],如下标为2的a next值是-1


先看一下,未改进的shiftTable函数

//求模式串的next数组
	public int[] shiftTable(char[] m)
	{
		int[] next = new int[m.length];
	        int mLen = m.length;
		//第一个字符next值
		next[0] = -1;
		
		//j在遍历比较过程中会跳动
		int j = -1;
		
		//i为遍历模式串的变量
		for(int i=0; i<mLen-1;)
			if(j == -1 || m[i] == m[j])
			{
				i++;
				j++;
				
				next[i] = j;
			}
			else j = next[j];
		
		return next;
	}



改进后的shiftTable函数

/**
	 * 求模式串的next数组
	 * @param m
	 *            模式串
	 * @return
	 */
	public static int[] shiftTable(char[] m)
	{
		int mLen = m.length;
		int[] next = new int[mLen];

		// 第一个字符next值
		next[0] = -1;

		// j在遍历比较过程中会跳动
		int j = -1;

		// i为遍历模式串的变量
		for (int i = 0; i < mLen - 1;)
			if (j == -1 || m[i] == m[j])
			{
				i++;
				j++;

				if (m[i] == m[j])
					next[i] = next[j];
				else
					next[i] = j;
			}
			else
				j = next[j];

		return next;
	}


在看一下匹配函数

/**
	 * 匹配函数,其中p为模式串,m为模式串长度,t为文本串,n为文本串长度,next为next数组
	 * 
	 * @param m
	 *            模式串
	 * @param t
	 *            文本串
	 * @return
	 */
	public static int kmp(char[] m, char[] t)
	{
		int[] next = shiftTable(m);
		int mLen = m.length;
		int tLen = t.length;

		// 遍历文本串n的变量
		int i = 0;

		// 表示模式串将验证位置的变量
		int j = 0;

		while (i < tLen && j < mLen)
		{
			// 如果匹配或者j为-1,匹配下一个字符
			if (j == -1 || t[i] == m[j])
			{
				i++;
				j++;
			}
			else
			{
				j = next[j];
			}
		}

		if (j == mLen)
			return i - j;
		else
			return -1;

	}


验证:


// args[0]为模式串,args[1]为文本串
	public static void main(String args[])
	{

		System.out.println(kmp("abaabcac".toCharArray(),
				"asdfaddsdabaabcacsdws".toCharArray()));
	}


输入:

args[0]: abaabcac

args[a]: asdfaddsdabaabcacsdws


输出: 9




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值