北邮2019计导下 链表一 D. 实验11_13_链表交换
作者:互联网
这题相对来说坑大一些,而且理解起来有丶难度。
1.理解
灵魂画师上线(可以自己动手画一画)
很普通的链表
原来的遍历顺序
或者说是这样
交换后
顺序就成了这样
所以总结起来,对于general situation,我们要做的的是
1.把S1的前驱prevS1节点的节点域改成S2,用来在第一段后执行紫色段。
2.把T2的节点域改成T1的节点域,用来在紫色段执行完后执行中间的白色段
3.把原S2的前驱prevS2节点的节点域改成S1,用来在白色段执行完后执行黄色段
4.把T1的节点域改成原T2的节点域(*之后会再提),用来执行第五段。
实现
设计index函数,用于直接返回某个给定下标的地址
exchangeSection函数是具体的实现形式,然后按照理解部分来做。
尬点
1.题目中给定的下标是自然下标,也就是从1开始计数的,一般程序习惯从0开始计数。
2.头结点的处理:如果S1是头结点(实际上给定的测试数据就是这种情况),需要更改头结点的位置。
3.相邻情况的处理,此时会发现原来general situation的处理不再适用,会产生环链表,反映在OJ里就是OLE。(Output Length Exceeded),因为程序一直在打印。
4.T2的后继需要预先保存下来,因为根据步骤,在第二步时T2的节点域就被重新赋值而丢失了,之后赋给T1的节点域时还要用。
#include <stdio.h>
#include <stdlib.h>
typedef struct _node
{
int data;
struct _node* nextPtr;
} Node;
Node* createList();
void destoryList(Node** sPtr);
void exchangeSection(Node **sPtr,int s1,int t1,int s2,int t2);
Node* index(Node **sPtr,int n);
int main(int argc, char const *argv[])
{
Node *list=createList();
int s1,s2,t1,t2;
scanf("%d%d%d%d",&s1,&t1,&s2,&t2);
exchangeSection(&list,s1-1,t1-1,s2-1,t2-1);//注意自然下标和数组下标的区别
//遍历打印时需要用一个临时指针来遍历,不要动list,不然头结点就丢了。
printf("The new list is:");
Node *duplicate=list;
while(duplicate)
{
printf("%d ",duplicate->data);
duplicate=duplicate->nextPtr;
}
putchar('\n');
duplicate=NULL;//不用的指针置空
destoryList(&list);
return 0;
}
Node* createList()
{
Node *currentPtr,*headPtr=NULL,*lastPtr;
int num;
scanf("%d",&num);
while(num!=-1)
{
currentPtr=(Node*)malloc(sizeof(Node));
currentPtr->data=num;
if(!headPtr)
headPtr=lastPtr=currentPtr;
else
{
lastPtr->nextPtr=currentPtr;
lastPtr=currentPtr;
}
scanf("%d",&num);
}
lastPtr->nextPtr=NULL;
return headPtr;
}
void destoryList(Node **sPtr)
{
Node *headPtr=*sPtr,*tmpPtr;
while(headPtr)
{
tmpPtr=headPtr;
headPtr=headPtr->nextPtr;
free(tmpPtr);
}
*sPtr=NULL;
}
//索引函数,传入二级指针和下标后可以找到对应节点的地址,实际上就是跳转n次
Node* index(Node **sPtr,int n)
{
if(n<0) return NULL;//之后另外有用
Node *headPtr=*sPtr;
while(n--)
headPtr=headPtr->nextPtr;
return headPtr;
}
void exchangeSection(Node **sPtr,int s1,int t1,int s2,int t2)
{
Node *prevS1=index(sPtr,s1-1);//S1的前置节点,如果S1是头结点,则prevS1为NULL
Node *nodeS1=index(sPtr,s1);//S1节点
Node *prevS2=index(sPtr,s2-1);
Node *nodeS2=index(sPtr,s2);
Node *nodeT1=index(sPtr,t1);
Node *nodeT2=index(sPtr,t2);
Node *afterAll=nodeT2->nextPtr;//保存原来T2的节点域
/*
欢迎来听:
After All~綴る想い~ (by 冬馬かずさ from WHITE ALBUM2 ORIGINAL SOUNDTRACK~kazusa~)
https://music.163.com/song?id=449824918
*/
if(!prevS1)//如果S1没有前置,就把头结点换成S2
*sPtr=nodeS2;
else prevS1->nextPtr=nodeS2;//一般情况是把S1前置的节点域改成S2
if(s2-t1!=1)//当两块区域不紧邻,即一般情况时
{
nodeT2->nextPtr=nodeT1->nextPtr;
prevS2->nextPtr=nodeS1;
nodeT1->nextPtr=afterAll;
}
else//紧邻时,需要把T2的节点域改成S1,而不是T1的后继,也不需要把S2的前驱的节点域改成S1
{
nodeT2->nextPtr=nodeS1;
nodeT1->nextPtr=afterAll;
}
}
题目描述
问题描述:已知一个正整数序列,序列元素个数未知,但至少有两个元素,你的任务是建立一个单链表用于存储这个正整数序列。然后实现交换此链表中任意指定的两段,第一段为[s1,t1],第二段[s2,t2]。s1、t1、s2、t2代表链表的第几个节点,且满足s1<=t1,s2<=t2,t1<s2,s2一定小于等于链表节点的总个数。正整数的输入用-1作为结束标志,注意-1不算这个正整数序列中的元素(不要统计-1)。最后将链表的全部节点释放。
输入与输出要求:输入一个正整数序列,以输入“-1”结束,序列中元素个数未知,但输入“-1”前至少输入两个正整数。然后是四个整数,即为s1、t1、s2、t2。 输出经过处理后的新链表,每个元素后有一个空格,注意最后一个元素后只有换行符。
数据最多的测试用例节点数在100这个数量级,所有整数可以用int型存储。
请注意输入输出格式。
输入样例
1 2 3 4 5 6 7 8 9 10 -1
1 1 4 7
输出样例
The new list is:4 5 6 7 2 3 1 8 9 10
标签:Node,11,int,北邮,链表,nextPtr,s2,sPtr,节点 来源: https://blog.csdn.net/weixin_43873801/article/details/88592707