串讲解

串

串的类型定义
串是由零个或多个字符组成的有限序列,串中字符的数目n称为串的长度。
零个字符的串称为空串,它的长度为零
串中任意个连续的字符组成的子序列称为串的子串,包含子串的串称主串
通常称字符在序列中的序号为该字符在串中的位置
称两个串是相等的,当且仅当这两个串的值相等,即对应位置字符相同,长度相同
NOTE 串值必须用单引号括起来,但是单引号并不属于串
串的常见基本操作由查找子串,求取子串,插入及删除子串等

串的表示和实现
串有3种机内表示方法
1----定长顺序存储表示
用一组连续地址的存储单元存储,可用数组描述
#define MAXSTRLEN 100
typedef unsigned char SString[MAXSTRLEN + 1];  //0号单元存放串长
1 串联接
Status Concat(SString &T, SString S1, SString S2)
{
	//用T返回S1 S2串联的串--超长部分截断
	if (S1[0] + S2[0] <= MAXSTRLEN)     //未截断
	{
		T[0] = S1[0] + S2[0];
		for (int i = 1; i < T[0]; i++)
		{
			if (i <= S1[0])
				T[i] = S1[i];
			else
				T[i] = S2[i - S1[0]];
		}
	}
	else if (S1[0]<MAXSTRLEN&&S1[0] + S2[0]>MAXSTRLEN)  //截断S2
	{
		T[0] = MAXSTRLEN;
		for (int i = 1; i < MAXSTRLEN; i++)
		{
			if (i <= S1[0])
				T[i] = S1[i];
			else
				T[i] = S2[i - S1[0]];
		}
	}
	else   //截断S1
	{
		for (int i = 1; i < S1[0]; i++)
			T[i] = S1[i];
	}
}

2 求子串
求子串的过程即为复制字符序列的过程,将串S从第pos个字符开始长度为len的字符序列复制到串Sub种
当用户给出初始参数非法时返回ERROR
Status SubString(SString &Sub, SString S, int pos, int len)
{
	//用Sub返回串S的第pos个字符起长度为len的子串
	if (pos<1 || pos>S[0] || len<0 || len>S[0] - pos + 1)
		return ERROR;

	for (int i = pos; i - pos < len; i++)
	{
		Sub[i - pos+1] = S[i];
	}
	Sub[0] = len;

	return OK;
}



2----堆分配存储表示
存储空间在程序执行过程中动态分配
typedef struct {
	char *ch;
	int len;      //串长
}HString;
这种种存储结构表示时的串操作仍然是基于字符序列的复制进行的,大体和上面一种相同,只是空间的利用更加灵活
Status StrInsert(HString &S, int pos, HString T)
{
	//1<=pos<=StrLength(S)+1   在串的第pos个字符之前插入串T
	if (pos<1 || pos>S.len + 1)
		return ERROR;

	if (T.len)
	{
		S.ch = (char *)realloc(S.ch, (S.len + T.len) * sizeof(char));
		if (!S.ch)
			exit(0);
		for (int i = S.len - 1; i >= pos - 1; --i)
			S.ch[i + T.len] = S.ch[i];
		for (int i = pos - 1; i < T.len; i++)
			S.ch[i] = T.ch[i - pos + 1];
		S.len = S.len + T.len;
	}

	return OK;
}

//堆串的基本操作
typedef struct {
	char *ch;
	int len;
}HString;

Status StrAssign(HString &T, char *chars)
{
	//生成一个其值等于串常量chars的串T
	if (T.ch)
		free(T.ch);   //释放T原有空间
	T.len = strlen(chars);
	T.ch = (char *)malloc(sizeof(char)*T.len);
	if (!T.ch)
		exit(0);

	for (int i = 0; i < T.len; i++)
		T.ch[i] = chars[i];

	return OK;
}


Status ClearString(HString &S)
{
	//将S清为空串
	if (S.ch)
	{
		free(S.ch);;
		S.ch = NULL;
	}
	S.len = 0;

	return OK;
}


3--串的块链表示
采用链式存储串值
运用链式结构时,由于串的结构,存在一个结点大小的问题,即一个结点要存放多少个字符
当一个结点并非存放一个字符时,串长则不一定是结点大小的整数倍,最后的结点不一定全被串值占满,可以补上'#'等其他字符
为了便于操作,除头指针外还可附设一个尾指针指示链表种的最后一个结点
#define CHUNKSIZE 100
typedef struct Chunk{
	char ch[CHUNKSIZE];
	struct Chunk *next;
}Chunk;
typedef struct {
	Chunk *head, *tail;     //串的头尾指针
	int curlen;             //串的当前长度
}LString;

在一般情况下,对串操作时,只需要从头向尾顺序扫描即可,一般不需要双向链表,设尾指针的目的是为了便于进行连接操作
但应注意连接时需处理第一个串尾的无效字符
存储密度=串值所占存储位/实际分配存储位
链式结构的串的操作类似线性表的操作



串的模式匹配算法
1 求子串位置的定位函数Index(S,T,pos)
子串的定位操作通常称为串的模式匹配(其中T称为模式串)
//采用定长顺序存储结构
int Index(SString S, SSting T, int pos)
{
	//返回子串T在主串S中第pos个字符之后的位置,若不存在返回值为零
	int loc = pos;
	int count = 0;
	for (int i = pos; i < S[0]; i++)
	{
		for (int j = 1; j < T[0]; j++)
		{
			if (T[j] == S[i])
			{
				count++;
			}
			else
			{
				loc++;
				count = 0;
				break;
			}
		}
		if (count == T[0])
			return loc;
	}
	
	return 0;
}
//示例代码
int Index(SString S, SSting T, int pos)
{
	//返回子串T在主串S中第pos个字符之后的位置,若不存在返回值为零
	int i = pos;
	int j = 1;
	while (i <= S[0] && j <= T[0])
	{
		if (S[i] == T[j])
		{
			++i;             //继续比较后续字符
			++j;
		}
		else
		{
			i = i - j + 2;        //退回指针重新匹配
			j = 1;
		}
	}

	if (j > T[0])
		return i - T[0];
	else
		return 0;
}



KMP匹配
相较于上个匹配算法,该算法改进在于:每一趟匹配过程中出现字符比较不等时,不需回溯i指针,而是利用已经得到的部分匹配的结果,将模式向右
滑动尽可能远的一段距离后,继续进行比较
int Index_KMP(SString S, SString T, int pos)
{
	//利用模式串T的next函数求T在主串S中第pos个字符之后的位置,其中T非空,1<=pos<=StrLength(S)
	int i = pos;
	int j = 1;
	while (i <= S[0] && j <= T[0])
	{
		if (j == 0 || S[i] == T[j])
		{
			i++;                      //继续比较后继字符
			j++;
		}
		else                 //模式串向右移动
			j = next[j];
	}

	if (j > T[0])            //匹配成功
		return i - T[0];
	else
		return 0;
}
问题:如何求得模式串的next值
next值与主串无关而仅取决于模式串本身,分析定义用递推的方法求next函数值
void get_next(SString T, int next[])
{
	//求模式串T的next函数值并存入数组next
	int i = 1;
	next[1] = 0;
	int j = 0;
	while (i < T[0])
		if (j == 0 || T[i] == T[j])
		{
			i++;
			j++;
			next[i] = j;
		}
		else
			j = next[j];
}




算法来源--大话数据结构

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值