#include<stdio.h>
#define MAXLENGTH 255//最大的字符串的长度
#define OK 1
#define ERROR 0
typedef int Status;//表示返回的状态值
typedef int ElemType;
/*
1、字符串有三种不同的表示方式
1. 定长顺序存储结构(数组Array固定形式),缺点为定长会有长度限制,以及插删的计算量比较大(插删需要平移数据)
2.堆分配存储结构(列表List形式)
3.链块存储结构(链表linklist形式)
2、C语言中字符串只能存在char数组中,并没有string类型,
而字符串常量“string”可以直接赋值给char*指针的变量,但是不能赋值给char[]的数组名(可以理解为数组名只是一个可读指针,但不可被赋值)
但是在初赋值时可以将常量直接赋给char数组,如char ch[]="string"; 同时char*p=ch;也成立
系统会在字符串后自动添加‘\0’字符表示字符串的结束
3、
4、
5、
*/
//串的定长顺序存储结构的结构体定义(类似列表list实现方式)
//即string 等于 unsigned char [MAXLENGTH+1]类型
typedef unsigned char String[MAXLENGTH+1];
//字符串的拼接算法
//将字符串S1和S2拼接到一起,并存放在T中
//O(n)
Status Concat(String &T,String S1,String S2)
{
int i,j;
if(S1[0]+S2[0]<=MAXLENGTH)//两个字符串之和小于最大容量
{
for(i=1,j=1;i<=S1[0];i++,j++)
{
T[j]=S1[i];
}
for(i=1;i<=S1[0]+S2[0];i++,j++)
{
T[j]=S2[i]
}
T[0]=S1[0]+S2[0];//合并长度
return OK;//合并成功没有溢出
}
else if(S1[0]<=MAXLENGTH)//需要对S2进行截取
{
for(i=1,j=1;i<=S1[0];i++,j++)
{
T[j]=S1[i];
}
for(i=1;i<=MAXLENGTH-S1[0];i++,j++)
{
T[j]=S2[i];
}
T[0]=255;
return ERROR;//合并以后长度超过界限,合并失败
}
else//需要对S1进行截取
{
for(i=1;i<=255;i++)
{
T[i]=S[i];
}
T[0]=255;
return ERROR;//合并失败,超过字符串的长度
}
}
//得到字符串的特定位置和特定长度的子串
//O(len)
Status SubString(String S,String &sub,int pos,int len)
{
int i,j;
if(pos+len-1>S[0]||pos<1||len<0)
{
return ERROR;//截取范围溢出
}
for(i=1,j=pos;i<=len;i++)
{
sub[i]=S[j];
}
sub[0]=len;
return OK;
}
//对子串进行检索与匹配(串的模式匹配)
//从pos位开始检索
//最坏的时间复杂度是O(S[0]*sub[0]),该算法在有些情况下效率极低
int StringIndex(String S,String sub,int pos)
{
int i=pos;j=1;
while(i<=S[0]&&j<=sub[0])
{
if(S[i]==sub[j])
{
j++;//前一个匹配成功则往前进一步
}
else
{
i-=(j-1);//若匹配不成功,则退回原点
j=1;//重置J
}
i++;
}
if(j>sub[0])
{
return i-(j-1);
}
return 0;
}
//串的模式匹配KMP算法
//优点为匹配到某一位失败后不需要回溯到最开始匹配成功的位置,直接利用已经匹配的信息(模式串自身信息)
//来继续向前匹配。但模式串自身信息需要用一个next[]数组求得。
//时间复杂度为O(S[0]+sub[0])
int StringIndexKMP(String S,String sub,int pos)
{
int i=pos,j=1;
while(i<=S[0]&&j<=sub[0])
{
if(S[i]==sub[j]||j==0)//如果匹配成功接着匹配下一位,当next[j]=0时也前进一位
{
i++;
j++;
}
else
{
j=next[j];//若匹配失败S[i]就从sub的next[j]的位置开始新的匹配
}
}
if(j>sub[0])
{
return i-j+1;//返回匹配成功的位置
}
return 0;//未找到
}
void GetNext(String sub,int next[])//数组为引用类型,因此不需要&。next数组长度与字符串长度一致
{
int i=1,j=0;
next[1]=0;//第一位匹配失败为0表示向前进一位
while(i<=sub[0])
{
if(j==0||T[i]==T[j])
{
i++;
j++;
next[i]=j;
}
else
j=next[j];
}
}
//----------------------------------------------------------------------------
//字符串的堆分配存储结构的定义
//类似于列表的定义。可以实现无限制长度的字符串,但插删比较慢
typedef struct
{
char *ch;//指向字符串存放地址
int length;
}String;
//为字符串变量分配字符串
//由于C中没有字符串类型,因此用char指针来接收字符串变量
//c中字符串结尾用'\0',在该string类型中不需要这个字符表示结尾,直接显示记录字符串长度
//O(n)
Status StringAssign(String &S,char* chars)
{
int i;
char *p;
if(S.ch)
{
free(S.ch);
}
//循环求字符串长度
for(i=0,p=chars;*p;i++,p++);//当*p为'\0'字符时,退出循环,i记录字符串长度
//判断是否是空字符串
if(i==0)
{
S.ch=NULL;//指空避免错误
S.length=0;
return OK
}
//开辟内存
S.ch=(char*)malloc(i*sizeof(char));
if(!S.ch)
{
exit(OVERFLOW);
}
//更新长度
S.length=i;
for(;i>=0;i--)
{
S.ch[i]=chars[i];
}
return OK;
}
//求字符串长度
//O(1)
int StringLength(String S)
{
return S.length;//若未被字符串赋值则返回的是NULL
}
//字符串的插入(将字符串T插入到字符串S的pos位置之前)
//O(T.length+S.length-pos+1)
Status StringInsert(String &S,String T,int pos)
{
int i,p;
if(pos>S.length+1||pos<1)
{
return ERROR;//超出插入范围
}
if(T.length==0)
{
return OK;//不需平移插入
}
S.ch=(char*)realloc(S.ch,(S.length+T.length)sizeof(char));//重新开辟内存
if(!S.ch)
{
exit(OVERFLOW);
}
for(i=0,p=S.length-1;i<S.length-pos+1;i++,p--)//平移数据
{
S.ch[p]=S.ch[p+T.length];
}
for(i=0,p=pos;i<T.length;i++,p++)//插入字符串T
{
S.ch[p]=T.ch[i];
}
S.length+=T.length;//更新长度
return OK;
}
//字符串的比较函数
//比较方法是从第一位开始逐个比较大小,相等则比较下一位
//大于为正,等于为0,小于为负
//O(min(S.length,T.length))
int CompareString(String S,String 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 S.length-T.length;//若之前的字符比较相同则比较长度
}
//清除字符串
//clear与destroy的区别在于clear是恢复到初始化之后,而destroy是之前
//O(1)
Status ClearString(String &S)
{
if(!S.ch)
{
free(S.ch);
S.ch=NULL;//free不会将ch置为NULL
}
S.length=0;
return OK;
}
//连接两个字符串
//将连接后的字符串存在S中
Status Concat(String &S,String T1,String T2)
{
int i;
free(S.ch);
//重新开辟内存,若是直接指针指向T1的话,会将S与T1关联到一起
S.ch=(char*)malloc((T1.length+T2.length)*sizeof(char));
if(S.ch)
{
exit(OVERFLOW);
}
for(i=0;i<T1.length;i++)
{
S.ch[i]=T1.ch[i];
}
for(i=0;i<T2.length;i++)
{
S.ch[i+T1.length]=T2.ch[i];
}
S.length=T1.length+T2.length;
return OK;
}
//给定位置和长度求子串
//
Status SubString(String S,String &sub,int pos,int len)
{
int i;
if(pos+len-1>S.length||pos<1||len<1)
{
return ERROR;
}
if(sub.ch)
{
free(sub.ch);
}
sub.ch=(char*)malloc(len*sizeof(char));
if(sub.ch)
{
exit(OVERFLOW);
}
for(i=0;i<len;i++)
{
sub.ch[i]=S.ch[i+pos-1];
}
sub.length=len;
return OK;
}
//------------------------------------------------------------------------
#define SIZE 30//一个链结点存放的数据大小
//链块存储结构的结构体表示
//数据结点的结构体定义
typedef struct Chunk
{
char ch[SIZE];//存放字符串块
Chunk *next;
}Chunk;
//字符串链表表头结构体定义
typedef struct
{
Chunk *head;//指向头结点,头结点不存储数据,头结点指向的结点才是第一个结点(存数据的)
Chunk *rear;//指向尾结点,有利于联结concat操作
int length;//字符串长度
}
//初始化字符串/字符串赋值
//略
串string定义与操作
最新推荐文章于 2023-10-14 23:30:38 发布