第四章 数据结构与算法- 串

      字符串数据是计算机非数值处理的主要对象之一。在早期字符串作为输入输出的变量出现,现已发展成为字符串类型,可以进行一系列的操作。

   字符串一般简称为串。在汇编和编译程序中,源程序是字符串数据。在事务处理程序中,顾客的姓名和地址以及货物的名称、产地等也是字符串。此外,如信息检索系统、文字编辑程序、自然语言翻译系统等都是以字符串为处理对象。

   然后,目前的计算机硬件结构主要是面向数值计算的需要,基本上没有提供处理字符串数据操作的指令,需要用软件来实现字符串类型。由于各种应用具有不同的特点,要有效的实现字符处理,必须根据具体情况使用合适的存储结构。

 

1、********************************************************************************************

****这里有两种基本算法:BF算法(Brute-Force,最基本的字符串匹配算法)、

****KMP算法。

BF算法:

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

/* run this program using the console pauser or add your own getch, system("pause") or input loop */
/***********************************************************************
****这里A是主串,B是模式串.判断B是否为A的字串。 
****
*/
int count=0;
int main(int argc, char *argv[]) {
	char A[]="ababcdeec", B[]="abcdee";	
	if(1 == StrBF(A, B, count)){
		printf("successed !\n");
		
	}else{
		printf("failed !");
	}
	printf("执行了%d次\n", count);
	return 0;
}

int StrBF(char A[], char B[]){
	int aLen = strlen(A);
	int bLen = strlen(B);
	int i,j=0;
	for(i=0; i<aLen; i++){
		if(A[i] == B[j]){
			j++;
		}else{
			i = i-j+1;
			j=0;			
		}
		count++;
		if(j == bLen)
			return 1;
	}
	return -1;
}

     

KMP算法:

      在KMP算法中,如果有部分字符已经匹配,即当前S[i] = T[j], 例S=cababc  T=ababd 可以说i=1,j=0,此时S[1]=T[0] ,那么现在i++,j++,继续匹配,直到S[i] !=T[j]的时候,那么此时i=5,j=4。这时候i不动,保持不变,并且让j=next[j],这里可能大家就迷惑了,next[j]哪里来的,为什么要让j=next[j] ?这就是KMP算法的难点,也是算法的核心。

       这里我具体描述一下,因为T中的abab是重复的,那么我们让 j = next[j] = 2 让 S[5]和 T[2]进行比较,毕竟我们知道S[3、4]=ab = T[2、3]=ab,同时T中的abab是重复的,所以只需 S[5]和 T[2]进行比较,就不用回溯到初试位置。这就是KMP的理念,寻找next[j]。

       

KMP算法分为两部分,首先计算next()函数,然后进行串匹配。

例如:T = ababd

j12345
T[j]ababd
next[j]01121

现在KMP算法已经讲述的很清楚了,下面我们程序实现。


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

/* run this program using the console pauser or add your own getch, system("pause") or input loop */
/***********************************************************************
****这里A是主串,B是模式串.判断B是否为A的字串。 
****char A[]="ababcdeec", B[]="abab";
****只有形参为指针的时候才能改变实参的值 
*/
int *StrKmpNext(char B[]);

int main(int argc, char *argv[]) {
	char A[]="ababcdeec", B[]="abab";	
	int *p;
	int len;
	len = strlen(B); 
	p = StrKmpNext(B);
	p++;
	while(-1 != *p){		
		printf("%d\t", *p++);
	}
	printf("执行了%d次\n", len);
	return 0;
}
//求取next数组 
int *StrKmpNext(char B[]){
	int bLen = strlen(B);
	int i=0,j=0;
	int *next = malloc(sizeof(int)*bLen+8);//这里next[1] - next[bLen] - next[bLen+1]
	for(i=0; i<=bLen; i++){
		next[i] = 0;
	}
	next[1] = 0;
	i = 1;
	while(i<bLen){
		if(B[i] == B[j] || j==0){		
			i++;
			j++;	
			next[i] = j;					
		}else{
			j = next[j];
		}
	} 
	next[i+1] = -1;
	return next;
}
根据已经拿到的next值,使用KMP算法判定B是否为A的字串。

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

