数据结构与算法----串

1串的基本概念
串(字符串)∶是零个或多个字符组成的有限序列。记作: S="aia2a3.…”,其中s是串名,a(1≤i≤n)是单个,可以是字母、数字或其它字符。
串值:双引号括起来的字符序列是串值。
串长:串中所包含的字符个数称为该串的长度。空串(空的字符串):长度为零的串称为空串,它不包含任何字符。
空格串(空白串):构成串的所有字符都是空格的串称为空白串。
 

串基本运算的代码实现


 1.定义串结构体,以堆分配的存储方式

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<malloc.h>
 
#define Max 20
#define error 0
#define overflow -2
#define ok 1
#define true 1
#define false 0
 
typedef struct
{
	char *ch;
	int length;
}HString;
 
typedef int Status;
2.初始化串

//初始化串 
void InitString(HString &s)
{
	s.ch=NULL;
	s.length=0;
}
3.串赋值

 
//串赋值 
Status StrAssign(HString &T,char *str)
{
	int i,j;
	InitString(T);
	i=strlen(str);
	if(!i)
		return error;
	else
	{
		T.ch=(char*)malloc(i*sizeof(char));
		if(!T.ch)
			exit (overflow);
		for(j=0;j<i;j++)
			T.ch[j]=str[j];
			T.length=i;
	}
}
4. 判断串非空

//判断串非空 
Status StrEmpty(HString &T)
{
	if(T.length==0&&T.ch==NULL)
		return true;
	else 
		return false;		
}
5.串赋值

//串复制,将S赋给T 
Status StrCopy(HString &T,HString S)
{
	int i;
	InitString(T);
	if(StrEmpty(S))
		return error;
		
	T.ch=(char*)malloc(S.length*sizeof(char));
	if(!T.ch)
		exit(overflow);
		
	for(i=0;i<S.length;i++)
		T.ch[i]=S.ch[i];
		
	T.length=S.length;
	
	return ok;		
}
6.串比较

//串比较 
Status StrCmp(HString S,HString T)
{
	int i;
	for(i=0;i<S.length&&i<T.length;i++)
	{
		if(S.ch[i]!=T.ch[i])
			return S.ch[i]-T.ch[i];
	}
	return 0;
}
7.求串长

Status StrLength(HString S)
{
	if(StrEmpty(S))
		return error;
	else
		return S.length; 
}
8.串清空

//串清空,恢复到初始化时刻 
Status ClearString(HString &s)
{
	if(s.ch)
	{
		free(s.ch);
		s.ch=NULL;
	}
	s.length=0;
	return ok;
}
9.串拼接

//串拼接,将S1,S2拼接后用T返回 
Status Concat(HString &T,HString S1,HString S2)
{
	int i;
	InitString(T);
	T.length=S1.length+S2.length;
	T.ch=(char*)malloc(T.length*sizeof(char));
	if(!T.ch)
		exit(overflow);
		
	for(i=0;i<S1.length;i++)
		T.ch[i]=S1.ch[i];
	for(i=0;i<S2.length;i++)
		T.ch[S1.length+i]=S2.ch[i];
		
	return ok;
}
10.求子串

//求子串,将S从第pos位起len个长度的子串用Sub返回 
Status SubString(HString &Sub,HString S,int pos,int len)
{
	int i;
	InitString(Sub);
	if(StrEmpty(S))
		return error;
	if(pos<1||pos>S.length||len<0||pos+len-1>S.length)
		return error;
	if(len)
	{
		Sub.ch=(char*)malloc(len*sizeof(char));
		if(!Sub.ch)
			exit(overflow);
		for(i=0;i<len;i++)
			Sub.ch[i]=S.ch[pos+i-1];
		Sub.length=len;		
	}
	return ok;
}
11.串索引

