链式存储方式下字符串的replace运算
- ⭐️题目
- ⭐️思路
- ⭐️代码
- ✨定义结点
- ✨打印字符串函数
- ✨计算字符串函数
- ✨初始化字符串函数
- ✨代码解读
- ✨字符串替换函数
- ✨字符串替换函数解读
- ✨ 主函数
- ✨完整代码
实现在链式存储下字符串的replace(S,T1,T2),来自课本习题的一道题目。这篇博客是我自己的思路,其中也还有很多不完善的地方,也还有很大的局限性。
希望对大家能有一点帮助。
⭐️题目
试编写一个函数,实现在链式存储方式下字符串的replace(S,T1,T2)运算。
⭐️思路
①首先,题目明确要求在链式存储
方式下实现函数,所以,我们的字符串S以及我们的字符串T1,和要替换T1的字符串T2都必须是链式存储
的。
明确了这一点,我们首先要初始化创建三个字符串,为了方便,写一个初始化字符串的函数。
②关于初始化一个字符串函数,采用前插
或者尾插
都可以。我自己写得是前插。
③关于替换掉S中T1,首先,应该是要找T1是否是在S中存在。其次应该计算T1的长度,改变有关两个结点的next值,举例即:
如上图,即改变b结点
的next值,使之指向T2的头节点,并改变T2尾结点
的next值,使之指向T1尾结点的后继结点。
我下面的代码并没有判断T1是否在S中是否存在,缺乏稳健性。计算T1的长度的原因是,这样以便我们能够很快找到f结点,并使T2的尾结点o指向f结点。
③关于替换,如上面所说,我们要找到关键结点。
即b结点
、m结点
和o结点
。
b结点
的找法是,当我们设置一个当前结点开始遍历循环S字符串时,也要找一个指针pre
来跟踪cur指针,当cur指针指向T1的第一个字符时,这时q就指向了在了我们的目标结点。
f结点
的查找方法是,我们计算T2结点的长度length,然后cur指针从当前c位置移动length-1
个单位,这时cur就指向了f结点。
o结点
即我们对T2字符串用指针tmp进行遍历,当以循环条件whiile(tmp->next)
进行循环遍历,当不满足条件是,tmp恰好指在了尾结点即o结点。
④最后,我们改变相关结点的next值即可。
即pre->next=head2;
,tmp->next=cur;
⑤释放T1.free(head1)
⭐️代码
✨定义结点
typedef struct node
{
char data;
struct node* next;
}linkstrnode;
✨打印字符串函数
void printstr(linkstrnode* head)
{
linkstrnode* cur = head;
while (cur)
{
printf("%c", cur->data);
cur = cur->next;
}
}
✨计算字符串函数
int length(linkstrnode* head)
{
int i = 0;
linkstrnode* cur = head;
while (cur)
{
i++;
cur = cur->next;
}
return i;
}
✨初始化字符串函数
linkstrnode* Initstr()
{
int n,i;
printf("请输入字符串的长度:\n");
scanf("%d", &n);
printf("请依次输入各节点:\n");
getchar();//吸收回车
linkstrnode* q = NULL;
for (i = 1; i <= n; i++)
{
char s;
scanf("%c",&s);
//前插
linkstrnode* newnode = (linkstrnode*)malloc(sizeof(linkstrnode));//产生新的结点
newnode->data = s;
newnode->next =q;
q = newnode;
}
return q;
}
在这里插入一个在我自己写代码时的一个报错!0x00007FFC8C5325E7 (ucrtbased.dll)处(位于 DataStructure.exe 中)引发的异常: 0xC0000005: 读取位置 0xFFFFFFFFFFFFFFFF 时发生访问冲突。 原因就是 使用了malloc函数 ,但没有包含<stdlib.h>头文件。
✨代码解读
①
首先,对于getchar()这一行
在下面的for循环中,用scanf来接收从键盘输入的字符。在上面,我们知道此时还有一个回车留在了缓冲区,如果不将缓冲区中的回车清除,那么scanf函数读取到的第一个字符就是回车了而不是从键盘输入的第一个字符。
②
在for循环中,scanf先从缓冲区读取到一个字符,然后我们用malloc函数在堆上开辟内存,开辟空间的大小即sizeof(linkstrnode)
,然后让栈上面的局部变量newnode
来管理这块内存。
当我们开辟好空间,即开辟好一个结点的空间,我们就需要通过指针newnode
来对这个结点进行赋值。newnode->data=s;
即将scanf读取到的字符s赋值给newnode的data域。
那关键就在于next域,它就关键在可以将我们所输入的字符“连接起来”。
在这里我采用前插的方法。即我使一个字符所在的结点指向空。
然后此时,我存下来现在结点的值
q=newnode;
然后第二个结点如是,
然后最后一次的q
即为这个链表的头节点。
✨字符串替换函数
//创建字符串替换函数
void strreplace(linkstrnode* head, linkstrnode *head1, linkstrnode* head2)
{
linkstrnode* pre = NULL;
linkstrnode* cur = head;
linkstrnode* q;//q结点作为指向cur结点指针的前驱结点指针
int i = 0;
while (cur)
{
if (cur->data == head1->data)
{
while (i < length(head1) && cur)
{
i++;
cur = cur->next;
}
break;
}
else
{
pre = cur;
cur = cur->next;
}
}
//将T2替换原来T1的位置,插入到字符串S中
//先找到T2的尾结点
linkstrnode* tmp = head2;
while (tmp->next)
{
tmp = tmp->next;
}
pre->next = head2;
tmp->next = cur;
}
✨字符串替换函数解读
head指向字符串S的头节点,head1是指向字符串T1的头节点,T2是指向字符串T2的头节点。
①
指针cur
用来循环遍历S字符串。
❌❌我这里在S中查找T1字符串不严谨!只是判断了cur所指向的当前结点的值是否和T1头结点的值是否相等,就直接进行了替换。
当cur所指向结点的值和T1头节点的值不相等时,进入else
条件体。
直到cur所指向结点的值和T1头节点的值相等。
若相等,则pre就指向了–>如图(假设d结点即是T1字串第一个结点的值)
这时,我们进入if
条件体。我们需要的是,移动指针cur
,使之指向T1尾结点值的后一个结点。(举例,若T1尾结点值为f,则我们需要将cur指向g)
这时,我们就需要直到T1的长度,使循环cur移动length-1
次即可。
此时cur指向了–>如图
此时我们在循环中达到了目的,break
退出循环即可。
②
下面,我们仍然是利用长度找到T2的尾结点。
③连接
即pre->next=head2;
tmp->next=cur;
✨ 主函数
int main()
{
printf("*****创建字符串S*****\n");
linkstrnode* head=Initstr();//创建指向字符串S头节点的指针
printf("字符串S为:");
printstr(head);
printf("\n");
printf("*****创建字符串T1*****\n");
linkstrnode* head1 = Initstr();//创建指向字符串T1头节点的指针
printf("字符串T1为:");
printstr(head1);
printf("\n");
printf("*****创建字符串T2*****\n");
linkstrnode* head2 = Initstr();//创建指向字符串T2头节点的指针
printf("字符串T2为:");
printstr(head2);
printf("\n");
strreplace(head, head1, head2);
printf("被替换后的字符串S:");
printstr(head);
free(head1);//释放T1字符串所占的空间
return 0;
}
✨完整代码
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include<stdlib.h>
//定义结点
typedef struct node
{
char data;
struct node* next;
}linkstrnode;
//初始化链式字符串 (使用前插)
linkstrnode* Initstr()
{
int n,i;
printf("请输入字符串的长度:\n");
scanf("%d", &n);
printf("请依次输入各节点:\n");
getchar();//吸收回车
linkstrnode* q = NULL;
for (i = 1; i <= n; i++)
{
char s;
scanf("%c",&s);
//前插
linkstrnode* newnode = (linkstrnode*)malloc(sizeof(linkstrnode));//产生新的结点
newnode->data = s;
newnode->next =q;
q = newnode;
}
return q;
}
//打印字符串
void printstr(linkstrnode* head)
{
linkstrnode* cur = head;
while (cur)
{
printf("%c", cur->data);
cur = cur->next;
}
}
//计算字符串的长度
int length(linkstrnode* head)
{
int i = 0;
linkstrnode* cur = head;
while (cur)
{
i++;
cur = cur->next;
}
return i;
}
//创建字符串替换函数
void strreplace(linkstrnode* head, linkstrnode *head1, linkstrnode* head2)
{
linkstrnode* pre = NULL;
linkstrnode* cur = head;
linkstrnode* q;//q结点作为指向cur结点指针的前驱结点指针
int i = 0;
while (cur)
{
if (cur->data == head1->data)
{
while (i < length(head1) && cur)
{
i++;
cur = cur->next;
}
break;
}
else
{
pre = cur;
cur = cur->next;
}
}
//将T2替换原来T1的位置,插入到字符串S中
//先找到T2的尾结点
linkstrnode* tmp = head2;
while (tmp->next)
{
tmp = tmp->next;
}
pre->next = head2;
tmp->next = cur;
}
//主函数
int main()
{
printf("*****创建字符串S*****\n");
linkstrnode* head=Initstr();//创建指向字符串S头节点的指针
printf("字符串S为:");
printstr(head);
printf("\n");
printf("*****创建字符串T1*****\n");
linkstrnode* head1 = Initstr();//创建指向字符串T1头节点的指针
printf("字符串T1为:");
printstr(head1);
printf("\n");
printf("*****创建字符串T2*****\n");
linkstrnode* head2 = Initstr();//创建指向字符串T2头节点的指针
printf("字符串T2为:");
printstr(head2);
printf("\n");
strreplace(head, head1, head2);
printf("被替换后的字符串S:");
printstr(head);
free(head1);
return 0;
}