• C++编程练习(7)----“KMP模式匹配算法“字符串匹配


    子串在主串中的定位操作通常称做串的模式匹配。

    KMP模式匹配算法实现:
    /* Index_KMP.h头文件 */
    #include<string>
    #include<sstream>
    
    void get_next(std::string T,int *next)
    {
    	unsigned int i,j;
    	i=1;
    	j=0;
    	next[1]=0;
    	while(i<(T.size()-1))	/* 此处T的首个字符T[0]表示串T的长度,不参与计算 */
    	{
    		if(j==0||T[i]==T[j])	/* T[i]表示后缀的单个字符,T[j]表示前缀的单个字符 */
    		{
    			++i;
    			++j;
    			next[i]=j;
    		}
    		else
    			j=next[j];		/* 若字符不相同,则j值回溯 */
    	}
    }
    
    int Index_KMP(std::string S, std::string T, unsigned int pos)
    {
    	std::string s,t;				/*在字符串S,T的最前插入一个字符来保存串的长度值,*/
    	std::ostringstream s1,s2;		/*用来保证字符串的有用元素是从下标1开始*/
    	s1<<S.size()<<S;				/*将新的数组保存为s,t*/
    	s2<<T.size()<<T;
    	s=s1.str();
    	t=s2.str();
    	unsigned int i=pos;	/* i用于主串s当前位置下标值,若pos不为1,则从pos位置开始匹配 */
    	unsigned int j=1;	/* j用于字串t中当前位置下标值 */
    	int next[255];	/* 定义一next数组 */
    	get_next(t,next);	/* 对串t作分析,得到next数组 */
    	while (i<=(s.size()-1) && j<=(t.size()-1))	/* 若i小于S的长度且j小于T的长度时,循环继续 */
    	{
    		if ( j==0 || s[i]==t[j])	/* 两字母相等则继续,相对于朴素算法增加了j=0判断 */
    		{
    			++i;
    			++j;
    		}
    		else		/* 指针后退重新开始匹配 */
    		{
    			j=next[j];		/* j退回合适的位置,i值不变 */
    		}
    	}
    	if ( j>(t.size()-1) )
    		return i-(t.size()-1);
    	else
    		return 0;
    }

    KMP模式匹配算法的改进:

    /* Index_KMP.h头文件 */
    #include<string>
    #include<sstream>
    
    void get_nextval(std::string T,int *nextval)
    {
    	unsigned int i,j;
    	i=1;
    	j=0;
    	nextval[1]=0;
    	while(i<(T.size()-1))	/* 此处T的首个字符T[0]表示串T的长度,不参与计算 */
    	{
    		if(j==0||T[i]==T[j])	/* T[i]表示后缀的单个字符,T[j]表示前缀的单个字符 */
    		{
    			++i;
    			++j;
    			if (T[i]!=T[j])			/*若当前字符与前缀字符不同*/
    				nextval[i]=j;		/*则当前的j为nextval在i位置的值*/
    			else
    				nextval[i]=nextval[j];	/*如果与前缀字符相同,则将前缀字符的nextval值赋值给nextval在i位置的值*/
    			
    		}
    		else
    			j=nextval[j];		/* 若字符不相同,则j值回溯 */
    	}
    }
    
    int Index_KMP(std::string S, std::string T, unsigned int pos)
    {
    	std::string s,t;				/*在字符串S,T的最前插入一个字符来保存串的长度值,*/
    	std::ostringstream s1,s2;		/*用来保证字符串的有用元素是从下标1开始*/
    	s1<<S.size()<<S;				/*将新的数组保存为s,t*/
    	s2<<T.size()<<T;
    	s=s1.str();
    	t=s2.str();
    	unsigned int i=pos;	/* i用于主串s当前位置下标值,若pos不为1,则从pos位置开始匹配 */
    	unsigned int j=1;	/* j用于字串t中当前位置下标值 */
    	int next[255];	/* 定义一next数组 */
    	get_nextval(t,next);
    	while (i<=(s.size()-1) && j<=(t.size()-1))	/* 若i小于S的长度且j小于T的长度时,循环继续 */
    	{
    		if ( j==0 || s[i]==t[j])	/* 两字母相等则继续,相对于朴素算法增加了j=0判断 */
    		{
    			++i;
    			++j;
    		}
    		else		/* 指针后退重新开始匹配 */
    		{
    			j=next[j];		/* j退回合适的位置,i值不变 */
    		}
    	}
    	if ( j>(t.size()-1) )
    		return i-(t.size()-1);
    	else
    		return 0;
    }
    

    匹配算法不做变化,只需要将"get_next(T,next)"改为“get_nextval (T,next)”即可。

    总结:改进过的KMP算法,它是在计算出 next 值的同时,如果a位字符与它 next 值指向的 b 位字符相等,则该 a 位的nextval 就指向 b 位的 nextval 值,如果不等,则该 a 位的 nextval 值就是它自己 a 位的 nextval 的值。
  • 相关阅读:
    54、操控变形—调整
    leetcode 106. Construct Binary Tree from Inorder and Postorder Traversal 从中序与后序遍历序列构造二叉树(中等)
    leetcode 219. Contains Duplicate II 存在重复元素 II(简单)
    leetcode 145. Binary Tree Postorder Traversal 二叉树的后序遍历 (中等)
    leetcode 530. Minimum Absolute Difference in BST二叉搜索树的最小绝对差 (简单)
    leetcode 889. Construct Binary Tree from Preorder and Postorder Traversal 根据前序和后
    leetcode 146. LRU Cache LRU 缓存 (简单)
    leetcode 785. Is Graph Bipartite判断二分图 (中等)
    leetcode 94. Binary Tree Inorder Traversal 二叉树的中序遍历(中等)
    leetcode 220. Contains Duplicate III 存在重复元素 III(困难)
  • 原文地址:https://www.cnblogs.com/fengty90/p/3768856.html
Copyright © 2020-2023  润新知