//串索引,返回T在S中第pos个字符后第一次出现的位置 
Status Index(HString S,HString T,int pos)
{
	int s,t,i;
	HString Sub;
	InitString(Sub);
	
	if(pos>0)
	{
		s=S.length;
		t=T.length;
		i=pos;
		
		while(i+t-1<=s)
		{
			SubString(Sub,S,i,t);
			if(StrCmp(Sub,T))
					i++;
			else
				return i;
		}
	}
	return 0;
}
12.串插入

//串插入 
Status StrInsert(HString &S,int pos,HString T)
{
	int i;
	if(pos<1||pos>S.length+1)
		return error;
	if(StrEmpty(T))
		return error;
	else
	{
		S.ch=(char*)realloc(S.ch,(S.length+T.length)*sizeof(char));
		if(!S.ch)
			exit (overflow);
		for(i=S.length-1;i>=pos-1;i--)
			S.ch[i+T.length]=S.ch[i];
			
		for(i=0;i<T.length;i++)
			S.ch[pos+i-1]=T.ch[i];
			
		S.length+=T.length;			
	}
	return ok;
}
13.串删除

//串删除 
Status StrDelete(HString &S,int pos,int len)
{
	int i;
	if(StrEmpty(S))
		return error;
	if(pos<1||pos+len-1>S.length||len<0)
		return error;
		
	for(i=pos-1;i+len<=S.length;i++)
		S.ch[i]=S.ch[i+len];
	S.length-=len;
	S.ch=(char*)realloc(S.ch,S.length*sizeof(char));
	return ok;
}
 14.串替换

//串替换 ,用v替换主串中所有与T相等的不重叠子串 
Status Replace(HString &S,HString T,HString V)
{
	int i;
	if(StrEmpty(T))
		return error;
	i=Index(S,T,1);
	while(i!=0)
	{
		StrDelete(S,i,StrLength(T));
		StrInsert(S,i,V);
		i+=StrLength(V);
		i=Index(S,T,i); 
	}
	return ok;
}
15.输出串

//输出串S 
void StrPrint(HString S)
{
	int i;
	if(StrEmpty(S))
		printf("S为空串,不可输出!");
	for(i=0;i<S.length;i++)
		printf("%c",S.ch[i]); 
	printf("\n");
}
16.主函数测试,只调用了主要的几个函数,其余函数也可以自行验证

//主函数
int main()
{
	HString S,T,V;
	InitString(T);InitString(S);InitString(V);
	
	printf("***************************\n");
	printf("从键盘输入两串字符(分别为字符串1,2):\n"); 
	char str1[Max]; gets(str1);
	char str2[Max]; gets(str2);
	
	printf("***************************\n");
	printf("实现两串字符的连接: ");
	StrAssign(S,str1);StrAssign(T,str2);
	Concat( V,S, T);
	StrPrint(V); 
	
	printf("\n********************************\n");
	printf("\n对字符串1进行删除操作:\n");
	int pos,len;
	printf("输入你想删除的位置和长度:");
	scanf("%d%d",&pos,&len);
	StrDelete(S, pos, len);
	StrPrint(S);
	
	printf("********************************\n");
	printf("\n将串2插入到修改后的串1的某个位置:\n");
	printf("输入你想插入的位置:");
	scanf("%d",&pos);
	StrInsert(S, pos, T);
	StrPrint(S);
	
	printf("********************************\n");
	printf("\n求串3的子串:\n");
	printf("输入你想取的子串的起始位置和长度:");
	scanf("%d%d",&pos,&len); 
	HString Sub;
	SubString(Sub,V, pos, len);
	StrPrint(Sub);
	
	printf("********************************\n");
	printf("\n清空并释放串指针\n");
	ClearString(S);
	ClearString(V);
	ClearString(T);
	
	printf("\n程序结束!\n");
	return 0;
 
 }
————————————————
版权声明:本文为CSDN博主「凉柒-lq」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_42475914/article/details/84244197

Brute-Force算法
 Brute-Force,BF算法,亦称简单匹配算法
 基本思路
 从目标串s=“s 0 s 1 …s n-1 ”的第一个字符开始
