串string定义与操作

#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;//字符串长度
}


//初始化字符串/字符串赋值
//略

























评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值