• 数据结构 | 串的存储结构之链串


    在这里插入图片描述

    本文,大家带来数据结构中串的存储结构之链串,了解其基本实现及算法

    🌳结构声明

    对于链串,与单链表比较类似,其结构声明如下

    typedef struct snode {
    	char data;
    	struct snode* next;
    }LinkStrNode;
    
    • 1
    • 2
    • 3
    • 4
    • 也是需要一个数据域,然后既然是链式结构,那一定有指针

    🌳分步算法实现分析【⭐⭐⭐】

    对于链串的算法实现,不像顺序串那样简便,你需要去开辟结点空间然后将一个个结点链接起来

    🍃生成串

    • 首先我们来看如何使用链式思维去实现一个串
    • 参数的话还是一样,一个链串类型,一个字符数组,上面说了,形成一个链串需要链式思维,那对于链表我们是怎么构建的呢?大家还记得吗,使用尾插法会来的更加好一些,因此我们下面的算法操作都是基于尾插法的来实现的,我来一步步给大家说一下
    • 首先你需要定义一个头结点指针,用于头结点的存储,然后在定义一个新生结点的指针,用于存放后续结点。接着就是尾插法的基本思路,使用【malloc】开辟空间,一开始只有一个头结点,因此它就是尾结点
    • 接着取遍历这个字符数组,取出里面的每一个字符,为新的结点开辟空间,然后将字符一一放入data域,将此结点链在尾结点后,然后这个结点成为新的尾结点
    • 最后不要忘了将尾结点的next域置为空哦,这很重要❗
    void StrAssign(LinkStrNode*& s, char cstr[])
    {
    	LinkStrNode* r, * p;
    	//为头结点开辟空间
    	s = (LinkStrNode*)malloc(sizeof(LinkStrNode));
    	r = s;
    	for (int i = 0; cstr[i] != '\0'; ++i)
    	{
    		//为串s的后继结点开辟空间
    		p = (LinkStrNode*)malloc(sizeof(LinkStrNode));
    		p->data = cstr[i];
    		//尾插法
    		r->next = p;	r = p;
    	}
    	r->next = NULL;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    🍃销毁串

    • 然后来说说如何销毁一个串,这和销毁链表其实是一个道理。
    • 你要销毁一个结点,那就要判断它的下一个结点是否为空,若是不为空,就进入循环,下一个结点不为空,就free掉这个结点,然后进行一个交替更换,直至扫描完所有的结点位置
    • 最后别忘了当扫描到最后一个尾结点的时候,跳出循环要单独再做一个free
    void DestroyStr(LinkStrNode*& s)
    {
    	LinkStrNode* pre = s, * p = s->next;
    	while (p != NULL)
    	{
    		free(pre);
    		pre = p;
    		p = pre->next;
    	}
    	free(pre);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    🍃串的复制

    • 首先一样,是基于尾插法的整体思路,可以看到,这里是给目标串s做了一个引用,所以是要将串t复制到串s中去。
    • 接着取思考一下我们的需求,我们需要一个头结点现将串s放进去,然后需要一个结点指针去扫描复制串t的,然后对于新增加的结点,还需要一个新增结点指针
    • 接下去就是算法思路,具体不做讲解,与生成串一致。就是这个【q->data = p->data】,就是将p中即扫描的串t的内容放到新生结点中
    void StrCopy(LinkStrNode*& s, LinkStrNode* t)
    {
    	LinkStrNode* r, * p = t->next, * q;
    	//为头结点开辟空间
    	s = (LinkStrNode*)malloc(sizeof(LinkStrNode));
    	r = s;
    	while (p != NULL)
    	{
    		q = (LinkStrNode*)malloc(sizeof(LinkStrNode));
    		q->data = p->data;		//将串t中的结点放入q中暂存
    
    		r->next = q;
    		r = q;			//尾插法
    
    		p = p->next;
    	}
    	r->next = NULL;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    🍃判断两个串是否相等

    • 然后去比较两个串是否相等,思路很简单,我们来看看
    • 首先你需要两个指针,一个指向串s的内容,另一个指向串t的内容。接着将它们放到一个循环里分别去扫描即可,若是相等的话继续向下扫描,直至尾结点位置,其中若是发现 有不相同的元素,则跳出循环
    • 在循环外面,可以看到我是有两个判断,一个是判断是否两个指针都扫描到了两个串的尾部,若是,则表明两个串是相等匹配的,返回true;若不是,则表明上面的循环是中途结束的,指针并没有扫描到结尾,返回false
    bool StrEqual(LinkStrNode* s, LinkStrNode* t)
    {
    	LinkStrNode* p = s->next, * q = t->next;
    	while (p != NULL && q != NULL && p->data == q->data)
    	{
    		p = p->next;
    		q = q->next;
    	}
    	if (p == NULL || q == NULL)		//表明此时已经扫描到串尾
    		return true;
    	else
    		return false;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    🍃求串的长度

    • 求解串的长度一样是和链表一样,从首结点开始扫描,使用循环控制,直至尾结点即可,使用一个变量记录循环次数,最后返回
    int StrLength(LinkStrNode* s)
    {
    	int i = 0;
    	LinkStrNode* p = s->next;
    	while (p != NULL)
    	{	
    		i++;
    		p = p->next;
    	}
    	return i;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    🍃连接两个串

    • 连接串的思路其实和顺序串一致,也是先定一个存储串,然后先将串s放入,接着再将串t做一个链接
    • 一样分析一下需求:存放结果串的指针、存放串s的指针、新建的结点指针以及尾指针
    • 内部思路就是尾插法的思路,便不做过多叙述。这里的话就是将这个一开始存放串s的指针p做了一个再次利用
    LinkStrNode* ConCat(LinkStrNode* s, LinkStrNode* t)
    {
    	LinkStrNode* str, * p, * q, * r;
    	str = (LinkStrNode*)malloc(sizeof(LinkStrNode));
    	r = str;
    	//先将s存放到str中
    	p = s->next;
    	while (p != NULL)
    	{
    		q = (LinkStrNode*)malloc(sizeof(LinkStrNode));
    		q->data = p->data;
    
    		r->next = q;	r = q;
    
    		p = p->next;
    	}
    	//再循环利用变量将t也存入str中,即接在s之后
    	p = t->next;
    	while (p != NULL)
    	{
    		q = (LinkStrNode*)malloc(sizeof(LinkStrNode));
    		q->data = p->data;
    
    		r->next = q;	r = q;
    
    		p = p->next;
    	}
    	r->next = NULL;
    	return str;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    接下去又开始了我们的“烧脑部分”,做好准备🌊

    🍃取子串

    • 然后是取子串的部分,一样需要先去判断要取出的子串是否合法,若不合法,直接返回定义出来的空串即可
    • 这里也是一样先使用指针p存放串s的内容,接着使用循环去遍历,但这还是用到了一个技巧,因为要取的子串是从位置i开始,那么直接使用循环遍历到了这个地方,然后的话其实就又是一个尾插法的操作,从这个位置开始,将s串中的部分一一存放到串str中,最后将尾指针置为空,返回即可
    LinkStrNode* SubStr(LinkStrNode* s, int i, int j)
    {
    	LinkStrNode* str, * p, * q, * r;
    	str = (LinkStrNode*)malloc(sizeof(LinkStrNode));
    	str->next = NULL;		//若不将str置为空串,则输入放入会出现异常
    	r = str;
    	
    	if (i <= 0 || i > StrLength(s) || j < 0 || i - 1 + j > StrLength(s))
    		return str;
    	//利用指针p先行遍历到位置i
    	p = s->next;
    	for (int k = 1; k < i; ++k)
    		p = p->next;
    	//在从位置i开始遍历到位置j取出子串
    	for (int k = 1; k <= j; ++k)
    	{
    		q = (LinkStrNode*)malloc(sizeof(LinkStrNode));
    		q->data = p->data;
    
    		r->next = q;	r = q;
    
    		p = p->next;
    	}
    	r->next = NULL;
    	return str;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    🍃在串1指定位置插入串2

    • 一样,也是顺序串的思路,先将前半部分放到目标串中,然后在后插入串,接着将后半部分继续放入即可
    • 指针数量还是一样,只是多了一个指针去遍历插入串t,细心的同学在看了上篇文章后,一定也发现了这里也使用了边界条件的判断,上次我们说过,这个插入串的话是可以插入到一个串的末尾的,所以是其长度length + 1,但是超出就不行了
    • 接着三步走,完成插入操作
    • 第一步,将串s的前半部分,也就是从1遍历到i - 1的位置,一样使用尾插法插入
    • 第二步,串s的前半部分插入完成后,使用指针p1继续去遍历串t,一样的思路放入串str中
    • 第三步,放入串s的后半部分,被忘了,此时这个指针p还在i的位置,只需要继续使用这个指针p,利用尾插法插入即可
    LinkStrNode* InsStr(LinkStrNode* s, int i, LinkStrNode* t)
    {
    	int k = 1;
    	LinkStrNode* str, * p, * p1, * q, * r;
    	str = (LinkStrNode*)malloc(sizeof(LinkStrNode));
    	str->next = NULL;
    	r = str;
    	//判断下标i是否越界
    	if (i <= 0 || i > StrLength(s) + 1)
    		return str;
    	
    	//利用指针p,先将前0~i-1个字符存入str
    	p = s->next;
    	for (int k = 1; k < i; ++k)
    	{
    		q= (LinkStrNode*)malloc(sizeof(LinkStrNode));
    		q->data = p->data;
    		r->next = q;	r = q;
    		p = p->next;
    	}
    
    	//利用指针p1,将串t中的结点顺势放入str中
    	p1 = t->next;
    	while (p1 != NULL)
    	{
    		q = (LinkStrNode*)malloc(sizeof(LinkStrNode));
    		q->data = p1->data;
    		r->next = q;	r = q;
    		p1 = p1->next;
    	}
    
    	//此时的指针p,已然移动到i的位置,开始将后面的剩余结点继续存入串str中
    	while (p != NULL)
    	{
    		q = (LinkStrNode*)malloc(sizeof(LinkStrNode));
    		q->data = p->data;
    		r->next = q;	r = q;
    		p = p->next;
    	}
    	r->next = NULL;
    	return str;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42

    🍃删除一个串中指定长度的串

    • 不要看代码越来越长,其实这就是【纸老虎】,实现的思路还是很简单,内部的原理都是使用尾插法,只需要在外层控制一下指针的移动即可
    • 首先一样先来看一下这个边界的判断,顺序串中说过,插入串不需要判断长度,但是删除需要,还有就是这个边界条件,目标串的最后部分是不可以被删除的,因为根本没有内容可以给你删
    • 删除操作,一样是现将前i个字符放入目标串中,接着我们再度利用指针p,通过一个循环,将这j个位置直接遍历过。循环结束时,p就处于j的位置,然后利用这个指针将剩余的内容放入目标串中即可
    LinkStrNode* DelStr(LinkStrNode* s, int i, int j)
    {
    	int k = 1;
    	LinkStrNode* str, * p, * q, * r;
    	str = (LinkStrNode*)malloc(sizeof(LinkStrNode));
    	str->next = NULL;
    	r = str;
    
    	if (i <= 0 || i > StrLength(s) || i - 1 + j > StrLength(s))
    		return str;
    	//利用指针p,先将前0~i-1个字符存入str
    	p = s->next;
    	for (int k = 1; k < i; ++k)
    	{
    		q = (LinkStrNode*)malloc(sizeof(LinkStrNode));
    		q->data = p->data;
    		r->next = q;	r = q;
    		p = p->next;
    	}
    
    	//再利用指针p,直接遍历过j个位置
    	for (k = 0; k < j; ++k)
    		p = p->next;
    	//此时的指针p,已然移动到j的位置,开始将后面的剩余结点继续存入串str中
    	while (p != NULL)
    	{
    		q = (LinkStrNode*)malloc(sizeof(LinkStrNode));
    		q->data = p->data;
    		r->next = q;	r = q;
    		p = p->next;
    	}
    	r->next = NULL;
    	return str;
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35

    🍃将一个串中从某一位置开始的指定长度替换为另一个串

    • 一眼望去代码很长,你会怕吗?要记住这只是【纸老虎】罢了
    • 顺序串里也说到过,替换串的操作和插入串很像,你也可以再拉上去看看,是不是真的很像
    • 你可以进行一个对比,然后就可以发现,又是插入和删除两个算法操作的结合
    • 对于替换串来说,和删除串一样,超过length + 1的位置是不可以替换的,替换串的话不想插入串那样,不要考虑长度,替换的话肯定是要考虑你所使用的替换串的长度
    • 替换操作的整体思路也会差不多,利用指针做一个后移,内部实现逻辑还是尾插法,如果你认真看了上面的内容,相信你对这一个算法不会陌生,自己分析着试试吧😀
    LinkStrNode* RepStr(LinkStrNode* s, int i, int j, LinkStrNode* t)
    {
    	int k = 1;
    	LinkStrNode* str, * p, * p1, * q, * r;
    	str = (LinkStrNode*)malloc(sizeof(LinkStrNode));
    	str->next = NULL;
    	r = str;
    	//判断下标i是否越界
    	if (i <= 0 || i > StrLength(s) || j<0 || i - 1 + j>StrLength(s))
    		return str;
    
    	//利用指针p,先将前0~i-1个字符存入str
    	p = s->next;
    	for (int k = 1; k < i; ++k)
    	{
    		q = (LinkStrNode*)malloc(sizeof(LinkStrNode));
    		q->data = p->data;	 q->next = NULL;
    		r->next = q;	r = q;
    		p = p->next;
    	}
    
    	for (k = 0; k < j; ++k)
    		p = p->next;		//直接删除原本串s中从第i位开始长度为j的那一子串
    
    	//利用指针p1,将串t中的结点顺势放入str中
    	p1 = t->next;
    	while (p1 != NULL)
    	{
    		q = (LinkStrNode*)malloc(sizeof(LinkStrNode));
    		q->data = p1->data;	 q->next = NULL;
    		r->next = q;	r = q;
    		p1 = p1->next;
    	}
    
    	//此时的指针p,已然移动到i的位置,开始将后面的剩余结点继续存入串str中
    	while (p != NULL)
    	{
    		q = (LinkStrNode*)malloc(sizeof(LinkStrNode));
    		q->data = p->data;	 q->next = NULL;
    		r->next = q;	r = q;
    		p = p->next;
    	}
    	r->next = NULL;
    	return str;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45

    🍃输出串

    • 如下是输出串的算法
    void DispStr(LinkStrNode* s)
    {
    	LinkStrNode* p = s->next;
    	while (p != NULL)
    	{
    		printf("%c", p->data);
    		p = p->next;
    	}
    	printf("\n");
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    🌳测试运行结果

    🐚测试1

    测试这一块,也是一样,分为两部分,我们先来看第一部分的测试

    void test1()
    {
    	printf("*测试串的生成*\n");
    	LinkStrNode* s1;
    	char ch1[12] = "Hello World";
    	StrAssign(s1, ch1);
    	printf("串s初始化为:");
    	DispStr(s1);
    
    	printf("\n*测试串的复制*\n");
    	LinkStrNode* s2;
    	char ch2[6] = "Frank";
    	StrAssign(s2, ch2);
    
    	StrCopy(s1, s2);
    	printf("复制后的串s1为:");
    	DispStr(s1);
    
    	printf("\n*测试串是否相等*\n");
    	LinkStrNode* s3, * s4, * s5;
    	char ch3[6] = "apple";
    	char ch4[6] = "apple";
    	char ch5[7] = "banana";
    	StrAssign(s3, ch3);
    	StrAssign(s4, ch4);
    	StrAssign(s5, ch5);
    	if (StrEqual(s3, s4))
    		printf("s3与s4两串相等\n");
    	else
    		printf("s3与s4两串不相等\n");
    
    	if (StrEqual(s3, s5))
    		printf("s3与s5两串相等\n");
    	else
    		printf("s3与s5两串不相等\n");
    
    	printf("\n*测试串的长度*\n");
    	int len = StrLength(s5);
    	printf("显示一下串s5:");
    	DispStr(s5);
    	printf("串s5的长度为:%d\n", len);
    
    	printf("\n*测试串的连接*\n");
    	LinkStrNode* s6;
    	LinkStrNode* s7;
    	LinkStrNode* s8;
    	char ch6[3] = "so";
    	char ch7[6] = " good";
    	StrAssign(s6, ch6);
    	StrAssign(s7, ch7);
    	s8 = ConCat(s6, s7);
    	printf("串s6与串s7连接之后为:");
    	DispStr(s8);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54

    在这里插入图片描述

    • 还是一样,大家自己对照我的测试过程看,非常清晰

    🐚测试2

    然后开始第二个测试

    void test2()
    {
    	printf("*测试求子串*\n");
    	LinkStrNode* s1, * s2;
    	char ch1[10]= "wonderful";
    	StrAssign(s1, ch1);
    	printf("初始化的串s1为:");
    	DispStr(s1);
    	printf("串s1从第2个字符开始的连续4个字符的子串为:");
    	s2 = SubStr(s1, 2, 4);
    	DispStr(s2);
    
    	printf("\n*测试子串的插入*\n");
    	LinkStrNode* s3,* s4;
    	char ch3[10] = "ok";
    	StrAssign(s3, ch3);
    
    	printf("在串s1的第3个位置插入串s3之后为:");
    	s4 = InsStr(s1, 3, s3);
    	DispStr(s4);
    
    	printf("\n*测试子串的删除*\n");
    	LinkStrNode* s5, * s6;
    	char ch5[10] = "fantistic";
    	StrAssign(s5, ch5);
    	
    	printf("将串s5的第5个字符开始的长度为2的子串删除后为:");
    	s6 = DelStr(s5, 5, 2);
    	DispStr(s6);
    
    	printf("\n*测试子串的替换*\n");
    	LinkStrNode* s7;
    	LinkStrNode* s8;
    	LinkStrNode* s9;
    	char ch7[15] = "accountability";
    	char ch8[3] = "le";
    	StrAssign(s7, ch7);
    	StrAssign(s8, ch8);
    
    	printf("将串s7从第10个字符开始的长度为2的子串替换成s8后为:");
    	s9 = RepStr(s7, 10, 5, s8);
    	DispStr(s9);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43

    在这里插入图片描述

    🌳整体代码展示

    #include 
    #include 
    
    typedef struct snode {
    	char data;
    	struct snode* next;
    }LinkStrNode;
    
    /*生成串*/
    void StrAssign(LinkStrNode*& s, char cstr[])
    {
    	LinkStrNode* r, * p;
    	//为头结点开辟空间
    	s = (LinkStrNode*)malloc(sizeof(LinkStrNode));
    	r = s;
    	for (int i = 0; cstr[i] != '\0'; ++i)
    	{
    		//为串s的后继结点开辟空间
    		p = (LinkStrNode*)malloc(sizeof(LinkStrNode));
    		p->data = cstr[i];
    		//尾插法
    		r->next = p;	r = p;
    	}
    	r->next = NULL;
    }
    
    /*摧毁串*/
    void DestroyStr(LinkStrNode*& s)
    {
    	LinkStrNode* pre = s, * p = s->next;
    	while (p != NULL)
    	{
    		free(pre);
    		pre = p;
    		p = pre->next;
    	}
    	free(pre);
    }
    
    /*串的复制*/
    void StrCopy(LinkStrNode*& s, LinkStrNode* t)
    {
    	LinkStrNode* r, * p = t->next, * q;
    	//为头结点开辟空间
    	s = (LinkStrNode*)malloc(sizeof(LinkStrNode));
    	r = s;
    	while (p != NULL)
    	{
    		q = (LinkStrNode*)malloc(sizeof(LinkStrNode));
    		q->data = p->data;		//将串t中的结点放入q中暂存
    
    		r->next = q;
    		r = q;			//尾插法
    
    		p = p->next;
    	}
    	r->next = NULL;
    }
    
    /*判断串相等*/
    bool StrEqual(LinkStrNode* s, LinkStrNode* t)
    {
    	LinkStrNode* p = s->next, * q = t->next;
    	while (p != NULL && q != NULL && p->data == q->data)
    	{
    		p = p->next;
    		q = q->next;
    	}
    	if (p == NULL || q == NULL)		//表明此时已经扫描到串尾
    		return true;
    	else
    		return false;
    }
    /*求串长*/
    int StrLength(LinkStrNode* s)
    {
    	int i = 0;
    	LinkStrNode* p = s->next;
    	while (p != NULL)
    	{	
    		i++;
    		p = p->next;
    	}
    	return i;
    }
    
    /*串的连接*/
    LinkStrNode* ConCat(LinkStrNode* s, LinkStrNode* t)
    {
    	LinkStrNode* str, * p, * q, * r;
    	str = (LinkStrNode*)malloc(sizeof(LinkStrNode));
    	r = str;
    	//先将s存放到str中
    	p = s->next;
    	while (p != NULL)
    	{
    		q = (LinkStrNode*)malloc(sizeof(LinkStrNode));
    		q->data = p->data;
    
    		r->next = q;	r = q;
    
    		p = p->next;
    	}
    	//再循环利用变量将t也存入str中,即接在s之后
    	p = t->next;
    	while (p != NULL)
    	{
    		q = (LinkStrNode*)malloc(sizeof(LinkStrNode));
    		q->data = p->data;
    
    		r->next = q;	r = q;
    
    		p = p->next;
    	}
    	r->next = NULL;
    	return str;
    }
    
    /*求子串*/
    LinkStrNode* SubStr(LinkStrNode* s, int i, int j)
    {
    	LinkStrNode* str, * p, * q, * r;
    	str = (LinkStrNode*)malloc(sizeof(LinkStrNode));
    	str->next = NULL;		//若不将str置为空串,则输入放入会出现异常
    	r = str;
    	
    	if (i <= 0 || i > StrLength(s) || j<0 || i - 1 + j>StrLength(s))
    		return str;
    	//利用指向p先行遍历到位置i
    	p = s->next;
    	for (int k = 1; k < i; ++k)
    		p = p->next;
    	//在从位置i开始遍历到位置j取出子串
    	for (int k = 1; k <= j; ++k)
    	{
    		q = (LinkStrNode*)malloc(sizeof(LinkStrNode));
    		q->data = p->data;
    
    		r->next = q;	r = q;
    
    		p = p->next;
    	}
    	r->next = NULL;
    	return str;
    }
    
    /*子串的插入*/
    LinkStrNode* InsStr(LinkStrNode* s, int i, LinkStrNode* t)
    {
    	int k = 1;
    	LinkStrNode* str, * p, * p1, * q, * r;
    	str = (LinkStrNode*)malloc(sizeof(LinkStrNode));
    	str->next = NULL;
    	r = str;
    	//判断下标i是否越界
    	if (i <= 0 || i > StrLength(s) + 1)
    		return str;
    	
    	//利用指针p,先将前0~i-1个字符存入str
    	p = s->next;
    	for (int k = 1; k < i; ++k)
    	{
    		q= (LinkStrNode*)malloc(sizeof(LinkStrNode));
    		q->data = p->data;
    		r->next = q;	r = q;
    		p = p->next;
    	}
    
    	//利用指针p1,将串t中的结点顺势放入str中
    	p1 = t->next;
    	while (p1 != NULL)
    	{
    		q = (LinkStrNode*)malloc(sizeof(LinkStrNode));
    		q->data = p1->data;
    		r->next = q;	r = q;
    		p1 = p1->next;
    	}
    
    	//此时的指针p,已然移动到i的位置,开始将后面的剩余结点继续存入串str中
    	while (p != NULL)
    	{
    		q = (LinkStrNode*)malloc(sizeof(LinkStrNode));
    		q->data = p->data;
    		r->next = q;	r = q;
    		p = p->next;
    	}
    	r->next = NULL;
    	return str;
    }
    
    /*子串的删除*/
    LinkStrNode* DelStr(LinkStrNode* s, int i, int j)
    {
    	int k = 1;
    	LinkStrNode* str, * p, * q, * r;
    	str = (LinkStrNode*)malloc(sizeof(LinkStrNode));
    	str->next = NULL;
    	r = str;
    
    	if (i <= 0 || i > StrLength(s) || i - 1 + j > StrLength(s))
    		return str;
    	//利用指针p,先将前0~i-1个字符存入str
    	p = s->next;
    	for (int k = 1; k < i; ++k)
    	{
    		q = (LinkStrNode*)malloc(sizeof(LinkStrNode));
    		q->data = p->data;
    		r->next = q;	r = q;
    		p = p->next;
    	}
    
    	//再利用指针p,直接遍历过j个位置
    	for (k = 0; k < j; ++k)
    		p = p->next;
    	//此时的指针p,已然移动到j+1的位置,开始将后面的剩余结点继续存入串str中
    	while (p != NULL)
    	{
    		q = (LinkStrNode*)malloc(sizeof(LinkStrNode));
    		q->data = p->data;
    		r->next = q;	r = q;
    		p = p->next;
    	}
    	r->next = NULL;
    	return str;
    
    }
    
    /*子串的替换*/
    LinkStrNode* RepStr(LinkStrNode* s, int i, int j, LinkStrNode* t)
    {
    	int k = 1;
    	LinkStrNode* str, * p, * p1, * q, * r;
    	str = (LinkStrNode*)malloc(sizeof(LinkStrNode));
    	str->next = NULL;
    	r = str;
    	//判断下标i是否越界
    	if (i <= 0 || i > StrLength(s) + 1 || j<0 || i - 1 + j>StrLength(s))
    		return str;
    
    	//利用指针p,先将前0~i-1个字符存入str
    	p = s->next;
    	for (int k = 1; k < i; ++k)
    	{
    		q = (LinkStrNode*)malloc(sizeof(LinkStrNode));
    		q->data = p->data;	 q->next = NULL;
    		r->next = q;	r = q;
    		p = p->next;
    	}
    
    	for (k = 0; k < j; ++k)
    		p = p->next;		//直接删除原本串s中从第i位开始长度为j的那一子串
    
    	//利用指针p1,将串t中的结点顺势放入str中
    	p1 = t->next;
    	while (p1 != NULL)
    	{
    		q = (LinkStrNode*)malloc(sizeof(LinkStrNode));
    		q->data = p1->data;	 q->next = NULL;
    		r->next = q;	r = q;
    		p1 = p1->next;
    	}
    
    	//此时的指针p,已然移动到i的位置,开始将后面的剩余结点继续存入串str中
    	while (p != NULL)
    	{
    		q = (LinkStrNode*)malloc(sizeof(LinkStrNode));
    		q->data = p->data;	 q->next = NULL;
    		r->next = q;	r = q;
    		p = p->next;
    	}
    	r->next = NULL;
    	return str;
    }
    /*输出串*/
    void DispStr(LinkStrNode* s)
    {
    	LinkStrNode* p = s->next;
    	while (p != NULL)
    	{
    		printf("%c", p->data);
    		p = p->next;
    	}
    	printf("\n");
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
    • 211
    • 212
    • 213
    • 214
    • 215
    • 216
    • 217
    • 218
    • 219
    • 220
    • 221
    • 222
    • 223
    • 224
    • 225
    • 226
    • 227
    • 228
    • 229
    • 230
    • 231
    • 232
    • 233
    • 234
    • 235
    • 236
    • 237
    • 238
    • 239
    • 240
    • 241
    • 242
    • 243
    • 244
    • 245
    • 246
    • 247
    • 248
    • 249
    • 250
    • 251
    • 252
    • 253
    • 254
    • 255
    • 256
    • 257
    • 258
    • 259
    • 260
    • 261
    • 262
    • 263
    • 264
    • 265
    • 266
    • 267
    • 268
    • 269
    • 270
    • 271
    • 272
    • 273
    • 274
    • 275
    • 276
    • 277
    • 278
    • 279
    • 280
    • 281
    • 282
    • 283
    • 284

    🌳总结与提炼

    看完了链串的基本算法实现,是不是觉得并没有顺序串那么烧脑,仔细看我在中途说的烧脑打上了双引号,链串的基本算法实现其实并不难,就是底层思路我在一开头就讲了,使用尾插法,可以看到,虽然代码很长,但是理解起来并不难,因此完全可以说是【纸老虎】,大家不要被各种数据结构的算法实现难住了,只要你去认真思考,然后动手打打代码,其实是没有那么困难的。包括在后续我们还会讲到二叉树、图的算法实现,比这些还要困难,所以学习编程还是要有一颗强大的内心

    有关链串的算法实现就说到这里,感谢您对本文的观看,如有问题请于评论区留言或者私信我🍀

  • 相关阅读:
    渗透测试 | IP信息收集
    南美阿根廷市场最全分析开发攻略,收藏一篇就够了
    如何防范 DAO 中的治理攻击?
    黑磷和量子点结合分子印迹技术的荧光传感材料(BPS-QDs@MIP)
    Linux 线程概念&线程控制
    计算机三级 - 数据库技术 - 第十四章 数据仓库与数据挖掘 笔记
    Java(四)(多态,final,常量,抽象类,接口)
    STM32中I2C通信的完整C语言代码范例
    nodejs+vue旅行社网站系统-计算机毕业设计
    SpringMVC:绝对地址、相对地址(动力)
  • 原文地址:https://blog.csdn.net/Fire_Cloud_1/article/details/127414613