一步一步写算法(之字符串查找 中篇)

原文:一步一步写算法(之字符串查找 中篇)

【 声明:版权所有,欢迎转载,请勿用于商业用途。  联系信箱:feixiaoxing @163.com】

昨天我们编写了简单的字符查找函数。虽然比较简单,但是也算能用。然而,经过我们仔细分析研究一下,这么一个简单的函数还是有改进的空间的。在什么地方改进呢?大家可以慢慢往下看。

下面的代码是优化前的代码,现在再贴一次,这样分析起来也方便些:

char* strstr(const char* str, char* data)
{
	int index;
	int len;

	if(NULL == str || NULL == str)
		return NULL;

	len = strlen(data);
	while(*str && (int)strlen(str) >= len){
		for(index = 0; index < len; index ++){
			if(str[index] != data[index])
				break;
		}

		if(index == len)
			return (char*) str;

		str++;
	}

	return NULL;
}

不知道朋友们发现没有,原来的while条件中有一个很费时的操作。那就是每次str移动的时候,都需要判断str的长度大小。如果str的长度远大于data的长度,那么计算str长度的时间是相当可观的。

int check_length_of_str(const char* str, int len)
{
	int index;

	for(index = 0; index < len; index ++){
		if(‘\0‘ == str[index])
			return 0;
	}

	return 1;
}

char* strstr(const char* str, char* data)
{
	int index;
	int len;

	if(NULL == str || NULL == str)
		return NULL;

	len = strlen(data);
	while(*str && check_length_of_str(str, len)){
		for(index = 0; index < len; index ++){
			if(str[index] != data[index])
				break;
		}

		if(index == len)
			return (char*) str;

		str++;
	}

	return NULL;
}

上面的代码很好地解决了长度判断的问题,这样一来每次比较的长度很短,只要判断len的大小字符长度即可。但是,我们还不是很满足,如果两者不比较岂不更好。那么,有没有这个可能?我们发现,如果str在每次比较不成功的时候,就会自己递增一位。那么我们只要判断这一位是不是‘\0’不就可以了吗?所以说,我们的代码还可以写成下面的形式。

char* strstr(const char* str, char* data)
{
	int index;
	int len;

	if(NULL == str || NULL == str)
		return NULL;

	len = strlen(data);
	if((int)strlen(str) < len)
		return NULL;

	while(*str){
		for(index = 0; index < len; index ++){
			if(str[index] != data[index])
				break;
		}

		if(index == len)
			return (char*) str;

		if(‘\0‘ == str[len])
			break;

		str++;
	}

	return NULL;
}

和上面第一次的优化不同,我们在进入while之前会判断两者的长度区别,但是经过第一次判断之后,我们就再也不用判断了,因为接下来我们只要判第n个元素是否为‘\0’即可,原来的n-1个元素我们已经判断过了,肯定是合法的元素。为什么呢?大家可以好好想想。

(二)、KMP算法

KMP算法本质上说是为了消除查找中的多余查找步骤。怎么就产生了多余的查找步骤了呢。我们可以用示例说话。假设有下面两个字符串:

A:  baaaaabcd

B:  aaaab

那么这两个查找的时候会发生什么现象呢?我们可以看一下:

/*      1 2 3 4 5 6 7 8 9
*    A: b a a a a a b c d
*    B:   a a a a b
*       1 2 3 4 5 6 7 8 9
*/  

我们发现B和A在从第2个元素开始比较的时候,发现最后一个元素是不同的,A的第6个元素是a,而B的第5个元素是b。按照普通字符串查找的算法,那么下面A会继续向右移动一位,但是事实上2-5的字符我们都已经比较过了,而且2-5这4个元素正好和B的前4个元素对应。这个时候B应该用最后一位元素和A的第7位元素比较即可。如果这个计算步骤能省下,查找的速度不就能提高了吗?

【预告: 下面一篇博客介绍KMP的编写和多核查找算法】

时间: 2024-10-25 14:31:26

一步一步写算法(之字符串查找 中篇)的相关文章

一步一步写算法(之查找)

原文:一步一步写算法(之查找) [ 声明:版权所有,欢迎转载,请勿用于商业用途.  联系信箱:feixiaoxing @163.com] 无论是数据库,还是普通的ERP系统,查找功能数据处理的一个基本功能.数据查找并不复杂,但是如何实现数据又快又好地查找呢?前人在实践中积累的一些方法,值得我们好好学些一下.我们假定查找的数据唯一存在,数组中没有重复的数据存在. (1) 普通的数据查找 设想有一个1M的数据,我们如何在里面找到我们想要的那个数据.此时数据本身没有特征,所以我们需要的那个数据可能出现

常用算法3 - 字符串查找/模式匹配算法(BF &amp; KMP算法)

