我的KMP算法

以前老师讲数据结构的时候,我还年轻,不知道这东西跟背课文似的有什么用。考试都是抄过去的,幸亏老师不是很负责,马马虎虎就让大家都过关了。

我不知道是否庆幸没挂,还是该怪老师的不负责任。我还记得我是多么恨给我挂了一科的那个老师,不过如果是重要科目,挂了,却是应该的,因为这样我们就会去认真复习了。于是重要的知识渴望被我学习的愿望得以实现,为学习更重要的知识做好了铺垫。尽管如此,年少的大家仍不免对该老师有偏见,不过,他大可问心无愧地说出那句不会说这句话的老师一定不是好老师的话:以后你们就明白了。

是的,老师也有说的对的时候,只是明白的有些晚了。

数据结构这本书很薄,但我看了一个多月,才到第4章。可见我对这本书及这门课的忌惮和恐惧。是的,我的思维惯性特别大,以前不喜欢看的东西,现在也很难看下去,当然,智商上的差距我是不愿提及的。

本来是想不求甚解的随便看下就完了,可是第四章卡到了KMP算法上了,假如没有看这本书,只看这个名字“KMP”,打死我也想不到这是3个人名字的缩写,只能说外国人的思维果然犀利,中国人很少会这么干,他们一般喜欢用诗词地名或者物品什么的给东西命名,比如:黄鹤楼,岳阳楼,真维斯楼,明远楼,修远楼等等,逸夫图书馆什么的我是没有见过的。

仿照书上的例子,写了如下程序,希望以后还能看到:

//获取模式串的next数组
//数组长度跟匹配串的长度相同,不算\0的话。
//它的值表示,跟主串匹配时,第i个字符失配了,那么j回溯到的位置。
void get_kmp_offset(const char * s, int *next){
	int l = strlen(s) - 1;//去掉\0
	int i = 1;
	int j = 0;
	next[0] = 0;
     if(l == 1)
        return;
	next[1] = 0;
     if(l == 2)
        return;
	while (i <= l - 1){
         //这个算法就是把s抽象成2个相同的串,一个作为主串,下标用i,一个是匹配串,下标用j。
         //这里加 j==0 是因为else里面i没变,万一j本来就是0, 然后next[j]也是0就死循环了。
         //它表示回溯到0了。此时若s[0]和s[i]的值相等的话,next[i+1]就等于1了。
         //走到else就意味着失配,失配就要回溯,KMP不让i回溯,所以只能j回溯。
         //此时,next[i]已经求出来了。我们求的是next[i+1]
         //此时失配时,
         //1.假设i-1没有失配, 那么next[i] 的值就是j,m大于0。
         //(i-1时的没有失配已经决定了next[i]的值了)
         //那就表示:'P0P1...Pj-1' == 'Pi-j-1Pi-j-2...Pi-1'
         //但是现在s[j]和s[i]不相等了。
         //回溯!
         //j为什么要回溯到next[j]呢?
         //next[j]的值表示什么?假如next[j]为k,那就意味着 'P0P1...Pk-1' == 'Pj-k+2Pj-k+3...Pj-1'
         //上面两个式子合并我们发现,下面的式子是上面式子的左值的一部分。
         //通过简单的数学比较,我们就知道如果Pk的值同Pi的值相等,那么我们就得到一个新的等式:
         //'P0P1...Pk-1' + 'Pk' ==  'Pi-k+2Pi-k+3...Pi-1' + 'Pi'
         //这意味着next[i+1] = k+1也就是next[j]也就是else中的赋值j = next[j]
         //2.假设i-1也是失配的,next[i]就是0.否则回溯到next[j](不为0的话),那就不叫失配了。因此next[i+1]也是0.
		if(j == 0 || s[i] == s[j]){			
              if(s[i] == s[j])
				j++;
			i++;
			if(s[i] == s[i-1])
				next[i] = next[j];
			else
				next[i] = j;
		}else{
			j = next[j];
		}
	}
}
int index(const char *src, const char * sub, int begin, bool isKMP){
	if(begin > length || begin < 0)
		return -1;
	int j = 0;
	int i;
	int *next;
	int length = strlen(src);
	int sub_len = strlen(sub);
	if(isKMP){
		next = new int[length];
		get_kmp_offset(sub, next);
	}
	for(i = begin; i < length && j < sub_len;){
		const char a1 = *(src + i);
		const char a2 = *(sub + j);
		if(j == 0 || a1 == a2) {
			i++; 
			if(a1 == a2)
				j++;
		} else {
			if(!isKMP){//一般匹配方法
				i = i - j + 1;//失配之后i回溯到上次失配时的位置+2
				j = 0;//j回溯到0。
			}else{//kmp
				j = next[j];//从kmp模式串数组中获得回溯值。
			}
		}
	}
	if(isKMP)
		delete []next;
	if(j >= sub_len)//匹配成功
		return i - j;//返回首字符下标
	else
		return -1;
}

可能有错误,但我已经查不出来了,以后功力深点了再看吧。

好多人说基础要打牢,但是我总分不清什么才是基础。我都是拿到书就看,看完了就扔,才不管啥是基础呢。这样特别不好,还是希望有先闻道的前辈指点一二,不说要达到什么成就,但是谁都希望自己越来越好,谁能告诉我应该学会什么知识呢?或者学什么书呢?

希望已经在路上的朋友,能帮仍在起点徘徊的人指点一下。谢谢


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值