1.基本概念

由零个或多个字符组成的有限序列。

2.抽象数据类型(ADT)

数据对象:串的数据对象约束为字符集

数据关系:与线性表类似,除第一个和最后一个元素外,其余元素有且仅有一个直接前驱和直接后驱。

基本操作:

                   StrAssign(*T, chars): 生成一个其值等于chars的串T。

                   StrCopy(*T, S): 由串S复制得串T。

                   StrEmpty(S):若串S为空串,则返回TRUE,否则返回FALSE。

                   StrCompare(S, T): 若S>T,则返回值为1;若S=T,则返回值为0;若S<T,则返回值为-1。

                   StrLength(S): 返回串S的元素个数。

                   ClearString(*S): 清空S。

                   Contact(*T, S1, S2): 用T返回由S1和S2联接而成的新串。

                   SubString(*Sub, S, pos, len): 用Sub返回串S的第pos个字符起长度为len的子串。

                   Index(S, T, pos): 若主串S中存在与非空串T值相同的子串,则返回它在主串中第pos个字符之后第一次出现的位置;否则返回0。

                  Replace(*S ,T ,V): 用V替换主串S中出现的所有与T相等的不重叠的子串。

                  StrInsert(*S, pos, T): 在串S的第pos个字符之前插入串T。

                  StrDelete(*S, pos, len): 从串S中删除第pos个字符起长度为len的子串。

3.顺序存储

串的顺序存储方式可以用定长数组存储表示,也可以用堆分配存储表示。两者都具有顺序存储结构的特点,处理方便,但前者有个缺陷,由于数组长度限定,可能会出现数据溢出的错误。因此相比之下,第二种方法更为灵活。在此主要介绍堆分配存储方式。

#define ERROR 0
#define OK 1
#define TRUE 1
#define FALSE 0
#include <stdlib.h>
#include <stdio.h>
#define MAXSIZE 100 
//串的堆分配存储表示
typedef struct
{
	char*ch;           //串的存储基地址 
	int length;	      //串的长度 
}HString;

int StrAssign(HString*T,char *chars)    //新建串 
{
	int i=0;
	char*c=chars;
	if (T->ch) free(T->ch);
	while (*c)
	{
		c++;
		i++;
	}
	T->length=i;      //确定字符串长度      
	if (i==0) 
	{
		T->ch=NULL;
	}else
	{
		if (!(T->ch=(char*)malloc(sizeof(char)*(i+1)))) return ERROR;     //申请存储空间,多预留一个空间,用于放置结束符号'\0',方便之后输出 
		for (i=0;i<T->length;i++)
		{
			T->ch[i]=chars[i];
		}
		T->ch[i]='\0';	
	}
	return OK;
}

int StrCopy(HString*T,char*S)   //复制串 
{
	int i=0,j;
	char*c=S;
	while (*c)
	{
		c++;
		i++;
	}
	if (T->ch) free(T->ch);
	if (!(T->ch=(char*)malloc(sizeof(char)*i+1))) return ERROR;    //申请存储空间,多预留一个空间,用于放置结束符号'\0',方便之后输出 
	for (j=0;j<i;j++)               //逐个字符复制 
	{
		T->ch[j]=S[j];
	} 
	T->length=i;
	T->ch[j]='\0';
	return OK;
}

int StrEmpty(HString S)   //验证串是否为空 
{
	if (S.length==0) return TRUE;
	return FALSE;
}

int StrLength(HString S)  //返回串长度 
{
	return S.length;
}

int ClearString(HString *S)  //清空串 
{
	if (S->ch) 
	{
		free(S->ch);
		S->ch=NULL;
	}
	S->length=0;
	return OK;
}

int StrCompare(HString S,HString T)  //比较两个串的大小 
{
	int i;
	for (i=0;i<S.length && i<T.length;i++)
	{
		if (S.ch[i]>T.ch[i]) return 1;
		if (S.ch[i]<T.ch[i]) return -1;
	}
	if (S.length>T.length) i=1;
	else if (S.length<T.length) i=-1;
	else i=0;
	return i;
} 

