探索数据结构:顺序串与链式串的深入理解

news2024/10/5 9:59:56

✨✨ 欢迎大家来到贝蒂大讲堂✨✨

🎈🎈养成好习惯,先赞后看哦~🎈🎈

所属专栏:数据结构与算法
贝蒂的主页:Betty’s blog

1. 串的定义

串是一种特殊的顺序表,即每一个元素都是单独一个字符。在C语言中我们学习的字符串便是串的一种,它在我们的数据搜索与文本编译中起着不可或缺的作用。

img

特别注意:空格也是一个字符!!

下面是与串相关概念:

  • 串的长度:指串中有效元素的个数(不包括字符\0)。
  • 空串:不含任何元素的串,即长度为0。
  • 子序列:抽取串的一些字符,按照原字符串的顺序进行放置的新串。
  • 子串:串中任意连续字符组成的子序列称为该串的子串,其中空串是任意串的子串。
  • 主串:包含子串的串称为该子串的主串。

2. 串的实现方式

串是一种特殊的顺序表,所以实现方式也与顺序表类似,分别以顺序表和链表来实现。

  1. 顺序实现

img

  1. 链式实现

img

3. 串的功能

  1. 串的初始化
  2. 串的生成。
  3. 串的复制。
  4. 判断两个串是否相等。
  5. 返回串的长度。
  6. 链接两个串。
  7. 取子串。
  8. 在串1的指定位置插入串2。
  9. 删除指定位置长度为n的某个子串。

4. 串的声明

4.1. 顺序串

顺序串的存储自然是以顺序表的形式,但是在定义其长度有三种实现方式,如下:

  1. 初始化一个头结点作为长度的存储。

img

但是这种存储有一个明显的缺点就是char类型的最大表示范围为255,所以这种方式并不可取。

  1. 以字符\0作为结束标志。

img

C/C++中的字符串就是以这种实现方式,但是这种实现方式每次求长度都需要遍历整个顺序表。所以在这里也不是特别好。

  1. 添加为结构体成员。

img

这种实现方式相较于前两种更加合理,后续我们也将以这种方式实现。

同时为了方便扩容,我们可以再增加一个结构体成员capacity

#define MAXSIZE 50
typedef struct string
{
	char *data;
	int length;
	int capacity;
}Sstring;

4.2. 链式串

链式串我们使用单链表来实现,为了方便操作我们可以添加一个头节点

typedef struct snode 
{
	char data;
	struct snode* next;
}LinkStrNode;

5. 串的初始化

5.1. 顺序串

void StrInit(Sstring* s)//初始化串
{
	char *arr = (char*)malloc(sizeof(char) * MAXSIZE);
	if (arr == NULL)
	{
		perror("malloc fail");
		return;
	}
	s->data = arr;
	s->length = 0;
	s->capacity = MAXSIZE;
}

5.2. 链式串

链式串并不需要单独初始化,可以在具体的实现中初始化。

5.3. 复杂度分析

  • 时间复杂度:顺序串花费时间是一个常数,所以时间复杂度为O(1)。
  • 空间复杂度:初始化开辟了MAXSIZE的空间。可以视为O(N)的复杂度。

6. 串的生成

6.1. 顺序串

在对串进行拷贝时,要检查是否需要扩容,放置越界。

void CheckCapacity(Sstring* s, int len)
{
	if (s->length + len > s->capacity)
	{
		char* tmp = (char*)realloc(s->data, sizeof(char) * (s->length + len));
		if (tmp == NULL)
		{
			perror("realloc fail");
			return;
		}
		s->data = tmp;
		s->capacity = MAXSIZE + len;
	}
}
void StrAssign(Sstring* s, char*str)//生成串
{
	assert(s && str);
	int i = 0;
	int len = strlen(str);
	CheckCapacity(s, len);
	for (i = 0; str[i] != '\0'; i++)
	{
		s->data[i] = str[i];
	}
	s->length = len;
}

6.2. 链式串

链式串每次插入都要生成一个节点,所以我们可以单独封装成一个函数。

LinkStrNode* BuyListNode()
{
	LinkStrNode*tmp= (LinkStrNode*)malloc(sizeof(LinkStrNode));
	if (tmp == NULL)
	{
		perror("malloc fail");
	}
	return tmp;
}
void StrAssign(LinkStrNode** s, char*str)
{
	assert(str);
	LinkStrNode* r, * p;
	*s = BuyListNode();
	r = *s;
	for (int i = 0; str[i] != '\0'; ++i)
	{
		p = BuyListNode();
		p->data = str[i];
		r->next = p;	
		r = p;
	}
	r->next = NULL;
}

