单链表的逆置还是很重要的,不过第一次写逆置的时候程序就直接奔溃了,因为解决与链表相关的问题总是有大量的指针操作,而指针操作的代码总是容易出错的,因此这也就成就了单链表在面试中的地位。
1.普通循环逆置
第一次循环后: ① pTemp指向Head ② pCur指向P1 ③pTemp->pNext指向NULL。
第二次循环后: ① pTemp指向P1 ② pCur指向P2 ③pTemp->pNext指向Head。
第三次循环后: ① pTemp指向P2 ② pCur指向P3 ③ pTemp->pNext指向P1。
第四次循环后: ① pTemp指向P3 ② pCur指向NULL ③ pTemp->pNext指向P2。
//有头结点
typedef struct ListNode
{
TypeDate Value;
ListNode* pNext;
};
ListNode* ReverseList(ListNode* pHead)
{
if (pHead == NULL || pHead->pNext == NULL)
{
return pHead;
}
ListNode* pRev = NULL;
ListNode* pCur = pHead;
while (pCur != NULL)
{
ListNode* pTemp = pCur;
pCur = pCur->pNext;
pTemp->pNext = pRev;
pRev = pTemp;
}
return pRev;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
//有头结点
typedefstructListNode
{
TypeDateValue;
ListNode*pNext;
};
ListNode*ReverseList(ListNode*pHead)
{
if(pHead==NULL||pHead->pNext==NULL)
{
returnpHead;
}
ListNode*pRev=NULL;
ListNode*pCur=pHead;
while(pCur!=NULL)
{
ListNode*pTemp=pCur;
pCur=pCur->pNext;
pTemp->pNext=pRev;
pRev=pTemp;
}
returnpRev;
}
2.用三个指针逆置
分为两种情况:①链表为空或者链表中仅有一个节点,直接返回pHead ②链表中有多个节点时,利用三个指针的方法向后遍历,但是最后一个节点循环是进不去的,因此跳出循环需要单独处理。
//无头结点
typedef struct ListNode
{
TypeDate value;
ListNode* pNext;
};
ListNode* ReverseList(ListNode* pHead)
{
if (pHead == NULL || pHead->pNext == NULL)
return pHead;
//3个指针分别指向前3个节点
ListNode* pPre = pHead;
ListNode* pCur = pPre->pNext;
ListNode* pNet = pCur->pNext;
while (pNet)
{
pCur->pNext = pPre;
pPre = pCur;
pCur = pNet;
pNet = pNet->pNext;
}
pCur->pNext = pPre;//最后一个节点处理
pHead->pNext = NULL;
return pCur;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
//无头结点
typedefstructListNode
{
TypeDatevalue;
ListNode*pNext;
};
ListNode*ReverseList(ListNode*pHead)
{
if(pHead==NULL||pHead->pNext==NULL)
returnpHead;
//3个指针分别指向前3个节点
ListNode*pPre=pHead;
ListNode*pCur=pPre->pNext;
ListNode*pNet=pCur->pNext;
while(pNet)
{
pCur->pNext=pPre;
pPre=pCur;
pCur=pNet;
pNet=pNet->pNext;
}
pCur->pNext=pPre;//最后一个节点处理
pHead->pNext=NULL;
returnpCur;
}
3.头插法逆置
分为两种情况:①链表为空或者链表中仅有一个节点,直接返回pHead ②链表中有多个节点时:将pHead后面的节点依次插入到头结点的后面。
//有头结点
typedef struct ListNode
{
TypeDate value;
ListNode* pNext;
};
ListNode* ReverseList(ListNode* pHead)
{
if (pHead == NULL || pHead->pNext == NULL)
return pHead;
ListNode* pCur = pHead->pNext;
ListNode* pNet = NULL;
pHead->pNext = NULL;
while (pCur)
{
pNet = pCur->pNext;//保存当前节点的下一个节点
pCur->pNext = pHead->pNext;//把节点插入到pHead的后面
pHead->pNext = pHead;//让pHead指向最新的节点
pCur = pNet;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
//有头结点
typedefstructListNode
{
TypeDatevalue;
ListNode*pNext;
};
ListNode*ReverseList(ListNode*pHead)
{
if(pHead==NULL||pHead->pNext==NULL)
returnpHead;
ListNode*pCur=pHead->pNext;
ListNode*pNet=NULL;
pHead->pNext=NULL;
while(pCur)
{
pNet=pCur->pNext;//保存当前节点的下一个节点
pCur->pNext=pHead->pNext;//把节点插入到pHead的后面
pHead->pNext=pHead;//让pHead指向最新的节点
pCur=pNet;
}
}
总体来说,我觉得三个指针的方法最容易理解,但容易出错,很多人都会忽视最后一个节点的特殊性,因此我建议大家在以后的使用与面试中最好使用头插法,头插法的原理很简单,只需要将新节点插入到头结点的后面即可。