数据结构 串的定义,操作,表示和实现

本文介绍了串(字符串)的概念,包括串的定义、基本操作(赋值、比较、求长度、连接、子串),以及两种存储表示方法:定长顺序存储和堆分配存储。在C语言中,通过字符数组和动态内存分配实现串的操作。文中还提供了具体的代码示例,展示了如何实现串的连接和子串提取等操作。此外,讨论了在实现过程中可能遇到的问题,如内存分配和字符串结束标志的处理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

串的相关定义与概念

串也叫字符串,是由零个或多个字符组成的有限序列,形如 s = " a0a1​...an-1 ";其中 s 是串的名,双引号括起来的字符序列是串的值。字符可以是字母,数字,或其他字符。串中字符的数目 n 称为串的长度,零个字符的串为空串,它的长度为零。串中任意连续的字符称为串的子串,包含子串的称为对应的主串。子串在主串中的位置数值就等于子串中第一个字符在主串中前面的字符数量。两个串之间的比较,长度相等并且对应位置的数据元素也相同则两个字符串相等。若是不相等,则从第一个字符开始比较,谁大则所在的字符串较大。串值必须用双引号括起来,但双引号本身不属于串。如果字符全为空格,则为空格串。一个空格也占一个长度单位。

串的相关操作

串的基本操作集可以有不同的定义方法,各个版本的C语言都定义了自己的串操作函数。在使用高级程序设计语言中的串类型时,应以该语言的参考手册为准。

串的各种操作中,串赋值StrAssign,串比较StrCompare,求串长StrLength,串连接Concat 以及求子串SubString 这5种操作构成串类型的最小操作子集。即这些操作不能利用其他串操作来实现,反之,其他串操作可在这个最小操作子集上实现。例如定位函数Index如下:

int Index(String S, String T, int pos)
{
	//T为非空串。若主串S中第 pos 个字符之后存在与 T 相等的子串
	//则返回第一个这样的子串在S中的位置,否则返回-1
	int m, n;
	int i;
	if (pos >= 0)
	{
		n = StrLength(S);
		m = StrLength(T);
		i = pos;
		while (i <= n - m)
		{
			SubString(sub, S, i, m);            //求子串操作 
			if (StrCompare(sub, T) != 0)
				++i;
			else
				return i;
		}
	}
	return -1;         //S中不存在与T相等的子串
}

该算法的思想是:在串S中取从第 i (初值为pos) 个字符起,长度和串T相等的子串与串T进行比较,若相等,则返回 i ,否则 i 值增1,直至串 S 中不存在和串T长度相等的子串为止,则返回-1。

串的存储表示和实现

1.定长顺序存储表示

类似于线性表的顺序存储表示方法,可用一组地址连续的存储单元存储串值的字符序列。例如C语言中字符串的一种处理方式就是将字符串作为字符数组来处理。如:char str[10]; 但是最后要用\0作为字符串结束的标志。且 \0 占一位,定义数组长度时要加上,但是计算字符串长度时不计算在内。

#include<stdio.h>
#include<string.h>

void Concat_Sq(char S1[], char S2[], char T[])
{
	//用T返回由S1和S2连接而成的新串
	int j = 0, k = 0;
	while (S1[j] != '\0')
		T[k++] = S1[j++];         //复制S1
	j = 0;
	while (S2[j] != '\0')
		T[k++] = S2[j++];         //复制S2
	T[k] = '\0';                  //字符串结束标志   
}

int StrLength(char *S)
{
	return (strlen(S));
}

void SubString_Sq(char Sub[], char *S, int pos, int len)
{
	//用Sub返回串S的第pos个字符起往后长度为len的子串
	//其中,0<=pos<=StrLength(S) 且0<=len<=SteLength(S)-pos
	int slen = StrLength(S);         //求取顺序存储表示的字符串S的串长度
	int j;
	if (pos<0 || pos>slen - 1 || len<0 || len>slen - pos)
		printf("参数不合法!");
	for (j = 0; j < len; j++)
		Sub[j] = S[pos + j];          //向子串Sub复制字符
	Sub[len] = '\0';
}

void main()
{
	char S1[10] = "LXY";
	char S2[10] = "ILOVEU!";
	char T[20];
	char Sub[10];
	int pos = 1, len = 6;
	Concat_Sq(S1, S2, T);
	printf("字符串1:%s\n", S1);
	printf("字符串2:%s\n", S2);
	printf("连接后:%s\n", T);
	SubString_Sq(Sub, S2, pos, len);
	printf("字符串2从第%d个字符往后%d长度的子串为:%s\n",pos,len,Sub);
}

2,堆分配存储表示

由于实际操作中串的长度相差较大,并且串值长度的改变也比较大,所以一开始就给串变量设定固定大小空间的数组不尽合理。而堆分配存储表示串的特点是:串变量的存储空间是在程序执行过程中动态分配得到的,而其可用的存储空间是一个称之为”堆“的共享空间。利用操作符new动态分配内存空间。此时的串操作仍基于”字符序列的复制“进行。

#include<stdio.h>
#include<string.h>
#include<stdlib.h>


void StrInsert_HSq(char *S, int pos, char *T)
{
	//在串的第pos个字符之前插入串T 其中1<=pos<=StrLength(S)+1
	int i,j,k;
	int slen = strlen(S);
	int tlen = strlen(T);     //取原串长和插入串长
	char *S1;              //S1作为辅助空间暂存S
	S1 = new char[slen + 1];
	if (pos<1 || pos>slen + 1)
		printf("插入位置不合法!");
	if (tlen > 0)
	{
		//T非空则为S重新分配内存空间并插入T
		i = 0;
		while(S[i] != '\0')
		{
			S1[i] = S[i];    //暂存串S
			i++;
		}
		S1[i] = '\0';
		S = new char[tlen];       //为S重新分配内存空间
		for (i = 0, k = 0; i < pos - 1; i++)
			S[k++] = S1[i];           //保留插入位置之前的子串
		j = 0;
		while (T[j] != '\0')
			S[k++] = T[j++];
		while (S1[i] != '\0')
			S[k++] = S1[i++];
		S[k] = '\0';
	}
	printf("%s", S);
}

void main()
{
	char *str1,*str2;
	int len;
	str1 = new char;
	str2 = new char;
	printf("第一个串:");
	scanf("%s", str1);
	len = strlen(str1);
	printf("第二个串:");
	scanf("%s", str2);
	printf("在第一个串末尾插入第二个串后:");
	StrInsert_HSq(str1, len + 1, str2);
	
}

(以上程序写的时候遇到些卡顿点:1,对于new无法重新分配内存空间,只能是在原有空间基础上重新追加空间。2,realloc只能对应于malloc来使用。3,不管什么时候,复制一个字符串到另一个数组里面后一定一定一定要在末尾加上'\0';)

本笔记所依据的教材为严薇敏版的《数据结构及应用算法教程》

所有代码在Visual Studio 2017上均可正常运行

如有错误欢迎指出

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值