6.3. 复杂度分析

  • 时间复杂度:无论是顺序串还是链式串都需要遍历一遍目标串,间复杂度可以视为O(N))。
  • 空间复杂度:顺序串可能会扩容,链式串需要开辟等量节点,所以空间复杂度可以视为O(N)。

7. 串的复制

7.1. 顺序串

串的复制也需要检查是否需要扩容,然后再依次拷贝。

void StrCopy(Sstring* s, Sstring* t)//复制串
{
	assert(s && t);
	if (s->capacity < t->capacity)
	{
		char* tmp = (char*)realloc(s->data, sizeof(char) * t->capacity);
		if (tmp == NULL)
		{
			perror("realloc fail");
			return;
		}
		s->data = tmp;
		s->capacity = t->capacity;
	}
	for (int i = 0; i < t->length; i++)
	{
		s->data[i] = t->data[i];
	}
	s->length = t->length;
}

7.2. 链式串

链式串的拷贝我们采用一种方法:即先将原串销毁,然后再拷贝。

void StrCopy(LinkStrNode** s, LinkStrNode* t)//复杂
{
	assert(t);
	DestroyStr(*s);//销毁
	LinkStrNode* r, * q;
	LinkStrNode* p = t->next;
	*s = BuyListNode();
	r = *s;
	while (p != NULL)
	{
		q = BuyListNode();
		q->data = p->data;		

		r->next = q;
		r = q;			

		p = p->next;
	}
	r->next = NULL;
}

7.3. 复杂度分析

  • 时间复杂度:需要遍历一遍被复制串,所以时间复杂度可以视为O(N)。
  • 空间复杂度:顺序串可能扩容,链式串需要复制等量节点,所以空间复杂度可以视为O(N)。

8. 串的比较

串的比较与C语言中strcmp函数功能类似,都是依次比较串中的字符,直至结束或者出现不同的字符为至。

若大于则返回>0,等于返回0,小于则返回<0。

列如:

  • 当串长度不同时:“aabc”>“abbca”,“aaa”<“aaab”。
  • 当串长度相同时:“acbc”>“bcbc”,“acac”=“acac”。

8.1. 顺序串

int StrCmp(Sstring* s, Sstring* t)//比较两个串
{
	assert(s && t);
	char* p1 = s->data;
	char* p2 = t->data;
	int i = 0;
	while (i < s->length && i < t->length && p1[i] == p2[i])
	{
		i++;
	}
	if (i == s->length&&i==t->length)
	{
		return 0;
	}
	if (i == s->length && i != t->length)
	{
		return -1;
	}
	if (i != s->length && i == t->length)
	{
		return 1;
	}
	return p1[i] - p2[i];
}

8.2. 链式串

