(6)数据结构与算法-无空头链表的节点交换

交换数据

根据数据查找交换

注意:若有几个相同的数据,是交换第一个数据

利用中间变量交换

数据的交换,对于指针指向是不变的,所以传一级指针就可
1.找到数据一的节点地址,找到数据二的节点地址,判断两个是否为空

2.不为空则交换,结构体允许直接交换
或者节点直接互相赋值
字符串必须调用strcpy或者循环赋值
3.为NULL,无法交换

void SwopiData(struct Chain *pHead, int iData1, int iData2)
{
//合法性检测
	if (NULL == pHead->pNext || NULL == pHead)
		return;
//找到两个节点
	struct Chain *pTemp1 = FindiData(pHead, iData1);
	struct Chain *pTemp2 = FindiData(pHead, iData2);
//交换
	if (pTemp1 != NULL && pTemp2 != NULL)
	{
		int pTemp = pTemp1->iData;
		pTemp1->iData = pTemp2->iData;
		pTemp2->iData = pTemp;
	}

利用mencpy内存拷贝交换

	struct chain pT = *pTemp1;
	memcpy(pTemp1,pTemp2,4);
	memcpy(pTemp2,&pT,4);

纵使要交换的特别多,只要这两行就够了

根据下标查找交换

和根据数据查有异曲同工之妙

void SwopiIndex(struct Chain *pHead, int iIndex1, int iIndex2){
	if (NULL == pHead->pNext || NULL == pHead)
		return;
	struct Chain *pTemp1 = FindIndex(pHead, iIndex1);
	struct Chain *pTemp2 = FindIndex(pHead, iIndex2);
	if (pTemp1 != NULL && pTemp2 != NULL){
		int pTemp = pTemp1->iData;
		pTemp1->iData = pTemp2->iData;
		pTemp2->iData = pTemp;
	}
}

交换节点指向

与交换数据不同,交换数据节点的位置不变,只是变得是数据,而交换节点是指针的指向变了,节点中的数据是不变的,这有可能改变头尾指针的指向,所以要传二级指针。
1)参数合法性检测
交换两个节点,所以节点要多于一个节点–下标不能相等

if (NULL == *pHead || (*pHead)->pNext == NULL || iIndex1 == iIndex2 || iIndex1 < 0 || iIndex2 < 0)
		return;

2)确定两下标的大小关系,这样就固定是某一个会装头,另一个一定不会装头,就不用再单独判断了

//确定大小关系
	int Max = iIndex1;
	int Min = iIndex2;
	if (iIndex1<iIndex2){
		Max = iIndex2;
		Min = iIndex1;
	}

3)根据下标找节点

//根据下标找节点
	struct Chain *pMin = FindIndex(*pHead, Min);
	struct Chain *pMax = FindIndex(*pHead, Max);

4)交换节点
上面已经确定了大小关系,所以这里头指针一定是装在Min中的,就不用再判断另一个了,也是提高程序的逻辑。
分为4种情况:交换头与尾;交换头与中间;交换尾与中间;交换中间两个节点。

交换头与尾节点

两种情况:链表有两个节点、链表有3个以上节点
a)判断是否找到

	//判断是否找到
	if (NULL == Min || NULL == Max)
		return;

b)头尾交换
交换条件是找到的节点,一个是头,一个是尾
条件内又有两种情况:一种是只有两个节点,一种是有多个节点

//头尾交换
	if (Max == *pHead && Min == *pTail){
		//两个节点
		if ((*pHead)->pNext == *pTail){}
		else{}//多个节点
	}

c)先连后断
先将尾连到头

			(*pTail)->pNext = *pHead;

再将头断开

			(*pHead)->pNext = NULL;

d)头尾指针的交换,让头指针指向新头,尾指针指向新尾。

//交换指针指向 让头指针变为指向新头
			*pHead = *pTail;
			*pTail = (*pHead)->pNext;