/* run this program using the console pauser or add your own getch, system("pause") or input loop */
/***********************************************************************
****这里A是主串,B是模式串.判断B是否为A的字串。 
****char A[]="ababcdeec", B[]="abab";
****只有形参为指针的时候才能改变实参的值 
*/
int *StrKmpNext(char B[]);

int main(int argc, char *argv[]) {
	char A[]="adababeec", B[]="abab";	
	int *p;
	int len;
	int i,j=0;
	len = strlen(B); 
	p = StrKmpNext(B);
	p++;
	//****kmp算法的实现过程 
	for(i=0; i<strlen(A); i++){
		if(A[i] == B[j]){
			j++;
			if(j == len){
				printf("B是A的字串\n");
				return;
			}			
		}else{
			j = p[j+1];
		}		
	}
	printf("B不是A的字串\n");
	return 0;
}
//求取next数组 
int *StrKmpNext(char B[]){
	int bLen = strlen(B);
	int i=0,j=0;
	int *next = malloc(sizeof(int)*bLen+8);//这里next[1] - next[bLen] - next[bLen+1]
	for(i=0; i<=bLen; i++){
		next[i] = 0;
	}
	next[1] = 0;
	i = 1;
	while(i<bLen){
		if(B[i] == B[j] || j==0){		
			i++;
			j++;	
			next[i] = j;					
		}else{
			j = next[j];
		}
	} 
	next[i+1] = -1;
	return next;
}
KMP算法在判断是否为某一串的字串时,若匹配串重复度特别高,则效率会特别明显。

2、/*********************************************
****给定字符串A和B,输出A和B中的最大公共子串。
****比如A="aocdfe" B="pmcdfa" 则输出"cdf"

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

/*********************************************
****给定字符串A和B,输出A和B中的最大公共子串。
****比如A="aocdfe" B="pmcdfa" 则输出"cdf" 
/* run this program using the console pauser or add your own getch, system("pause") or input loop */
char *commanstring(char shortstring[],char longstring[]);
int main(int argc, char *argv[]) {
	char *str1 = "aocdfe";
	char *str2 = "aocfe";
	char *comman = NULL;
	if(strlen(str1)>strlen(str2))
		comman= commanstring(str2,str1);
	else
		comman = commanstring(str1,str2);
	printf("the longest comman string is:%s\n",comman);	
	return 0;
}
char *commanstring(char shortstring[],char longstring[])
{
	int i,j;
	char *substring = malloc(256);
	int lenShort = strlen(shortstring);
	if(strstr(longstring,shortstring)!=NULL)
		return shortstring;
	for(i=lenShort-1;i>0;i--){
		for(j=0;j<=lenShort-i;j++){
			memcpy(substring,&shortstring[j],i);
			substring[i]='\0';
			if(strstr(longstring,substring)!=NULL)
				return substring;
		}
	}
	return NULL;
}

3、/*********************************************
***如果两个字符串的字符一样,但是顺序不一样,被认为是兄弟字符串,

***问如何在迅速匹配兄弟字符串(如,bad和adb就是兄弟字符串)。

 

#include <stdio.h>
#include <stdlib.h>

/* run this program using the console pauser or add your own getch, system("pause") or input loop 
*如果两个字符串的字符一样,但是顺序不一样,被认为是兄弟字符串,问如何在迅
速匹配兄弟字符串(如,bad和adb就是兄弟字符串)。思路:判断各自素数乘积
是否相等。更多方法请参见:http://blog.csdn.net/v_JULY_v/article/details/6347454。
*date:2013/11/2 
*@author_hanzhen
*/
int main(int argc, char *argv[]) {
	char A[]={"bad"},B[]={"adb"};
	if(array(A,B) == 1)
		printf("A and B are the brothers!");
	else
		printf("NO,error!");
	return 0;
}

int array(char A[],char B[]){
	int i=0;
	char *a, *b;
	int Aresult[26]={0},Bresult[26]={0};
	a = A;
	b = B;
	if(strlen(A)!=strlen(B))  return -1;
	i=0;
	while(i<strlen(A))
	{ 
		i++;
		Aresult[*a-'a']++;
		a++;
		Bresult[*b-'a']++;
		b++;
		//printf("%d\n", i);
	}
	for(i=0;i<26;i++){
		if(Aresult[i]!=Bresult[i]){			
			return -1;
		}		
	}
	if(i>=26)
			return 1;	
}


 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值