int StrCmp(LinkStrNode* s, LinkStrNode* t)//比较两个串
{
	assert(s&&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 0;
	if (p == NULL && q != NULL)
	{
		return -1;
	}
	if (p != NULL && q == NULL)
	{
		return 1;
	}
	return p->data - q->data;
}

8.3. 复杂度分析

  • 时间复杂度:无论是链式串还是顺序串都可能遍历整个串,所以时间复杂度可以视为O(N)
  • 空间复杂度:无论是顺序串还是链式串花费空间是一个常数,所以空间复杂度为O(1)。

9. 返回串的长度

9.1. 顺序串

int StrLength(Sstring* s)//返回串的长度
{
	assert(s);
	return s->length;
}

9.2. 链式串

int StrLength(LinkStrNode* s)//返回串的长度
{
	assert(s);
	int count = 0;
	LinkStrNode* p = s->next;
	while (p != NULL)
	{
		count++;
		p = p->next;
	}
	return count;
}

9.3. 复杂度分析

  • 时间复杂度:顺序串是一个常数,所以时间复杂度为O(1)。但是链式串需要遍历整个串,所以为O(N)。
  • 空间复杂度:无论是顺序串还是链式串花费空间是一个常数,所以空间复杂度为O(1)。

10. 链接两个串

链接两个串十分简单,首先找个一个串的末尾,然后再链接即可。

10.1. 顺序串

链接两个串也需要判断该串是否需要扩容。

Sstring Strcat(Sstring* s, Sstring* t)//链接两个串
{
	assert(s && t);
	int len = t->length;
	CheckCapacity(s, len);
	for (int i = s->length; i < s->length + t->length; i++)
	{
		s->data[i] = t->data[i - s->length];
	}
	s->length = s->length + t->length;
	return *s;
}

10.2. 链式串

LinkStrNode*Strcat(LinkStrNode* s, LinkStrNode* t)//链接两个串
{
	assert(s && t);
	LinkStrNode* p = s->next, * q = t->next;
	while (p->next != NULL)
	{
		p = p->next;
	}
	LinkStrNode* str1 = p,*str2;
	while (q != NULL)
	{
		str2 = BuyListNode();
		str2->data =q->data;

		str1->next = str2;
		str1 = str2;

		q = q->next;
	}
	str1->next = NULL;
	return s;
}

10.3. 复杂度分析

  • 时间复杂度:无论是顺序串还是链式串都需要遍历两个串,所以时间复杂度为O(N)。
  • 空间复杂度:顺序串可能会扩容,链式串需要开辟等量节点,所以空间复杂度为O(N)

11. 取子串

我们通过传入的目标位置与长度来截取一段子串返回,如果长度过大则截取后续所有字符。

11.1. 顺序串

Sstring SubStr(Sstring* s, int i, int len)//取子串
{
	assert(i < s->length);
	assert(s);
	Sstring str;
	str.data = (char*)malloc(sizeof(char) * s->capacity);
	if (str.data == NULL)
	{
		perror("malloc fail");
		return *s;
	}
	str.capacity = s->capacity;
	if (i + len >= s->length)
	{
		for (int pos = i; pos < s->length; pos++)
		{
			str.data[pos-i] = s->data[pos];
		}
		str.length = s->length - i;
	}
	else
	{
		for (int pos = i; pos < i+len; pos++)
		{
			str.data[pos - i] = s->data[pos];
		}
		str.length = len;
	}
	return str;
}

11.2. 链式串

LinkStrNode*SubStr(LinkStrNode* s, int i, int len)//取子串
{
	assert(s);
	assert(i <= StrLength(s));
	int count = 0;
	LinkStrNode* r, * p;
	p = s->next;//跳过头节点
	r = BuyListNode();
	while (p != NULL)//找到第i个位置
	{
		count++;
		if (count == i)
		{
			break;
		}
		p = p->next;
	}
	LinkStrNode* str1=r,*str2;
	while (len--&&p!=NULL)
	{
		str2 = BuyListNode();
		str2->data = p->data;
		str1->next = str2;
		str1 = str2;
		p = p->next;
	}
	str1->next = NULL;//末尾置空
	return r;
}

11.3. 复杂度分析

  • 时间复杂度:都可能遍历整个串,所以时间复杂度为O(N)。
  • 空间复杂度:都需要开辟len个大小的空间,所以空间复杂度可以视为O(N)。

12. 指定位置插入

12.1. 顺序串

指定位置插入也许检查是否扩容,然后指定位置后续字符移动len个单位。

img

img

Sstring InsStr(Sstring* s1, int i, Sstring* s2)//指定位置插入
{
	assert(s1 && s2);
	assert(i < s1->length);
	int len = s2->length;
	CheckCapacity(s1, len);
	for (int pos = s1->length - 1; pos >= i; pos--)
	{
		s1->data[pos + len] = s1->data[pos];
	}
	for (int pos = i; pos < i + len; pos++)
	{
		s1->data[pos] = s2->data[pos - i];
	}
	s1->length += len;
	return *s1;
}

12.2. 链式串

LinkStrNode*InsStr(LinkStrNode* s1, int i, LinkStrNode* s2)//指定位置插入
{
	assert(s1&&s2);
	assert(i <= StrLength(s1));
	int count = 0;
	LinkStrNode* r, * p,*q;
	q=p = s1->next;//q为i之前的位置
	while (p != NULL)//找到第i个位置
	{
		count++;
		if (count == i)
		{
			break;
		}
		q = p;//记录前一个位置
		p = p->next;
	}
	r = q;
	LinkStrNode* str;
	LinkStrNode* ptr=s2->next;//跳过头节点
	while (ptr != NULL)
	{
		str = BuyListNode();
		str->data = ptr->data;
		r->next = str;
		r = str;
		ptr = ptr->next;
	}
	r->next= p;//链接
	return s1;
}

12.3. 复杂度分析

  • 时间复杂度:顺序串需要移动覆盖,链式串需要寻找目标位置,时间复杂度都可以视为O(N)。
  • 空间复杂度:顺序串可能扩容,链式串需要开辟等量空间,空间复杂度都可以视为O(N)。

13. 指定删除子串

13.1. 顺序串

如果删除的长度过长,只需要修改串的length。否则需要从前往后覆盖。

Sstring DelStr(Sstring* s, int i, int len)//指定删除子串
{
	assert(i < s->length);
	assert(s);
	if (i + len >=s->length)
	{
		s->length = i ;
	}
	else
	{
		for (int pos = i+len; pos <s->length; pos++)
		{
			s->data[pos-len] = s->data[pos];
		}
		s->length -= len;
	}
	return *s;
}

13.2. 链式串

LinkStrNode* DelStr(LinkStrNode* s, int i, int len)//指定删除子串
{
	assert(s);
	assert(i < StrLength(s));
	int count = 0;
	LinkStrNode* r, * p;
	p = s->next;
	r = p;//r为前一个节点
	while (p != NULL)
	{
		count++;
		if (count == i)
		{
			break;
		}
		r = p;
		p = p->next;
	}
	while (len-- && p != NULL)
	{
		LinkStrNode* str = p->next;
		free(p);
		p = str;
	}
	r->next = p;
	return s;
}

13.3. 复杂度分析

  • 时间复杂度:顺序串可能需要移动覆盖,链式串需要寻找目标位置,时间复杂度都可以视为O(N)。
  • 空间复杂度:顺序串与链式串都不需要开辟格外空间,空间复杂度都可以视为O(1)。

14. 串的打印

14.1. 顺序串

void PrintStr(Sstring* s)
{
	assert(s);
	char* p = s->data;
	for (int i = 0; i < s->length; i++)
	{
		printf("%c", p[i]);
	}
	printf("\n");
}

14.2. 链式串

void PrintStr(LinkStrNode* s)//打印
{
	assert(s);
	LinkStrNode* p = s->next;
	while (p != NULL)
	{
		printf("%c", p->data);
		p = p->next;
	}
	printf("\n");
}

14.3. 复杂度分析

  • 时间复杂度:无论是顺序串还是链式串都需要遍历整个串,所以时间复杂度为O(N)。
  • 空间复杂度:顺序串与链式串都不需要开辟格外空间,空间复杂度都可以视为O(1)。

15. 串的销毁

15.1. 顺序串

void StrDestroy(Sstring* s)//销毁串
{
	free(s->data);
	s->data = NULL;
	s->length = s->capacity = 0;
}

15.2. 链式串

void DestroyStr(LinkStrNode* s)//销毁
{
	LinkStrNode* pre = s, * p = s->next;
	while (p != NULL)
	{
		free(pre);
		pre = p;
		p = p->next;
	}
	free(pre);
}

15.3. 复杂度分析

  • 时间复杂度:顺序串消耗时间固定,时间复杂度为O(1)。链式串需要遍历这个串,时间复杂度为O(N)
  • 空间复杂度:顺序串与链式串都不需要开辟格外空间,空间复杂度都可以视为O(1)。

16. 对比与应用

16.1. 对比

因为串也是一种顺序表,所以无论是顺序表还是链式串的优劣都与顺序表与链表差不多。这里就不在赘述。

16.2. 应用

串在计算机领域有着广泛的应用:

  1. **文本处理:**文本编辑器或处理器中,文本被表示为一个字符串,可以进行查找、替换、插入、删除等操作
  2. 加密和安全:加密算法中经常使用字符串表示数据,例如对称加密和非对称加密中的密钥和明文。

17. 完整代码

17.1. 顺序串

17.1.1. Sstring.h
#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>
#include<assert.h>
#include<string.h>
#define MAXSIZE 50
typedef struct string
{
	char *data;
	int length;
	int capacity;
}Sstring;
void StrInit(Sstring* s);//初始化串
void StrAssign(Sstring* s, char str[]);//生成串
void StrCopy(Sstring* s, Sstring*t);//复制串
int StrCmp(Sstring*s, Sstring*t);//比较两个串
int StrLength(Sstring*s);//返回串的长度
Sstring Strcat(Sstring*s, Sstring*t);//链接两个串
Sstring SubStr(Sstring* s, int i, int len);//取子串
Sstring InsStr(Sstring* s1, int i, Sstring* s2);//指定位置插入
Sstring DelStr(Sstring* s, int i, int len);//指定删除子串
void PrintStr(Sstring* s);//打印
void StrDestroy(Sstring* s);//销毁串
17.1.2. Sstring.c
#define _CRT_SECURE_NO_WARNINGS 1
#include"Sstring.h"
void CheckCapacity(Sstring* s, int len)
{
	if (s->length + len > s->capacity)
	{
		char* tmp = (char*)realloc(s->data, sizeof(char) * (s->length + len));
		if (tmp == NULL)
		{
			perror("realloc fail");
			return;
		}
		s->data = tmp;
		s->capacity = MAXSIZE + len;
	}
}
void StrInit(Sstring* s)//初始化串
{
	char *arr = (char*)malloc(sizeof(char) * MAXSIZE);
	if (arr == NULL)
	{
		perror("malloc fail");
		return;
	}
	s->data = arr;
	s->length = 0;
	s->capacity = MAXSIZE;
}
void StrAssign(Sstring* s, char*str)//生成串
{
	assert(s && str);
	int i = 0;
	int len = strlen(str);
	CheckCapacity(s, len);
	for (i = 0; str[i] != '\0'; i++)
	{
		s->data[i] = str[i];
	}
	s->length = len;
}
void StrCopy(Sstring* s, Sstring* t)//复制串
{
	assert(s && t);
	if (s->capacity < t->capacity)
	{
		char* tmp = (char*)realloc(s->data, sizeof(char) * t->capacity);
		if (tmp == NULL)
		{
			perror("realloc fail");
			return;
		}
		s->data = tmp;
		s->capacity = t->capacity;
	}
	for (int i = 0; i < t->length; i++)
	{
		s->data[i] = t->data[i];
	}
	s->length = s->length > t->length ? s->length : t->length;
}
int StrCmp(Sstring* s, Sstring* t)//比较两个串
{
	assert(s && t);
	char* p1 = s->data;
	char* p2 = t->data;
	int i = 0;
	while (i < s->length && i < t->length && p1[i] == p2[i])
	{
		i++;
	}
	if (i == s->length&&i==t->length)
	{
		return 0;
	}
	if (i == s->length && i != t->length)
	{
		return -1;
	}
	if (i != s->length && i == t->length)
	{
		return 1;
	}
	return p1[i] - p2[i];
}
int StrLength(Sstring* s)//返回串的长度
{
	assert(s);
	return s->length;
}
Sstring Strcat(Sstring* s, Sstring* t)//链接两个串
{
	assert(s && t);
	int len = t->length;
	CheckCapacity(s, len);
	for (int i = s->length; i < s->length + t->length; i++)
	{
		s->data[i] = t->data[i - s->length];
	}
	s->length = s->length + t->length;
	return *s;
}
Sstring SubStr(Sstring* s, int i, int len)//取子串
{
	assert(i < s->length);
	assert(s);
	Sstring str;
	str.data = (char*)malloc(sizeof(char) * s->capacity);
	if (str.data == NULL)
	{
		perror("malloc fail");
		return *s;
	}
	str.capacity = s->capacity;
	if (i + len >= s->length)
	{
		for (int pos = i; pos < s->length; pos++)
		{
			str.data[pos-i] = s->data[pos];
		}
		str.length = s->length - i;
	}
	else
	{
		for (int pos = i; pos < i+len; pos++)
		{
			str.data[pos - i] = s->data[pos];
		}
		str.length = len;
	}
	return str;
}
Sstring InsStr(Sstring* s1, int i, Sstring* s2)//指定位置插入
{
	assert(s1 && s2);
	assert(i < s1->length);
	int len = s2->length;
	CheckCapacity(s1, len);
	for (int pos = s1->length - 1; pos >= i; pos--)
	{
		s1->data[pos + len] = s1->data[pos];
	}
	for (int pos = i; pos < i + len; pos++)
	{
		s1->data[pos] = s2->data[pos - i];
	}
	s1->length += len;
	return *s1;
}
Sstring DelStr(Sstring* s, int i, int len)//指定删除子串
{
	assert(i < s->length);
	assert(s);
	if (i + len >=s->length)
	{
		s->length = i ;
	}
	else
	{
		for (int pos = i+len; pos <s->length; pos++)
		{
			s->data[pos-len] = s->data[pos];
		}
		s->length -= len;
	}
	return *s;
}
void PrintStr(Sstring* s)
{
	assert(s);
	char* p = s->data;
	for (int i = 0; i < s->length; i++)
	{
		printf("%c", p[i]);
	}
	printf("\n");
}
void StrDestroy(Sstring* s)//销毁串
{
	free(s->data);
	s->data = NULL;
	s->length = s->capacity = 0;
}

17.2. 链式串

17.2.1. Sstring.h
#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>
#include<assert.h>
#include<string.h>
typedef struct snode 
{
	char data;
	struct snode* next;
}LinkStrNode;
void StrInit(LinkStrNode* s);//初始化串
void StrAssign(LinkStrNode**s, char str[]);//生成串
void StrCopy(LinkStrNode**s, LinkStrNode*t);//复制串
int StrCmp(LinkStrNode*s, LinkStrNode*t);//比较两个串
int StrLength(LinkStrNode*s);//返回串的长度
LinkStrNode*Strcat(LinkStrNode*s, LinkStrNode*t);//链接两个串
LinkStrNode*SubStr(LinkStrNode* s, int i, int len);//取子串
LinkStrNode*InsStr(LinkStrNode* s1, int i, LinkStrNode* s2);//指定位置插入
LinkStrNode*DelStr(LinkStrNode* s, int i, int len);//指定删除子串
void PrintStr(LinkStrNode* s);//打印
void DestroyStr(LinkStrNode* s);//销毁串
17.2.2. Sstring.c
#include"Sstring.h"
LinkStrNode* BuyListNode()
{
	LinkStrNode*tmp= (LinkStrNode*)malloc(sizeof(LinkStrNode));
	if (tmp == NULL)
	{
		perror("malloc fail");
	}
	return tmp;
}
void StrAssign(LinkStrNode** s, char*str)
{
	assert(str);
	LinkStrNode* r, * p;
	*s = BuyListNode();
	r = *s;
	for (int i = 0; str[i] != '\0'; ++i)
	{
		p = BuyListNode();
		p->data = str[i];
		r->next = p;	
		r = p;
	}
	r->next = NULL;
}

void StrCopy(LinkStrNode** s, LinkStrNode* t)
{
	assert(t);
	DestroyStr(*s);
	LinkStrNode* r, * q;
	LinkStrNode* p = t->next;
	*s = BuyListNode();
	r = *s;
	while (p != NULL)
	{
		q = BuyListNode();
		q->data = p->data;		

		r->next = q;
		r = q;			

		p = p->next;
	}
	r->next = NULL;
}

int StrCmp(LinkStrNode* s, LinkStrNode* t)//比较两个串
{
	assert(s&&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 0;
	if (p == NULL && q != NULL)
	{
		return -1;
	}
	if (p != NULL && q == NULL)
	{
		return 1;
	}
	return p->data - q->data;
}
int StrLength(LinkStrNode* s)//返回串的长度
{
	assert(s);
	int count = 0;
	LinkStrNode* p = s->next;
	while (p != NULL)
	{
		count++;
		p = p->next;
	}
	return count;
}
LinkStrNode*Strcat(LinkStrNode* s, LinkStrNode* t)//链接两个串
{
	assert(s && t);
	LinkStrNode* p = s->next, * q = t->next;
	while (p->next != NULL)
	{
		p = p->next;
	}
	LinkStrNode* str1 = p,*str2;
	while (q != NULL)
	{
		str2 = BuyListNode();
		str2->data =q->data;

		str1->next = str2;
		str1 = str2;

		q = q->next;
	}
	str1->next = NULL;
	return s;
}
LinkStrNode*SubStr(LinkStrNode* s, int i, int len)//取子串
{
	assert(s);
	assert(i <= StrLength(s));
	int count = 0;
	LinkStrNode* r, * p;
	p = s->next;//跳过头节点
	r = BuyListNode();
	while (p != NULL)//找到第i个位置
	{
		count++;
		if (count == i)
		{
			break;
		}
		p = p->next;
	}
	LinkStrNode* str1=r,*str2;
	while (len--&&p!=NULL)
	{
		str2 = BuyListNode();
		str2->data = p->data;
		str1->next = str2;
		str1 = str2;
		p = p->next;
	}
	str1->next = NULL;//末尾置空
	return r;
}
LinkStrNode*InsStr(LinkStrNode* s1, int i, LinkStrNode* s2)//指定位置插入
{
	assert(s1&&s2);
	assert(i <= StrLength(s1));
	int count = 0;
	LinkStrNode* r, * p,*q;
	q=p = s1->next;//q为i之前的位置
	while (p != NULL)//找到第i个位置
	{
		count++;
		if (count == i)
		{
			break;
		}
		q = p;//记录前一个位置
		p = p->next;
	}
	r = q;
	LinkStrNode* str;
	LinkStrNode* ptr=s2->next;//跳过头节点
	while (ptr != NULL)
	{
		str = BuyListNode();
		str->data = ptr->data;
		r->next = str;
		r = str;
		ptr = ptr->next;
	}
	r->next= p;//链接
	return s1;
}
LinkStrNode* DelStr(LinkStrNode* s, int i, int len)//指定删除子串
{
	assert(s);
	assert(i < StrLength(s));
	int count = 0;
	LinkStrNode* r, * p;
	p = s->next;
	r = p;//r为前一个节点
	while (p != NULL)
	{
		count++;
		if (count == i)
		{
			break;
		}
		r = p;
		p = p->next;
	}
	while (len-- && p != NULL)
	{
		LinkStrNode* str = p->next;
		free(p);
		p = str;
	}
	r->next = p;
	return s;
}
void PrintStr(LinkStrNode* s)//打印
{
	assert(s);
	LinkStrNode* p = s->next;
	while (p != NULL)
	{
		printf("%c", p->data);
		p = p->next;
	}
	printf("\n");
}
void DestroyStr(LinkStrNode* s)//销毁
{
	LinkStrNode* pre = s, * p = s->next;
	while (p != NULL)
	{
		free(pre);
		pre = p;
		p = p->next;
	}
	free(pre);
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1595520.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Matlab 2024安装教程(附免费安装包资源)

鼠标右击软件压缩包&#xff0c;选择“解压到MatlabR2024a“。 2.打开解压后的文件夹&#xff0c;鼠标右击“MATHWORKS_R2024A“选择装载。 鼠标右击“setup“选择”以管理员身份运行“。点击“是“&#xff0c;然后点击”下一步“。复制一下密钥粘贴至输入栏&#xff0c;然后…

移动开发避坑指南——内存泄漏

在日常编写代码时难免会遇到各种各样的问题和坑&#xff0c;这些问题可能会影响我们的开发效率和代码质量&#xff0c;因此我们需要不断总结和学习&#xff0c;以避免这些问题的出现。接下来我们将围绕移动开发中常见问题做出总结&#xff0c;以提高大家的开发质量。本系列文章…

爬虫的目的是做什么

通过网站域名获取HTML数据解析数据&#xff0c;获取想要的信息存储爬取的信息如果有必要&#xff0c;移动到另一个网页重复过程 这本书上的代码的网址是 &#xff1a; GitHub - REMitchell/python-scraping: Code samples from the book Web Scraping with Python http://shop.…

低代码集成Java系列:高效构建自定义插件

前言 随着软件开发的快速发展和需求的不断增长&#xff0c;开发人员面临着更多的压力和挑战。传统的开发方法需要花费大量的时间和精力&#xff0c;而低代码开发平台的出现为开发人员提供了一种更加高效、快速的开发方式。今天小编就以构建命令插件为例&#xff0c;展示如何使…

不要顺从胃的指示进食

没有人喜欢一直胖着&#xff0c;但想瘦&#xff0c;运动力、运动量、毅力、耐力、坚持、饮食管控方面等都不可缺&#xff0c;道理懂得都懂&#xff0c;但大多数超重胖子却都是有心而无力的。原因&#xff0c;除了生理体积影响了行动外&#xff0c;更重要的一点是&#xff1a;由…

汽车抗疲劳驾驶测试铸铁试验底座技术要求有哪些

铸铁平台试验台底座的主要技术参数要求 1、 试验台底座设计制造符合JB/T794-1999《铸铁平板》标准。 2、 试验铁底板及所有附件的计量单位全部采用 单位&#xff08;SI&#xff09;标准。 3、铸铁平台平板材质&#xff1a;用细密的灰口铸铁HT250或HT200&#xff0c;强度符…

Mysql的事务隔离级别以及事务的四大特性。

MySQL 的事务隔离级别是数据库管理系统中的一个重要概念&#xff0c;它决定了事务如何隔离和影响其他并发事务。MySQL 支持四种事务隔离级别&#xff0c;分别是&#xff1a;读未提交&#xff08;READ UNCOMMITTED&#xff09;、读已提交&#xff08;READ COMMITTED&#xff09;…

Collection与数据结构 二叉树(二):二叉树精选OJ例题(上)

1. 判断是否为相同的二叉树 OJ链接 public boolean isSameTree(Node p, Node q) {if (p null && q ! null || p ! null && q null){//结构不同return false;}if (p null && q null){//结构相同,都是空树return true;}if (p.value ! q.value){//…

STC89C52学习笔记(十二)

STC89C52学习笔记&#xff08;十二&#xff09; 一、AD/DA 1.定义 AD能够将模拟信号转化为数字信号&#xff0c;DA能够将数字信号转化为模拟信号。 2.两种类型的DA转换器 &#xff08;1&#xff09;PWM型DA滤波器 由于PWM是通过脉冲调制的方法来调整的&#xff0c;低通滤…

【数字IC/FPGA】什么是无符号数?什么是有符号数?

进制 虽然在日常生活中&#xff0c;我们已经习惯了使用10进制数字&#xff0c;但在由数字电路构成的数字世界中&#xff0c;2进制才是效率更高的选择。 10进制与2进制 10进制&#xff08;decimal&#xff09;计数法&#xff08;一般也叫阿拉伯计数法&#xff09;是在日常生活…

C++ | Leetcode C++题解之第19题删除链表的倒数第N个结点

题目&#xff1a; 题解&#xff1a; class Solution { public:ListNode* removeNthFromEnd(ListNode* head, int n) {ListNode* dummy new ListNode(0, head);ListNode* first head;ListNode* second dummy;for (int i 0; i < n; i) {first first->next;}while (fi…

UE4_导入内容_骨架网格体

FBX 导入支持 骨架网格体&#xff08;Skeletal Mesh&#xff09; 。这提供了一种简化的处理流程来将有动画的网格体从 3D应用程序中导入到虚幻引擎内&#xff0c;以便在游戏中使用。除了导入网格体外&#xff0c;如果需要&#xff0c;动画和变形目标都可以使用FBX格式 在同一文…

IDA导入jni.h头文件步骤

源地址&#xff1a;https://www.ctvol.com/asreverse/2273.html 导入步骤1&#xff1a; 点击IDA Pro 菜单项“File->Load file->Parse C header file ” 选择jni.h头文件。 导入步骤2&#xff1a; 1、点击IDA Pro 主界面上的“Structures”选项卡。 2、按下Insert键…

为什么会有c++内存模型

1. 引言 c的内存模型主要解决的问题是多线程的问题。怎么理解多线程呢&#xff1f;单核时候&#xff0c;只有1个CPU内核处理多线程&#xff0c;各线程之间随着时间的推进&#xff0c;会不断的切换&#xff0c;如下图形便于理解。 实际上线程间的切换是非常快的&#xff0c;所以…

OpenHarmony实战开发-异步并发概述 (Promise和async/await)。

Promise和async/await提供异步并发能力&#xff0c;是标准的JS异步语法。异步代码会被挂起并在之后继续执行&#xff0c;同一时间只有一段代码执行&#xff0c;适用于单次I/O任务的场景开发&#xff0c;例如一次网络请求、一次文件读写等操作。 异步语法是一种编程语言的特性&…

信息系统项目管理师——管理类计算

风险管理——风险曝光度 风险曝光度概率*影响&#xff0c;概率指风险发生的概率&#xff0c;影响指风险一旦发生&#xff0c;受到影响的项。 题号【GX20061101](61) 知识点[风险曝光度] 风险的成本估算完成后&#xff0c;可以针对风险表中每个风险计算其风险曝光度。某软件小…

h5 笔记4 表格与表单

<table></table>设置表格&#xff1b; <tr></tr>设置行数&#xff1b; <td></td>设置列数&#xff1b; <caption></caption>设置表格标题&#xff1b; <th></th>设置列标题。 直列&#xff1a;column&#xf…

LeetCode 678——有效的括号字符串

阅读目录 1. 题目2. 解题思路3. 代码实现 1. 题目 2. 解题思路 需要两个栈&#xff0c;一个用来保存左括号所在的位置索引&#xff0c;一个用来保存星号所在的位置索引。 从左往右遍历字符串&#xff0c;如果是左括号或者星号&#xff0c;则将位置索引分别入栈&#xff0c;如…

【网站项目】面向企事业单位的项目申报小程序

&#x1f64a;作者简介&#xff1a;拥有多年开发工作经验&#xff0c;分享技术代码帮助学生学习&#xff0c;独立完成自己的项目或者毕业设计。 代码可以私聊博主获取。&#x1f339;赠送计算机毕业设计600个选题excel文件&#xff0c;帮助大学选题。赠送开题报告模板&#xff…

精通技术写作:如何写出高质量技术文章?

CSDN 的朋友你们好&#xff0c;我是未来&#xff0c;今天给大家带来专栏【程序员博主教程&#xff08;完全指南&#xff09;】的第 7 篇文章“如何撰写高质量技术文章”。本文深入探讨了如何写好一篇技术文章。文章给出了好的技术文章的定义和分析&#xff0c;并提供了从选题、…