e)处理多个节点的情况
头和尾中间有多个节点,尾如果直接指向头节点,那么尾部的节点就会丢失,我们需要先找到尾节点的前一节点,将尾指向第二个节点位置即(*pHead)->pNext,然后将头部接到尾巴上,再断开头部的pNext即可
找尾的前一个节点

//找尾的前一节点
			struct Chain*pTemp = FindIndex(*pHead,Max-1); 
			Max一定装的是尾节点

尾变头 将尾节点移前面去

//尾变头
			(*pTail)->pNext = (*pHead)->pNext;

头变尾 将头部移后面去

//头变尾
			pTemp->pNext = *pHead;

头下一个为空

//头下一个为空
			(*pHead)->pNext = NULL;

交换指针指向

//交换指向
			*pHead = *pTail;
			*pTail = pTemp->pNext;

总代码如下:

void SwopDir(struct Chain **pHead,struct Chain**pTail, int iIndex1,int iIndex2)
{
	if (NULL == *pHead || (*pHead)->pNext == NULL || iIndex1 == iIndex2 || iIndex1 < 0 || iIndex2 < 0)
		return;
	//确定大小关系
	int Min = iIndex1;
	int Max = iIndex2;
	if (iIndex1>iIndex2)
	{
		Min = iIndex2;
		Max = iIndex2;
	}
	//根据下标找节点
	struct Chain *pMin = FindIndex(*pHead, Min);
	struct Chain *pMax = FindIndex(*pHead, Max);
	//判断是否找到
	if (NULL == pMin || NULL == pMax)
		return;
	//头尾交换
	if (pMin == *pHead && pMax == *pTail)
	{ 
		//两个节点
		if ((*pHead)->pNext == *pTail)
		{
			//先连后断  头指针和尾指针交换
			(*pTail)->pNext = *pHead;
			(*pHead)->pNext = NULL;
			//交换指针指向 让头指针变为指向新头
			*pHead = *pTail;
			*pTail = (*pHead)->pNext;
		}
		else   //多个节点
		{
			//找尾的前一节点
			struct Chain*pTemp = FindIndex(*pHead,Max-1); //Max一定装的是尾节点
			//尾变头
			(*pTail)->pNext = (*pHead)->pNext;
			//头变尾
			pTemp->pNext = *pHead;
			//头下一个为空
			(*pHead)->pNext = NULL;
			//交换指向
			*pHead = *pTail;
			*pTail = pTemp->pNext;
		}
	}
}

交换头与中间节点

也是两种情况:与头节点相邻,与头节点不相邻
相邻
1)条件判断,pMin->pNext == pMax
2)pMin即头节点指向相邻节点的下一节点

			pMin->pNext = pMax->pNext;

3)相邻节点指向头节点,此时相邻节点就变成了头节点

			pMax->pNext = pMin;
			//头指向pMax
			*pHead = pMax;

不相邻
1)找pMax的前一节点

struct Chain *pTemp = FindIndex(*pHead,Max-1);

2)记录头的下一节点,一会要将pMax的节点指向它

struct Chain *HeadNext = (*pHead)->pNext;

3)头节点移到后面

pMin->pNext = pMax->pNext;
pTemp->pNext = Min;

4)pMax移到头

pMax->pNext = HeadNext;

5)改变新的头

*pHead = pMax;

交换尾与中间

两种情况:与尾节点相邻,不相邻。
具体看代码:不相邻是唯一特殊的,要记录两个的前节点,才能找到。

//交换尾和中间节点
	else if (pMin != *pHead && pMax == *pTail)
	{
		//相邻
		if (pMin->pNext == pMax)
		{
			//找到pMin的前一个节点
			struct Chain *pTemp = FindIndex(*pHead,Min-1);
			//尾移到中间
			pTemp->pNext = pMax;
			//中间移到尾
			pMax->pNext = pMin;
			//下一个赋值为NULL
			pMin->pNext = NULL;
			//尾指针重新变成尾
			*pTail = pMin;
		}
		//不相邻
		else
		{
			//记录pMax和pMin前一个节点
			struct Chain *pTemp1 = FindIndex(*pHead, Min - 1);
			struct Chain *pTemp2 = FindIndex(*pHead, Max - 1);
			//pMin前一个接pMax
			pTemp1->pNext = pMax;
			//pMax指向pMin的下一个节点
			pMax->pNext = pMin->pNext;
			//断开pMin,将pTemp1指向pMin
			pTemp2->pNext = pMin;
			//现在pMin在尾,赋空
			pMin->pNext = NULL;
			//将尾指针指向尾
			*pTail = pMin;
		}
	}

