看数据结构写代码(18) KMP算法

求 子串 的 位置 有两种方法,一种是暴力搜索法,另一种就是KMP 算法。他们的效率 在一般的情况下,区别不大。但是在 串的 变化 范围特别小的情况下,例如 只有 0 和 1,KMP 的时间复杂度是 O(m+n),而暴力搜索法定时间 复杂度 是 O(m*n),(m,n分别指 子串 和 母串的 长度)

下面给出两种算法的代码

欢迎指出代码不足

// Kmp2.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include <stdlib.h>
#include <string.h>

//暴力模式匹配(求子串位置)
int stringIndex(char * string,char * sub,int pos){
	char * p = string;
	int lenString = strlen(string);
	int lenSub = strlen(sub);
	int matchTimes = 0;
	for (int i = pos -1; i <= lenString - lenSub; i++)
	{
		int temp = i;
		for (int j = 0; j < lenSub;)
		{
			matchTimes++;
			if (string[temp] == sub[j])
			{
				temp++,j++;
				if (j == lenSub)
				{
					printf("暴力匹配算法,执行次数: %d\n",matchTimes);
					return i+1;
				}
			}
			else
			{
				break;
			}
		}
	}
	printf("暴力匹配算法,执行次数: %d\n",matchTimes);
	return 0;
}

//KMP 模式匹配法..
void getNext(char * sub,int * nextArray);
static int kmpTimes = 0;
int kmpIndex(char * string,char * sub,int pos){
	int stringLen = strlen(string);
	int subLen = strlen(sub);
	int i=pos-1,j=0;
	kmpTimes = 0;
	int * nextArray = (int *)malloc(sizeof(int) * subLen);
	getNext(sub,nextArray);
	while (i < stringLen - subLen + 1 && j < subLen)
	{
		kmpTimes++;
		if (j == -1 || string[i] == sub[j]  )
		{
			i++,j++;
		}
		else
		{
			j = nextArray[j];
		}
	}
	free(nextArray);
	printf("KMP匹配算法,执行次数(包括getNext函数匹配次数): %d\n",kmpTimes);
	return j == subLen ?  i-subLen+1: 0;
}

void getNext(char * sub,int * nextArray){
	int subLen = strlen(sub);
	nextArray[0] = -1;
	for (int i = 0,j = -1; i < subLen -1;)
	{
		kmpTimes++;
		if (j == -1 || sub[i] == sub[j])
		{
			i ++ ,j ++;
			if (sub[i] != sub[j])
			{
				nextArray[i] = j;
			}
			else
			{
				nextArray[i] = nextArray[j];
			}
		}
		else
		{
			j = nextArray[j];
		}
	}
}

//打印 信息
void printMsg(char * string,int index,int kmp){
	char * point = string + index - 1;
	char * kmpPoint = string + kmp - 1;
	printf("暴力模式匹配 字符串为:%s\n,KMP模式匹配算法字符串为:%s\n",point,kmpPoint,kmp);
}

int _tmain(int argc, _TCHAR* argv[])
{
	char * string = "abcdefghijklmnsdfdsdfsfdsd";
	char * sub = "sdfd";
	int index = stringIndex(string,sub,1);
	int kmp = kmpIndex(string,sub,1);
	printMsg(string,index,kmp);
	string = "00000000000000000000000000000000000111111111111111111100";
	sub = "000000000001111";
	index = stringIndex(string,sub,1);
	kmp = kmpIndex(string,sub,1);
	printMsg(string,index,kmp);
	return 0;
}

时间: 2024-08-26 18:58:51

看数据结构写代码(18) KMP算法的相关文章

看数据结构写代码(32) 赫夫曼树编码以及译码

杂谈:最近有点慵懒,不好不好.好几天都没写代码,原本准备上星期完结 树 这一章节的.现在 又耽误了.哎.要抓紧时间啊. 下面直接上代码: 可以到我的网盘下载源代码,或者 直接拷贝下面的源代码 运行 网盘地址:点击打开链接 // HuffmanTree.cpp : 定义控制台应用程序的入口点. //哈弗曼编码,译码 #include "stdafx.h" #include <stdlib.h> #include <cstring> enum E_State { E

看数据结构写代码(47)迪杰斯特拉最短路径算法

这个算法的 思想 根 求 最小生成树算法 普里姆(Prim)算法 极其相似.迪杰斯算法 是求 一个顶点 到其他 顶点的 最短路径算法. 下面 上代码:(用的是 邻接矩阵 表示法) //迪杰斯特拉 最短路径. //从 vex顶点 到其他 顶点的 最短路径 void shortestPath_Dij(MGraph g,char vex){ int loc = graphLocation(g,vex); int minArray[MAX_VERTEX_NUM]={0};//最小路径值 bool fin

