反转链表的四种方法
给你单链表的头节点 head
,请你反转链表,并返回反转后的链表。
示例 1:
输入:head = [1,2,3,4,5]
输出:[5,4,3,2,1]
示例 2:
输入:head = [1,2]
输出:[2,1]
示例 3:
输入:head = []
输出:[]
1.迭代法
因为单链表只能由当前节点查找到后一个节点,因此使用迭代法时,需要保存当前节点的后一个节点。
struct Node* reverseList(struct Node* head) {
struct Node *prev = NULL;
struct Node *cur = head;
struct Node *next;
while (cur != NULL) {
//用next指针保存cur下一个数据的地址
next = cur->next;
//调转当前节点指针的方向,为上一个节点的地址
cur->next = prev;
//prev保存当前节点的地址
prev = cur;
cur = next;
}
return prev;
}
2.头插法
由于单链表只能单向操作,由此可以想到链表的插入操作,把每一个节点的数据用头插法一一放入一个新的链表中,就能实现链表的反转操作了。
struct Node* reverseList(struct Node* head) {
//创建一个新的链表节点
struct Node* newHead = NULL;
while (head != NULL) {
//用nextNode保存待操作节点的下一个节点的地址
struct Node* nextNode = head->next;
//将当前节点用头插法插入新创建的链表当中
head->next = newHead;
newHead = head;
head = nextNode;
}
//返回反转之后的链表
return newHead;
}
3.原地反转法
与头插法类似,区别在于头插法通过建立一个新链表实现,原地反转法直接对原链表作出修改,借助两个指针实现。
1、初始状态,令beg指向第一个的开始节点,end指向beg->next
2、将end节点摘除,添加到新链表的头部
3、将end指向beg->next,然后将end所指节点摘除并且添加到当前头部
struct Node* reverseList(struct Node* head) {
struct Node* beg = NULL;
struct Node* end = NULL;
//如果是空链或者只有一个节点,就直接返回头指针
if(head==NULL || head->next==NULL) {
return head;
}else{
beg = head;
end = head->next;
while(end != NULL) {
//将end指向的节点摘出并插入到最前面
beg->next = end->next;
end->next = head;
head = end;
end = beg->next;
}
}
return head;
}
4.递归法
struct Node* reverseList(struct Node* head) {
//如果是空链或者只有一个节点,就直接返回头指针
if (head == NULL || head->next == NULL) {
return head;
}
//递归调用反转函数,此时restReversed保存最后一个节点的数据
struct Node* restReversed = reverseList(head->next);
//从后往前依次将节点的指向反转,并将最后一个节点里面的指针指向NULL
head->next->next = head;
head->next = NULL;
return restReversed;
}