int Contact(HString*T,HString S1,HString S2)  //连接两个串 
{
	int i,j;
	if (T->ch) free(T->ch);
	if (!(T->ch=(char*)malloc(sizeof(char)*(S1.length+S2.length+1)))) return ERROR;
	for (i=0;i<S1.length;i++) T->ch[i]=S1.ch[i];   //首先粘贴第一个串 
	for (j=0;j<S2.length;j++) T->ch[i+j]=S2.ch[j];  //接着粘贴第二个串 
	T->ch[i+j]='\0';
	T->length=S1.length+S2.length;
}

int SubString(HString*Sub,HString S,int pos,int len)    //取子串 
{
	int i;
	if (pos<1 || pos>S.length || len<0 || len>(S.length-pos+1))   //若取串的位置或长度不合法,则返回错误 
	return ERROR;
	if (Sub->ch) free(Sub->ch);
	if (!(Sub->ch=(char*)malloc(sizeof(char)*(len+1)))) return ERROR;
	for (i=0;i<len;i++)
	{
		Sub->ch[i]=S.ch[pos+i-1];          
	}
	Sub->ch[i]='\0';
	Sub->length=len;
	return OK; 
}

int Index(HString S,HString T,int pos)   //查找子串位置 
{
	int i,j;
	if (pos<1 || pos>S.length || T.length==0) return ERROR; //若子串为空或查找的起始位置不合理,则返回错误 
	if (T.length>S.length) return FALSE;
	j=pos;
	do{
		for (i=0;i<T.length;i++)         //遍历主串和子串,对比每个元素 
		{
			if (S.ch[j+i-1]!=T.ch[i])   //如果有元素不等,则主串的匹配初始位置加1,并重新开始匹配 
			{j++;break;}
		}
	}while(i<T.length && j<S.length);   //如果查找成功或未找到,则退出循坏 
	if (i>=T.length) return j-pos+1;   //若查找成功,返回从起始位置开始的坐标 
	else return FALSE;
}

int Replace(HString*S,HString T,HString V) //替换子串 
{
	int i,j=1;
	HString s,Sub,str,S1;
	s.ch=NULL;Sub.ch=NULL;str.ch=NULL;S1.ch=NULL;
	s.length=0;Sub.length=0;str.length=0;S1.length=0;
	if ( S->length ==0 || T.length==0) return ERROR;   //如果主串为空或要替换的子串长度为空,则返回错误 
	i=Index(*S,T,j);       //第一次查找被替换子串的位置 
	if (i==0) return FALSE; //如果主串中没有要替换的子串,则返回失败 
	while(i!=0)            //如果有替换的子串 
	{
		SubString(&Sub,*S,j,i-1);   //记录被替换子串前面的串 
		Contact(&s,Sub,V);          //将前面的串和新串相连,完成串的替换 
		Contact(&str,S1,s);        //添加到替换过的串后面 
		StrCopy(&S1,str.ch);
		j+=i+T.length-1;          //重新定位查找位置 
		i=Index(*S,T,j);          //查找下一个被替换子串的位置 
	}
	if (j<=S->length)            //把最后一个替换子串后面的串的内容连接到替换过的串尾部 
	{
		SubString(&Sub,*S,j,S->length-j+1);
		Contact(&str,S1,Sub);
		StrCopy(&S1,str.ch);
	}
	*S=S1;                     //更新原来的串 
	return OK;
}

int StrInsert(HString*S,int pos,HString T)  //插入子串 
{
	HString Sub1,S1,Sub2;
	Sub1.ch=NULL;S1.ch=NULL;Sub2.ch=NULL;
	Sub1.length=0;S1.length=0;Sub2.length=0;
	if (pos<1 || pos>S->length+1 || T.length==0) return ERROR;   //如果插入的子串为空或插入的位置非法,则返回错误 
	SubString(&Sub1,*S,1,pos-1);       //记录插入位置之前的串 
	Contact(&S1,Sub1,T);               //将插入位置前的串和插入的串连接起来 
	SubString(&Sub2,*S,pos,S->length-pos+1);  //记录剩下的串 
	Contact(S,S1,Sub2);              //将剩下的串连接到尾部 
	return OK;
}

