樸素匹配算法、KMP匹配算法及其改進【C Program】

之前代碼有點小問題,現在可以了~


樸素匹配算法


原理:
定義主串:CSGOCSDN
定義子串:CSDN

匹配不到就以此後移直至匹配成功或失敗。

代碼:

#include <stdio.h>
#include <string.h>

const int TRUE = 1;
const int FALSE = 0;

int Index(char* S, char* T, int pos);

int main()
{
	char text[100];
	char pattern[100];
	int start_position;
	int count = 1;
	while (count>0) 
	{	
		printf("開始第%d次匹配\n", count);
		printf("輸入主串:");
		scanf("%s", &text);
			
		printf("\ntext:%s", text);
		printf("\n輸入子串:");
		scanf("%s", &pattern);
		printf("\n輸入匹配的起始位置:");
		scanf("%d", &start_position);
	
		if(Index(text, pattern, start_position) == TRUE)
		{
			printf("\n匹配成功!主串中匹配到子串%s", pattern);	
		}	
		else
		{
			printf("\n匹配失敗!\n");
		}
		count++;
		printf("\n\n");
  	}
  	return 0;
}

int Index(char *text, char *pattern, int pos)
{
	int lengthS;
	int lengthT;
	lengthS = strlen(text);
	lengthT = strlen(pattern);
	int i = pos; // i用於主串s中當前位置下標,若pos不爲1
				//則從pos位置開始匹配 
	int j = 0; // j 用於子串T中當前位置下標值 
	while(i <= lengthS && j < lengthT) 
	{
		if (text[i] == pattern[j] ) //兩字母相等則繼續 
		{
			printf("text[%d] = %c\n", i, text[i]);
			i++;
			printf("pattern[%d] = %c\n", j, pattern[j]);
			j++;			
		}
		else //否則指針後退重新開始匹配 
		{
			i = i-j+1;
			j = 0; 
		}
		printf("i = %d\n",i);
		printf("j = %d\n",j);
	
	}
	if (j == lengthT)
		return TRUE;
	else
		return FALSE; 
}

運行結果:
在這裏插入圖片描述


KMP模式匹配算法

***:
原理:
定義主串:CSGOCSDN
定義子串:CSDN

KMP匹配算法的優勢就在於省去了中間一部分開頭就根本不可能匹配成功的多餘步驟,大大改善了時間複雜度。

代碼:

#include <stdio.h>
#include <string.h>

const int TRUE = 1;
const int FALSE = 0;

void get_next(char *pattern, int *next);
int Index_KMP(char* S, char* T, int pos);

int main()
{
	char text[100];
	char pattern[10];
	int start_position;
	int count = 1;
	while (count>0) 
	{	
		printf("開始第%d次匹配\n", count);
		printf("輸入主串:");
		scanf("%s", &text);
			
		printf("\ntext:%s", text);
		printf("\n輸入子串:");
		scanf("%s", &pattern);
		printf("\n輸入匹配的起始位置:");
		scanf("%d", &start_position);
	
		if(Index_KMP(text, pattern, start_position) == TRUE)
		{
			printf("\n匹配成功!主串中匹配到子串%s", pattern);	
		}	
		else
		{
			printf("\n匹配失敗!\n");
		}
		count++;
		printf("\n\n");
  	}
  	return 0;
}

void get_next(char *pattern, int *next)
{
	int i,j;
	i = 1;
	j = 0;
	next[1] = 0;
	while(i < strlen(pattern))
	{
		if(j==0 || pattern[i] == pattern[j])
		
		{
			++i;
			++j;
			next[i] = j;
		}
		else
			j = next[j]; //若字符不相同,則j值回溯
	}
}

int Index_KMP(char *text, char *pattern, int pos)
{
	
	int lengthS;
	int lengthT;
	lengthS = strlen(text);
	lengthT = strlen(pattern);
	int i = pos; // i用於主串s中當前位置下標,若pos不爲1
				//則從pos位置開始匹配 
	int j = 1; // j 用於子串T中當前位置下標值 
	int next[255];
	get_next(pattern, next);
	while(i <= lengthS && j <= lengthT) 
	{
		if (j == 0 || text[i] == pattern[j] ) //兩字母相等則繼續 
		{
			i++;
			j++;			
		}
		else 
		{
			j = next[j];
		}

	
	}

	if (lengthT != 1 && j > lengthT)
		return TRUE;
	else
		return FALSE; 
}

運行結果:
在這裏插入圖片描述
不同之處在於定義了一個next數組,將子串各個位置的j值變化定義爲一個數組next,那麼數組next的長度就是子串的長度。
函數定義:
next[j]={0j=1  Max{k1<k<j,p1pk1 =pjk+1pj1 }1,\bm{next[j] = \left\{ \begin{aligned} 0 & , 當j=1時 \\ \ \ Max & \{k|1<k<j,且'p_1···p_{k-1}\ '='p_{j-k+1}···p_{j-1}\ '\} & \\ 1, & 其他情況 \end{aligned} \right.}
next數組求法詳情建議參考:

kmp算法白話解析https://blog.csdn.net/sb985/article/details/79735488


KMP匹配算法改進


爲了避免出現以下這種開頭重複的尷尬局面,我們對KMP的next數組進行下一步優化。
在這裏插入圖片描述
代碼:

#include <stdio.h>
#include <string.h>

const int TRUE = 1;
const int FALSE = 0;

void get_nextval(char *pattern, int *next);
int Index_KMP(char* S, char* T, int pos);

int main()
{
	char text[100];
	char pattern[10];
	int start_position;
	int count = 1;
	while (count>0) 
	{	
		printf("開始第%d次匹配\n", count);
		printf("輸入主串:");
		scanf("%s", &text);
			
		printf("\ntext:%s", text);
		printf("\n輸入子串:");
		scanf("%s", &pattern);
		printf("\n輸入匹配的起始位置:");
		scanf("%d", &start_position);
	
		if(Index_KMP(text, pattern, start_position) == TRUE)
		{
			printf("\n匹配成功!主串中匹配到子串%s", pattern);	
		}	
		else
		{
			printf("\n匹配失敗!\n");
		}
		count++;
		printf("\n\n");
  	}
  	return 0;
}

void get_nextval(char *pattern, int *nextval)
{
	int i,j;
	i = 1;
	j = 0;
	nextval[1] = 0;
	while(i < strlen(pattern))
	{
		if(j==0 || pattern[i] == pattern[j])
		
		{
			++i;
			++j;
			if (pattern[i] != pattern[j])
				nextval[i] = j;
			else
				nextval[i] = nextval[j];
		}
		else
			j = nextval[j]; //若字符不相同,則j值回溯
	}
}

int Index_KMP(char *text, char *pattern, int pos)
{
	
	int lengthS;
	int lengthT;
	lengthS = strlen(text);
	lengthT = strlen(pattern);
	int i = pos; // i用於主串s中當前位置下標,若pos不爲1
				//則從pos位置開始匹配 
	int j = 1; // j 用於子串T中當前位置下標值 
	int nextval[255];
	get_nextval(pattern, nextval);
	while(i <= lengthS && j <= lengthT) 
	{
		if (j == 0 || text[i] == pattern[j] ) //兩字母相等則繼續 
		{
			i++;
			j++;			
		}
		else 
		{
			j = nextval[j];
		}

	
	}

	if (lengthT != 1 && j > lengthT)
		return TRUE;
	else
		return FALSE; 
}

替換next數組的nextval數組將首位的值取代後續與它相等的字符的值,進一步改善了算法的時間複雜度。

運行結果:
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章