其他分享
首页 > 其他分享> > 北邮2019计导下 链表一 D. 实验11_13_链表交换

北邮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