看数据结构写代码(67) 置换 _ 选择排序(完结篇)

杂谈: 严蔚敏版<数据结构(C语言版)> 一书 终于看完了.这是 一个完结,也是 一个新的开端.<算法导论> 已到手. 置换选择排序的思想 是 将 归并段 尽量 变的 更大,而不是根据 内存 大小 限制在 固定的 大小. 这样 可以 利用赫夫曼树 来 进行 最优归并树,从而 使 外存 读写次数 最少. 下面给出 具体 代码:欢迎指出代码不足. // Replace_Selcetion.cpp : 定义控制台应用程序的入口点. // #include "stdafx.h&q

看数据结构写代码(44) 判断无向图是否有环路

在 看 严蔚敏的 数据结构 一书 7.5小节时,书上 说" 判断有向图是否存在环要不无向图复杂.对于无向图来说,深度优先遍历过程中遇到回边(即指向已访问过的顶点的边),则必定存在环路". 看的不明白,所以 网上 百度了一下. 有了思路:故写下算法 和思路,以便以后 温故. 思路: 1.一个n个顶点,e条边的 无向图,若 e>= n,必有环路. 2.若 e < n ,需要 深度 遍历,并把 父节点传入 参数中,如果 遇到 一个 节点 被访问过 并且 不是 父节点,那么 就有环

看数据结构写代码(50)伙伴系统

伙伴系统 是一种 只 可以 分配 2的 幂次方 个 空间的 ,回收 内存 时 只 合并 "伙伴空间" 的一种 动态内存管理方式. 例如 一个 空间 大小 为 64 的 内存,伙伴 系统 为 这 64 的内存  建立 一组 双向循环 链表,分别 管理着  2的 0 次方,2的1 次方幂,2的 2 次方幂...2的6次方幂的 可用空间. 即使 我们 只想分配 一个 大小 为3的 空间,系统 却 只能 返回 一个 内存 大小 为 4(2的2次方)的 一个空间. 系统 在 初始化的 时候 ,并

看数据结构写代码(43) 关节点

首先 说明一下 概念问题: 关节点 :如果删除无向 图中的一个顶点,以及与顶点相关的边,把 图的 一个连通 分量 变成 两个 以上的 连通 分量.这样的顶点叫做关节点. 没有 关节点的 无向图,叫做 重连通图.重连通图中 任意 两个顶点 至少 存在 两条以上的 通路. 如果 删除 连通图上的 k个 节点,才能 破坏 他的连通性,那么 这个连通图的 连通度 为k. 下面的算法 是 求 连通图的 关节点,并没有 考虑 求图的 关节点,不过 要 改成 图的 关节点 也不难,只要 加 一个 for i

看数据结构写代码(40) 无向图的深度优先生成树与广度优先生成树

图的深度优先遍历 和 广度 优先 遍历 算法中的 每一次 最外层 循环 都 产生 一个 无向图 的 连通分量,每一个连通分量,都可以产生一个生成树,将这些生成树合在 一起 就是 一个 森林. 用 树的 孩子 兄弟 链表 表示法 来 表示 这个 森林, 就是 这一节 算法的  内容. 深度优先森林 代码 : //深度优先生成森林 void dfsTree(AMLGraph g,int i,Tree * t,bool isVisited[]){ isVisited[i] = true; bool i

看数据结构写代码(66) 败者树

计算机的 内存 是 有限的,无法 存入 庞大的数据.当 遇到 大数据需要排序时,我们 需要 将 这些 数据 分段 从 硬盘里 读到 内存中,排好序,再 写入到 硬盘中,这些段 叫做 归并段.最后将 这些 分段 合并 成 一个 最终  完整 有序的 数据. 这里 操作的 时间 =  内部 排序 时间 +  外存读写时间 + 内部归并所需时间. 其中 外存 读写时间 最耗时,外存读写时间 = 读写次数 * 读写数据的时间 ,读写 数据的时间 因 设备 性能 而 影响,我们 无法控制,我们 只能 控制

看数据结构写代码(4)单链表

单链表比较简单,中间倒也没出什么大问题,只是 在写 插入 和 删除的 算法的 时候 ,时间复杂度 是正常 算法的2倍.后来 改正了. 下面奉上代码.如有 bug,欢迎指出. // SingleList.cpp : 定义控制台应用程序的入口点. // #include "stdafx.h" #include <cstdlib> enum E_State { E_State_Error = 0, E_State_OK = 1, }; typedef int ElementTyp