`

js 字符串搜索算法

 
阅读更多

基本搜索:

 

function search(source, subject){  
	var srcLen = source.length;  
	var subLen = subject.length;  
			  
	for(var i=0; i<srcLen-subLen; i++){  
		var k = i;  
		for(var j=0; j<subLen; j++,k++){  
			if(source.charAt(k)!=subject.charAt(j))  
				break;  
			if(j == subLen-1)  
				return i;  
		}  
	}  
	return -1;  
}
 

kmp快速搜索:

 

KMP的优势就是没有回溯,这对于只能够使用一个指针进行搜索的情况下,不仅仅有效率上的优势,实现起来也更自然。当然对于数组来说,使用俩指针并没有什么不便,如果是对于文件或者输入流进行搜索,那回溯起来就会很麻烦了。下面是KMP搜索。

KMP算法的核心就是不回溯原字符串指针,这点其实不难做到,重要的是要想到这一点——对于回溯的字符,其实都是已知的。解释一下就是,比如在"abcdefg"中搜索"abcdeg",前五个字符"abcde"都是匹配的,第六个字符f和g不匹配,这时候,对于上面的搜索算法,i将会+1,整个匹配重新开始一次,这就是回溯了。但是仔细想一下,回溯其实完全可以避免的,因为如果知道是在第六个字符不匹配,那就说明前五个字符都是匹配的,从而说明"知道回溯之后的字符是什么",对于这个例子来说,我们肯定知道源字符串前面五个字符是"abcde"。这是KMP搜索的根基。

好,下面让我们抛开源字符串吧!我们只关心目标字符串,也就是"abcdeg"。下面我们来设想,如果在搜索中发现源字符串的【n】字符和目标字符串的【m】字符匹配失败,那说明什么呢?说明之前的字符都是匹配的,否则也不会走到这里。也就是源字符串的【n-m】到【n-1】这m个字符与目标字符串的【0】到【m-1】这m个字符匹配。既然已经在搜索之前知道这个相等关系,那何苦在搜索的时候一次又一次的回溯呢?这个本来就是可以预测的,是搞一次就得的事情。因为源字符串的【n-m】到【n-1】是已知的。所以不用每次都死板的回溯到源字符串的n-m+1。

举例来说,对于在"abababc"中搜索"ababc",第一次不匹配的情况如下

1 0 1 2 3 4 5 6
2 a b a b a b c
3 a b a b c
4         ^

这时候,如果把指针回溯到源字符串的1位置,其实没有意义的,因为它是b,和目标字符串的a不匹配。而且,我们其实已经知道源字符串0到3这四个字符的值是跟目标字符串的四个字符一样的,都是abab。KMP的思想就是,充分利用这个已知条件,"源字符串不回溯,尽量让目标字符串少回溯,然后继续进行搜索"。那应该让目标字符串回溯到什么地方呢?这就看已经匹配的字符串的内容了。

使用S代表源字符串,T代表目标字符串,S[n]和T[m]失配(注意,因为失配了,这时候S[n]是什么是不知道的)。对于源字符串已知的只有S[n-m+1]到S[n-1]这m-1个字符。假设能够找到这样一个k,使得S[n-k]...S[n-1]=T[0]....T[k-1] (0<k<m),那么就只需要保持S不回溯,让T回溯到K,然后继续匹配就好了。而如果能够找到一个最大的K值,那么效率则是最高的。

对于上面的例子,k的值是2,KMP搜索的下一个状态是:

1 0 1 2 3 4 5 6
2 a b a b a b c
3     a b a b c
4         ^

然后继续匹配就成功啦。

所以,KMP算法的核心是,如何为目标字符串的每个位置的找到一个k值,组成一个数组F,好在每次匹配到目标字符串的m失配的时候,将目标字符串回溯到F[m],然后继续进行匹配。找到这个数组之后,KMP搜索就算是完成80%了。

下面是构建这个数组F的方法。

这时候目标字符串身兼源字符串和目标字符串两个角色。构建数组T可以说是一个步进的过程,需要用到之前的结果。首先是F[0],F[0]的意思是第一个字符就不匹配,也就是说对源字符串一无所知,这时候没得搞了,直接要源字符串向前挪动一个。在F里,我们使用-1来标记第一个字符就匹配失败的情况。也就是F[0]=-1。F[1]其实肯定是0。我们真正需要计算的是从F[2]到最后的。下面是>=2的时候的计算方法。注意,F[i]代表S的第i个字符匹配"失败"的时候,T需要回溯到的索引的值。如何求F[i]的值呢?首先取得F[i-1]的值,然后看S[i-1]是否=T[F[i-1]],如果等于,那么F[i]=F[i-1]+1。这个原理是递归的。F[i-1]的值是在i-1失配的时候,T索引回溯到的值,如果这时候,这个值与S[i-1]相等,那就说明F[i]可以在F[i-1]的基础上增加1了。否则继续检查S[i-1]是否等于T[[F[i-1]]],直到没有的搜索了,就是0。

代码如下:

 

 

function kmpSearch(source, subject){  
	var srcLen = source.length;  
	var subLen = subject.length;  
	var pattern = [];  
	prefix(subject, pattern);  
			  
	for(var index=0,p=0; index<srcLen; index++){  
		if(source.charAt(index) == subject.charAt(p)){  
			p++;  
			if(p == subLen)  
				return index - subLen + 1;  
		}else{  
			p = pattern[p];  
		}     
	}     
	return -1;  
}  
		
function prefix(subject,pattern){  
	var subLen = subject.length;  
	pattern[0] = 0;  
	for(var i=1,k=0; i<subLen; i++){  
		while ((subject.charAt(i) != subject.charAt(k)) && k > 0){  
			k = pattern[k];               
		}         
		if(subject.charAt(i) == subject.charAt(k)){  
			k++;  
		}  
		pattern[i] = k;  
	}  
}
分享到:
评论
1 楼 anlaetion 2012-04-05  

这算法可以有

相关推荐

    js中对字符串加密解密算法

    js中对字符串加密解密算法

    js版字符串快速检索

    "js版字符串快速检索"这个主题聚焦于如何高效地在JavaScript环境中查找字符串中的特定子串。以下是一些相关的知识点,涵盖了基础概念、常见方法以及优化策略。 1. **字符串基本操作**:在JavaScript中,字符串是不...

    JavaScript字符串查找1

    本文主要关注的是最基础的字符串查找算法——朴素搜索法。这是一种简单直观的方法,但效率较低,适用于小规模的数据处理。 **一、字符串查找的基本概念** 字符串查找,或者称为字符串搜索或字符串匹配,其目标是在...

    字符串排序方法

    在深入探讨排序算法之前,我们先了解一些关于JavaScript字符串和数组的基本知识。 #### 1. 字符串和数组 - **字符串**:在JavaScript中,字符串是一种原始数据类型,用于表示文本。 - **数组**:数组是一种对象...

    Ukkonen的近似字符串匹配算法

    Esko Ukkonen提出的近似字符串匹配算法是一种高效的文本处理方法,主要用于在大规模文本数据中查找与给定模式字符串相似的子串。这种算法基于动态规划思想,它允许在一定程度上的错误匹配,比如单个字符的插入、删除...

    用 Levenshtein 距离算法最快的 JS 实现来测量两个字符串之间的差异_JavaScript_代码_相关文件_下载

    在"用Levenshtein距离算法最快的JS实现来测量两个字符串之间的差异"这个主题中,我们关注的是如何高效地在JavaScript中执行这个算法。通常,Levenshtein距离的计算会涉及到二维数组的填充,这可能导致性能问题,尤其...

    work2_分割字符串_字符串处理_

    无论是进行数据解析、日志分析,还是构建复杂的文本处理算法,有效的字符串操作都能极大地提高代码的效率和可读性。因此,花时间学习和实践这些基本技能是每个程序员职业生涯中不可或缺的一部分。

    JavaScript截取中文字符串

    ### JavaScript截取中文字符串知识点详解 #### 一、引言 在进行文本处理时,我们经常需要对字符串进行截取操作。特别是在处理包含多种字符集(如英文与中文)的字符串时,考虑到不同字符编码长度的差异性,简单地...

    字符串转ASCII ASCII转字符串

    总结,字符串转ASCII和ASCII转字符串是编程中常见的操作,主要涉及对字符和其对应的数字表示之间的转换。理解这些概念和实现方式对于理解和处理字符数据至关重要。通过学习不同编程语言中的相关函数和方法,你可以...

    字符串遗传算法-excited-JS-plus1S.zippython

    python字符串遗传算法_excited_JS_plus1S.zip

    基于模糊字符串搜索 过滤列表_JavaScript

    **基于模糊字符串搜索过滤列表_JavaScript** 模糊字符串搜索是一种高效、灵活的文本搜索方法,它允许用户在不完全记住确切关键词的情况下查找相关信息。在JavaScript中实现模糊搜索可以帮助开发者为用户提供更加...

    JS数据结构与算法.pdf

    在本书中,我们还讨论了 JavaScript 的基础知识,包括变量和数据类型、运算符和控制结构、函数和对象、数组和字符串等。此外,我们还讨论了数据结构,包括数组、栈、队列、链表、集合、字典、散列表、树、图等。最后...

    字符串查找工具

    5. **编程语言中的字符串查找**:在各种编程语言中,如Python的`str.find()`、Java的`String.indexOf()`、JavaScript的`string.includes()`,都有内置函数用于查找字符串。这些函数通常返回匹配位置的索引,或者如果...

    JavaScript自定义函数实现查找两个字符串最长公共子串的方法

    本文实例讲述了JavaScript自定义函数实现查找两个字符串最长公共子串的方法。分享给大家供大家参考,具体如下: //查找两个字符串的最长公共子串 function findSubStr(s1,s2){ var S=sstr= ,L1=s1.length,L2=s2....

    字符串哈希成数字的C实现的代码(含测试)

    将字符串哈希成数字的几种经典的方法:其中的一部分 #ifndef INCLUDE_GENERALHASHFUNCTION_C_H #define INCLUDE_GENERALHASHFUNCTION_C_H #include typedef unsigned int (*hash_function)(char*, unsigned int...

    js中获取只包含一种字符的最长非空子字符串的长度.pdf

    在JavaScript编程语言中,获取一个字符串中只包含一种字符的最长非空子字符串的长度是一项常见的字符串处理任务。这个问题可以通过遍历字符串并检测连续字符来解决。以下是一种实现方法: ```javascript /** * ...

    字符串相似度比较

    在JavaScript中,可以使用内置的字符串函数或第三方库如`natural`、`fuzzyset.js`等来实现这些算法。例如,Levenshtein距离可以用动态规划来实现: ```javascript function levenshteinDistance(s1, s2) { const m...

    字符串最长回文实现

    在编程领域,字符串处理是常见的任务之...总之,理解和实现寻找字符串最长回文子串的算法对提升编程技能非常有帮助,无论是动态规划的思路还是Manacher's Algorithm的巧妙设计,都能加深对字符串处理和算法优化的理解。

    字符串拼接工具

    5. **性能优化**:考虑到大规模字符串操作的性能,工具可能采用了内存效率高的算法,避免了频繁的字符串复制和内存分配。 6. **界面友好**:对于非编程人员,提供图形用户界面(GUI),使得操作更为直观和简便。 ...

Global site tag (gtag.js) - Google Analytics