交换中间与中间

也是分相邻与不相邻进行讨论
具体看代码,每一步都有注释

	//交换两个中间节点
	else if (pMin != *pHead && pMax != *pTail)
	{
		//相邻
		if (pMin->pNext == pMax)
		{
			//记录pMin前一个节点
			struct Chain *pTemp = FindIndex(*pHead,Min-1);
			//pMin移到后面
			pMin->pNext = pMax->pNext;
			//pMax指向pMin
			pMax->pNext = pMin;
			//pMin前一节点指向pMax
			pTemp->pNext = pMax;

		}
		//不相邻
		else
		{
			//记录两个节点的前节点
			struct Chain *pTemp1 = FindIndex(*pHead, Min - 1);
			struct Chain *pTemp2 = FindIndex(*pHead, Max - 1);
			//将pMin移到pMax位置
			pMin->pNext = pMax->pNext;
			pTemp2->pNext = pMin;
			//将pMax移到pMin位置
			pMax->pNext = pTemp2;
			pTemp1->pNext = pMax;
		}

翻转链表

翻转链表,也就是链表的顺序完全倒过来了

比如:一链表为1、2、3、4、5
反转链表:5、4、3、2、1

原链表直接操作

数据翻转

思路

计算链表节点数,然后前后成对交换数据

注意

数据翻转,只是数据变动,节点指向不变

节点指向不改变,传一级指针就可以;函数体中,节点数要两个或两个以上,获取节点数
循环交换:相当于有两个下标,一个从小往大,一个从大到小,小<大即可,循环内交换节点内容,调用节点交换函数

void ReverseData(struct Chain *pHead)
{
	//合法性检测
	if (NULL == pHead || NULL == pHead->pNext)
		return;
	//记录节点数量
	int iCount = GetCount(pHead);
	//循环交换  两边交换同时循环
	//下标最大为iCount-1
	for (int i = 0, j = iCount - 1; i < j; i++, j--) 
		SwopIndex(pHead, i, j);
}

节点翻转

注意:数据不变,节点指向改变 要传二级指针
和数据翻转大体相似,只是要循环调用的函数不同

void ReverseIndex(struct Chain**pHead,struct Chain**pTail)
{
	if (NULL == *pHead || NULL == (*pHead)->pNext)
		return;
	int iCount = GetCount(*pHead);
	//循环交换
	for (int i = 0, j = iCount - 1; i < j; i++, j--)
		SwopDir(pHead,pTail,i,j);  
		
}

空间辅助

既是对当先链表进行遍历,通过头添加的方式加进另外一个链表中,然后头指针和尾指针都指向新链表中的头和尾,释放之前的链表
头和尾要指向新的节点,改变方向,所以要传二级指针

void BySpace(struct Chain**pHead, struct Chain **pTail)
{
	//合法性检测
	if (NULL == *pHead || NULL == (*pHead)->pNext)
		return;
	//中间变量  二级指针 头指针会变
	struct Chain *pTemp = *pHead;
	//定义新头、尾
	struct Chain *pNewHead = NULL,
				 *pNewTail = NULL;
	//遍历链表
	while (NULL != pTemp)
	{	//在头添加 代码段在前面
		AddHead(&pNewHead,&pNewTail,pTemp->iData );
		pTemp = pTemp->pNext;
	}
	//释放原链表  代码段在前面
	FreeChain(pHead,pTail);
	//原头尾指针指向新头尾
	*pHead = pNewHead;
	*pTail = pNewTail;
}
  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

沐鑫本鑫

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值