和模式串t=“t 0 t 1 …t m-1 ”中的第一个字符比
较,若相等,则继续逐个比较后续字符
 否则从目标串s的第二个字符开始重新与模
式串t的第一个字符进行比较
 依次类推……
 若从目标串s的第i个字符开始,每个字符
依次和模式串t中的对应字符相等,则匹配
成功,返回i;否则,匹配失败,函数返回
-1。

int index(SqString s,SqString t)
{
int i=0,j=0;
while (i<s.length && j<t.length)
{
if (s.data[i]==t.data[j])
{
i++;
j++;
}
else
{
i=i-j+1;
j=0;
}
}
if (j>=t.length)
return(i-t.length);
else
return(-1);
}

KMP算法的关键是利用匹配失败后的信息,尽量减少模式串与主串的匹配次数以达到快速匹配的目的。具体实现就是实现一个next()函数,函数本身包含了模式串的局部匹配信息。时间复杂度O(m+n)。
(1)分析KMP算法的改进思路

分析朴素模式匹配中的例子:
如果我们人为来寻找的话,肯定不会再把i移动回第1位,因为主串匹配失败的位置前面除了第一个A之外再也没有A了,我们为什么能知道主串前面只有一个A?因为我们的子串中字符都不相同,而且我们已经知道前面三个字符都是匹配的!(这很重要)。移动过去肯定也是不匹配!因此,我们产生一个想法,可以保持i不动,只需要移动j即可,如下图:

KMP的思想就是:利用已经部分匹配这个有效信息,保持i指针不回溯,通过修改j指针,让模式串尽量地移动到有效的位置。

但是上面这种情况比较理想,因为子串中的字符都不相同,处理起来较简单。如果字串中存在相同的字符,匹配时如何知道j的指针应该移动到哪里呢?
于是我们有个想法:利用一个数组next来保存每一个字符不相同时j应该移动到的位置。

KMP算法的核心就是找到数组next

KMP算法

int KMPIndex(SqString s,SqString t)
{
int next[MaxSize],i=0,j=0;
GetNext(t,next);
while (i<s.length && j<t.length)
{
if (j==-1 || s.data[i]==t.data[j])
{
i++;
j++;
}
else
j=next[j];
}
if (j>=t.length)
return(i-t.length);
else
return(-1);
}



 待改进的问题
 模式“aaaab”在和主串“aaabaaaab”匹配
时,当i=3,j=3时,s.data[3]≠t.data[3],
由next[j]的指示还需进行i=3、j=2,i=3、
j=1,i=3、j=0等3次比较。
 解决思路
 模式中的第4个字符与前3个字符相同,
不需要再和主串中第4个字符相比较,
而是直接进行i=4,j=0时的字符比较。
i=9
j=5
使用修正的nextval

void GetNextval(SqString t,int nextval[])
{
int j=0,k=-1;
nextval[0]=-1;
while (j<t.length)
{
if (k==-1 || t.data[j]==t.data[k])
{
j++;
k++;
if (t.data[j]!=t.data[k])
nextval[j]=k;
else
nextval[j]=nextval[k];
}
else
k=nextval[k];
}
}


 思路
 若按上述定义得到next[j]=k,而模式
中t j =t k ,则当匹配失败时,不需要再和
t k 进行比较,而直接和t next[k] 进行比较。
即,此时的next[j]应和next[k]相同
 解决
 比较t.data[j]和t.data[k]
 若不等,则 nextval[j]=k;
 若相等nextval[j]=nextval[k]。
3 2 1 0 -1 next[j]
3 -1 -1 -1 -1 nextval[j]
b a a a a t.data[j]
4 3 2 1 0 j
修改后的KMP算法
 

int KMPIndex1(SqString s,SqString t)
{
int nextval[MaxSize],i=0,j=0;
GetNextval(t,nextval);
while (i<s.length && j<t.length)
{
if (j==-1 || s.data[i]==t.data[j])
{
i++;
j++;
}
else
j=nextval[j];
}
if (j>=t.length)
return(i-t.length);
else
return(-1);
}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值