1.无头结点的链表
在分析整个问题之前,我们先做一个假设。假设“NULL”是一个特殊的“结点”,它只能被其他结点指向而不能指向其他结点。这里一定要强调把NULL作为结点看待。
我们可以做个图:
NULL 1->2->……->n->NULL
其中,最左侧的NULL是新链表的NULL,我们期待的结果是:
NULL<-1<-2<-……<-n NULL
结合下面的代码,再根据此图进行手动模拟整个过程就能体会到这么做的好处。
1.1双指针头插法
原理是从原链表头部依次取结点,使用头插法插入到新链表中。
具体代码如下:
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* reverseList(ListNode* head) {
ListNode *p, *q;
p = head;
head = NULL; //head指向最左侧的NULL
while(p){
q = p, p = p -> next;
q -> next = head;
head = q;
}
return head;
}
};
1.2三指针原地法
具体代码如下:
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* reverseList(ListNode* head) {
ListNode *p, *q, *r;
p = head;
q = NULL; //q指向最左侧的NULL
while(p){
r = p -> next;
p -> next = q;
q = p, p = r;
}
return head = q;
}
};
2.带头结点的链表
注意:带头结点的链表的反转代码只要将以上两份代码中所有的“head”全部用“head->next”替换即可!
分析过程与上面相似,大家可以结合代码并手动模拟整个过程。