int StrDelete(HString*S,int pos,int len)  //删除子串 
{
	HString Sub1,Sub2;
	Sub1.ch=NULL;Sub2.ch=NULL;
	Sub1.length=0;Sub2.length=0;
	Sub1.ch=NULL;Sub2.ch=NULL;
	if (pos<1 || pos>S->length || len>S->length-pos+1) return ERROR;  //如果删除位置不合理或删除的长度超过主串的长度,则返回错误 
	SubString(&Sub1,*S,1,pos-1);             //记录删除位置之前的串 
	SubString(&Sub2,*S,pos+len,S->length-pos-len+1);  //记录删除子串后面的剩余串 
	Contact(S,Sub1,Sub2);   //将前面的串和后面的串相连 
	return OK;
}

int main()  
{  
    HString S,T,Sub,V,S1,S2;
    S.ch=NULL;
    T.ch=NULL;
    Sub.ch=NULL;
    V.ch=NULL;
    S1.ch=NULL;
    S2.ch=NULL;
	char s[MAXSIZE];    
    int pos,choice,len;   
    do{  
        printf("输入操作: 0.退出 1.返回串长度 2.插入串 3.删除串 4.获取子串 5.清空串 6.创建串 7.查找串 8.验证串是否为空 9.替换串 10.连接串 11.比较串 12.复制串\n");  
        scanf("%d",&choice);  
        switch (choice)  
        {  
            case 1:  
            {  
				printf("%d\n",StrLength(S));
                break;  
            }  
            case 2:  
            {
				printf("输入插入的位置\n");
				scanf("%d",&pos);
				printf("输入插入的串\n");
				scanf("%s",s);
				StrAssign(&T,s); 
				StrInsert(&S,pos,T);
				printf("S=%s\n",S.ch);
                break;  
            }  
            case 3:  
            {  
            	printf("输入删除的位置\n");
            	scanf("%d",&pos);
            	printf("输入删除的长度\n");
            	scanf("%d",&len);
				StrDelete(&S,pos,len);
				printf("S=%s\n",S.ch);
                break;  
            }  
            case 4:  
            {
				printf("输入子串的起始位置\n");
            	scanf("%d",&pos);
            	printf("输入子串的长度\n");
            	scanf("%d",&len);  
				SubString(&Sub,S,pos,len);
				printf("Sub=%s\n",Sub.ch);
                break;  
            }  
            case 5:  
            {
				ClearString(&S);
				printf("S=%s\n",S.ch);
                break;  
            }  
            case 6:  
            {
				printf("输入串的内容\n");
				scanf("%s",s);  
				StrAssign(&S,s);
				printf("S=%s\n",S.ch);
                break;  
            }  
            case 7:  
            {
				printf("输入在主串中的起始查找位置\n");
            	scanf("%d",&pos);
				printf("输入查找的子串\n");
				scanf("%s",s);
				StrAssign(&T,s);  
				printf("Index=%d\n",Index(S,T,pos)); 
                break;  
            }
			case 8:
			{
				printf("%d\n",StrEmpty(S));
				break;
			} 
			case 9:
			{
				printf("输入被替换的子串\n");
				scanf("%s",s);
				StrAssign(&T,s);
				printf("输入替换的子串\n");
				scanf("%s",s);
				StrAssign(&V,s);
				Replace(&S,T,V);
				printf("S=%s\n",S.ch);
				break;
			} 
			case 10:
			{
				printf("输入第一个子串\n");
				scanf("%s",s);
				StrAssign(&S1,s);
				printf("输入第二个的子串\n");
				scanf("%s",s);
				StrAssign(&S2,s);
				Contact(&T,S1,S2);
				printf("T=%s\n",T.ch);
				break;
			}
			case 11:
			{
				printf("输入第一个子串\n");
				scanf("%s",s);
				StrAssign(&S1,s);
				printf("输入第二个的子串\n");
				scanf("%s",s);
				StrAssign(&S2,s);
				printf("result=%d\n",StrCompare(S1,S2)); 
				break;
			}
			case 12:
			{
				printf("输入要复制的串\n");
				scanf("%s",s);
				StrCopy(&S,s);
				printf("S=%s\n",S.ch);
				break;
			}
        }  
 	}while(choice!=0);
    return 0;  
}  

4.链式存储

串也可以使用链式存储方式进行表示,每个结点可以存放多个字符。链表中的最后一个结点不一定全被串值占满,此时通常不上其他非串值字符。为方便串的连接操作,除头指针外还可附设一个尾指针指示链表中的最后一个结点。链式存储结构的操作与线性表类似,但总体上链式存储结构不如顺序存储结构灵活。


  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值