1. 程式人生 > >資料結構-字串匹配(KMP演算法、BF演算法、BM演算法)

資料結構-字串匹配(KMP演算法、BF演算法、BM演算法)

本程式碼中用了KMP演算法、BF演算法、BM演算法三種演算法進行字串匹配。

文字串儲存在了test.txt中,模式串需自行輸入。

程式碼如下:

#include"stdio.h"
#include"stdio.h"
#include"stdlib.h"
#include"conio.h"

#define ASIZE 256 
#define XSIZE 200
typedef struct{
	char *ch;
	int length;
}HString;

//BF演算法 
void BF(HString S,HString T)   
{   int i=0,j=0;
	loop:
    j=-1;
	while(i<S.length&&j<T.length)
	{
		if(S.ch[i]==T.ch[j])
		{i++;j++;	}
		else
		{	i=i-j+1;	j=0;}
	}
	if(j==T.length)
	{	printf("在位置%d發現匹配!\n",i-j+1);goto loop;	}
}

//KMP演算法 
void KMP(HString S,HString T,int *next)
{
	int i=0,j=0;
	loop:
	while(i<S.length&&j<T.length)
	{
		if(j==-1||S.ch[i]==T.ch[j])
		{	++i;	++j;	}
		else
		   j=next[j];
	}
	if(j==T.length)
	{
	     printf("在位置%d發現匹配!\n",i-j+1);
		 j=-1;
	     goto loop;
	 }
}

void Next(HString T,int *next) //求next函式 
{ 
	int i,j=0,k=-1;
	next[0]=-1;
	while(j<T.length)
	{
		if(k==-1||T.ch[j]==T.ch[k])
		{
			if(T.ch[++j]==T.ch[++k]) next[j]=next[k];
			else next[++j]=++k;
		}
		else k=next[k];
	}
}


 //BM演算法    (Boyer-Moore)    好字尾相關函式 
void preBmBc(HString Q, int m, int bmBc[]) {
   int i;
   for (i = 0; i <256; ++i)
      bmBc[i] = m;
   for (i = 0; i < m - 1; ++i)
      bmBc[Q.ch[i]] = m - i - 1;
}
 
 
void suffixes(HString Q, int m, int *suff) {
   int f, g, i;
   suff[m - 1] = m;
   g = m - 1;
   for (i = m - 2; i >= 0; --i) {
      if (i > g && suff[i + m - 1 - f] < i - g)
         suff[i] = suff[i + m - 1 - f];
      else {
         if (i < g)
            g = i;
         f = i;
         while (g >= 0 && Q.ch[g] == Q.ch[g + m - 1 - f])
            --g;
         suff[i] = f - g;
      }
   }
}
 
void preBmGs(HString Q, int m, int bmGs[]) {
   int i, j, suff[Q.length];
   suffixes(Q, m, suff);
   for (i = 0; i < m; ++i)
      bmGs[i] = m;
   j = 0;
   for (i = m - 1; i >= 0; --i)
      if (suff[i] == i + 1)
         for (; j < m - 1 - i; ++j)
            if (bmGs[j] == m)
               bmGs[j] = m - 1 - i;
   for (i = 0; i <= m - 2; ++i)
      bmGs[m - 1 - suff[i]] = m - 1 - i;
}
 
int MAX(int i,int j)   //求最大值 
{
	if(i>j) return i;
	else return j;
}
void BM(HString Q, int m, HString S, int n) {
   int i, j, bmGs[Q.length], bmBc[256];
   preBmGs(Q, m, bmGs);
   preBmBc(Q, m, bmBc);
   j = 0;
   while (j <= n - m) {
      for (i = m - 1; i >= 0 && Q.ch[i] == S.ch[i + j]; --i);
      if (i < 0) {
          printf("在位置%d發現匹配!\n",j+1);
         j += bmGs[0];
      }
      else
         j += MAX(bmGs[i], bmBc[S.ch[i + j]] - m + 1 + i);
   }
}


int main()
{   HString S,Q;
    FILE *fp;
    if(!(fp = fopen("test.txt" , "r"))) printf("讀取失敗!!\n");
    fseek(fp,0,SEEK_END);  //檢視檔案大小 
    int file_size;
    file_size=ftell(fp);
    
    int count=0;             //數出換行符數目 
    char ch;
    fseek(fp,0,SEEK_SET);
	printf("檔案中的內容如下:\n"); 
    while((ch=fgetc(fp))!=EOF) 
		{
		if(ch=='\n') count++;
	    putchar(ch);
		}
	file_size-=count;

    int i=0;                 //將檔案中的字元寫入S.ch 
    fseek(fp,0,SEEK_SET);
    S.ch =(char *)malloc(file_size * sizeof(char));
    while((ch=fgetc(fp))!=EOF) 
		if(ch!='\n') {S.ch[i]=ch;i++;}
	S.ch[i]='\0';
	S.length=file_size+1;

    printf("\n請輸入模式串:\n");
    Q.ch =(char *)malloc(XSIZE* sizeof(char));
    Q.length=0;
    ch=getchar();
    if(ch!='\n')
    Q.ch[Q.length++]=ch;
    while(ch!='\n')
    { 
    	ch=getchar();
    	Q.ch[Q.length++]=ch;
	}
	Q.ch[Q.length]='\0';
	Q.length--;


	int *next;                    //定義next陣列,KMP中使用 
    next=(int *)malloc(Q.length*sizeof(int));
    
    printf("----------------  BF演算法  ------------------\n"); 
    BF(S,Q);                   //BF演算法 
    printf("\n----------------  KMP演算法  ----------------\n"); 
    Next(Q,next);             //KMP演算法
    KMP(S,Q,next);     
    printf("\n----------------  BM演算法  ------------------\n"); 
    BM(Q,Q.length,S,S.length);  //BM 演算法 
    
    
    return 0;
    
}

執行結果如下: