Estructura de datos: algoritmo de coincidencia de patrones de cadenas (algoritmo kmp)

La operación de posicionamiento de una subcadena generalmente se denomina coincidencia de patrones de cadena.

Algoritmo ingenuo de coincidencia de patrones

  1. Utilice cada carácter de la cadena principal como el comienzo de la subcadena para que coincida con la cadena que se va a buscar.
  2. Haga un bucle grande para la cadena principal y comience un bucle pequeño con la longitud de la subcadena al comienzo de cada carácter hasta que la coincidencia sea exitosa o se complete todo el recorrido.
/*返回子串T在主串s中第pos个字符之后的位置。若不存在,则函数返回值为0。*/
/*T非空,1≤pos ≤StrLength(S)。*/
int Index(String S, String T, int pos)
{
    
    
	int i = pos;/*i用于主串S中当前位置下标,若pos不为1*/
			  /*则从pos 位置开始匹配*/
	int j = 1; /*j用于子串T中当前位置下标值*/
	while(i <= S[0] && j <= T[0])/*若i小于S长度且j小于T的长度时循环*/
	{
    
    
		if(S[i] == T[j]) /*两字母相等则继续*/
		{
    
    
			++i;
			++j;
		}  
		else /*指针后退重新开始匹配*/
		{
    
     
			i = i-j+2; /*i退回到上次匹配首位的下一位*/
						//串是从 1 开始计数的
						//i-j+1 恰好回到这次匹配的第一个字符
						//所以 (i-j+1)+1 指到下一个字符
						//从而开始一轮新的匹配
			j = 1;
		} 
	}
	if(j > T[0]){
    
    
		return i-T[0];
	}
	else
	{
    
    
		return 0;
	}
}

Complejidad del tiempo: O (n*m)
Lleva demasiado tiempo y generalmente no se recomienda.

Algoritmo de coincidencia de patrones KMP

Hay tres predecesores, DEKnuth, JHMorris y VRPratt (Knuth y Pratt investigados conjuntamente, investigación independiente de Morris) publicaron un algoritmo de coincidencia de patrones, que puede evitar en gran medida la situación de recorrido repetido, lo llamamos Algoritmo especial Knuth-Morris-Pratt , referido como algoritmo KMP .

En el algoritmo KMP, solo la posición de la subcadena necesita cambiar hacia adelante y hacia atrás, y la cadena principal se mueve hacia atrás.

  1. Algunos dígitos de la cadena que se va a hacer coincidir no son iguales entre sí y tienen subcadenas correspondientes en la cadena principal. Cuando el último dígito no coincide, estos dígitos en la cadena que se va a hacer coincidir no necesitan ser obviamente desiguales entre sí. en la cadena principal los caracteres a comparar;
  2. Hay igualdad de palíndromos en la cadena que se va a comparar y tienen subcadenas correspondientes en la cadena principal. Cuando el último dígito no coincide, los primeros dígitos de la cadena palíndromo en la cadena que se va a comparar no necesitan ser obviamente iguales a sí mismos. en los caracteres de la cadena principal para comparar.
  3. Consumo de tiempo muy reducido, suComplejidad del tiempo O (n+m);

Encuentre la posición de retroceso de una subcadena:

/*通过计算返回子串T的next数组。*/
void get_next(String T, int *next)
{
    
    
	int i,j;
	i = 1;
	j = 0;
	next[1] = 0;
	while(i < T[0]) /*此处T[0]表示串T的长度*/
	if(j == 0 || T[i] == T[j])/*T[i]表示后缓的单个字符,*/
							  /* T[j]表示前缀的单个字符 */
	{
    
    
		++i;
		++j;
		next[i]=j;	
	}
	else
	{
    
    
		j= next[j];/* 若字符不相同,则j值回溯*/
	}
}

codigo maestro

// 返回子串T在主串S中第pos个字符之后的位置。
// 若不存在,则函数返回值为0
// T非空,1<=pos<=StrLength(S)
int Index_KMP(String S, String T, int pos){
    
    
    // i 用于主串S当前位置下标值,若pos不为1,则从pos位置开始匹配
    int i = pos;
    int j = 1;//j 用于子串T中当前位置下标值
    int next[255];// 定义next数组
    get_next(T,next);// 对串T作分析,得到next数组
    // 若i小于S的长度且j小于T的长度时,循环继续
    while(i <= S[0] && j <= T[0]){
    
    
        // 两字母相等则继续,相对于朴素算法增加了j=0 判断
        if(j == 0 || S[i] == T[j]){
    
    
            ++i;
            ++j;
        }
        // 指针后退重新开始匹配
        else{
    
    
            // j退回合适的位置,i值不变
            j = next[j];
        }
    }
    if(j>T[0]){
    
    
        return i-T[0];
    }
    else
    {
    
    
        return 0;
    }
}

Adjunto:
Respecto a la mejora de encontrar la siguiente matriz :

// 求模式串T的next函数修正值并存入数组nextval
void get_nextval(String T,int *nextval){
    
    
    int i,j;
    i = 1;
    j = 0;
    nextval[1] = 0;
    while(i < T[0]){
    
    
        if(j == 0 || 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值回溯
	         j=nextval[j];
        }
    }
}

Si realmente no puedes entenderlo, ¡memorízalo!

Supongo que te gusta

Origin blog.csdn.net/The_onion/article/details/123759631
Recomendado
Clasificación