无空头链表的节点交换
交换数据
根据数据查找交换
注意:若有几个相同的数据,是交换第一个数据
利用中间变量交换
数据的交换,对于指针指向是不变的,所以传一级指针就可
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;
}