相信我们都有在linux下查找文本内容的经历,比如当我们使用vim查找文本文件中的某个字或者某段话时,Linux很快做出反应并给出相应结果,特别方便快捷! 那么,我们有木有想过linux是如何在浩如烟海的文本中正确匹配到我们所需要的字符串呢?这就牵扯到了模式匹配算法! 1. 模式匹配 什么是模式匹配呢? 模式匹配,即子串P(模式串)在主串T(目标串)中的定位运算,也称串匹配 假设我们有两个字符串:T(Target, 目标串)和P(Pattern, 模式串):在目标串T中查找模式串T的定位过程,称

一步一步写算法(之字符串查找 上篇)

原文:一步一步写算法(之字符串查找 上篇) [ 声明:版权所有,欢迎转载,请勿用于商业用途.  联系信箱:feixiaoxing @163.com] 字符串运算是我们开发软件的基本功,其中比较常用的功能有字符串长度的求解.字符串的比较.字符串的拷贝.字符串的upper等等.另外一个经常使用但是却被我们忽视的功能就是字符串的查找.word里面有字符串查找.notepad里面有字符串查找.winxp里面也有系统自带的字符串的查找,所以编写属于自己的字符串查找一方面可以提高自己的自信心,另外一方面在某

一步一步写算法(之字符串查找 下篇)

原文:一步一步写算法(之字符串查找 下篇) [ 声明:版权所有,欢迎转载,请勿用于商业用途.  联系信箱:feixiaoxing @163.com] 前面我们谈到了KMP算法,但是讲的还不是很详细.今天我们可以把这个问题讲的稍微详细一点.假设在字符串A中寻找字符串B,其中字符串B的长度为n,字符串A的长度远大于n,在此我们先忽略. 假设现在开始在字符串A中查找,并且假设双方在第p个字符的时候发现查找出错了,也就是下面的情况: /* * A: A1 A2 A3 A4 ... Ap ........

一步一步写算法(之单词统计)

原文:一步一步写算法(之单词统计) [ 声明:版权所有,欢迎转载,请勿用于商业用途.  联系信箱:feixiaoxing @163.com] 在面试环节中,有一道题目也是考官们中意的一道题目:如果统计一段由字符和和空格组成的字符串中有多少个单词? 其实,之所以问这个题目,考官的目的就是想了解一下你对状态机了解多少. (1) 题目分析 从题目上看,如果对一个字符串进行处理,那么可以有下面几种情形:初始状态,字符状态,空格状态,结束状态.那么这几种状态之间应该怎么迁移呢? 初始状态: 如果输入符号是

一步一步写算法(之爬楼梯)

原文:一步一步写算法(之爬楼梯) [ 声明:版权所有,欢迎转载,请勿用于商业用途.  联系信箱:feixiaoxing @163.com] 前两天上网的时候看到一个特别有意思的题目,在这里和朋友们分享一下: 有一个人准备开始爬楼梯,假设楼梯有n个,这个人只允许一次爬一个楼梯或者一次爬两个楼梯,请问有多少种爬法? 在揭晓答案之前,朋友们可以自己先考虑一下: 这个人爬n层楼梯,那么它也不是一下子就可以爬这么高的,他只有两个选择,要么从n-2层爬过来,要么从n-1层爬过来.除此之外,他没有别的选择.此

一步一步写算法(之 算法总结)

原文:一步一步写算法(之 算法总结) [ 声明:版权所有,欢迎转载,请勿用于商业用途.  联系信箱:feixiaoxing @163.com] 自10月初编写算法系列的博客以来,陆陆续续以来写了几十篇.按照计划,还有三个部分的内容没有介绍,主要是(Dijkstra算法.二叉平衡树.红黑树).这部分会在后面的博客补充完整.这里主要是做一个总结,有兴趣的朋友可以好好看看,欢迎大家提出宝贵意见. (1) 排序算法 快速排序 合并排序 堆排序 选择排序 基数排序 冒泡排序 插入排序 希尔排序 链表排序

一步一步写算法(之 回数)

原文:一步一步写算法(之 回数) [ 声明:版权所有,欢迎转载,请勿用于商业用途.  联系信箱:feixiaoxing @163.com] 回数的概念比较好玩,就是说有这么一个字符串str, 长度为n, 现在index开始从0->index/2遍历,那么str[index] = str[n-1-index],那么这种数据就是我们通常说的回数.比如说a = "a"是回数, a = "aba"是回数, a = "strarts"也是回数.因为这

一步一步写算法(之 可变参数)

原文:一步一步写算法(之 可变参数) [ 声明:版权所有,欢迎转载,请勿用于商业用途.  联系信箱:feixiaoxing @163.com] 可变参数是C语言编程的一个特色.在我们一般编程中,函数的参数个数都是确定的,事先定下来的.然而就有那么一部分函数,它的个数是不确定的,长度也不一定,这中间有什么秘密吗? 其实,我们可以回忆一下哪些函数是可变参数的函数?其实也就是sprintf.printf这样的函数而已.那么这些函数有什么规律吗?关键就是在这个字符串上面.我们可以举一个例子看看, voi