单链表反转详解(4种算法实现)
输入一个链表,反转链表后,输出新链表的表头。
示例1
输入:
{1,2,3}
复制
返回值:
{3,2,1}
这里给出四种解法
解法一:
思路就是最简单的思路,从头到尾遍历链表每个元素,然后修改指针域,前后一个指针域指向前一个元素,由于这里遍历过程中需要用到三个量,当前节点的前驱节点(用于把当前节点的后继赋给它),当前节点,后继节点(用于遍历链表用到,没有这个变量的话,前序节点后继修改后,原链表已经断开了)
public class Solution {
public ListNode ReverseList(ListNode head) {
ListNode pre = null;
ListNode mid = head;
ListNode next = head.next;
if(head == null && head.next == null){
return head;
}//空链或只有一个结点,直接返回头指针
while(true){
mid.next=pre;
if(null==next){
break;
}
pre = mid ;
mid = next;
next = next.next;
}
head = mid;
return head;
}
}
解法二:
思路就是进行简单的递归操作,当递归到最后一次,指针指向链表最后一个元素,此后开始出栈后,会同时得到链表尾部节点和倒数第二个节点 这样修改指针即可
public class Solution {
public ListNode ReverseList(ListNode head) {
if(head == null || head.next == null){
return head;
}
else{
ListNode l=ReverseList(head.next);//当递归到最后一次,head.next == null的时候 head就是最后一个元素,此后开始出栈,上一层的head必然是倒数第二个元素
head.next.next = head; //将尾部的元素指针域指向倒数第二个元素,然后递归下去
//直到第一个元素
head.next = null;
return l;
}
}
}
解法三:
这个思路也比较容易想到,在遍历链表的过程中,使用头插法,将链表的每个节点的后继修改为原来的新链表头节点,最后将该节点赋值给头节点。最后得到的就是逆置的链表
public class Solution {
public ListNode ReverseList(ListNode head) {
ListNode newhead = null;
ListNode temp = null;
if(head == null || head.next == null ) {
return head;
}
while(head!= null){
temp = head;
head = head.next;
temp.next = newhead;
newhead = temp;
}
return newhead;
}
}
解法四:
该思路和头插法比较相似,不同的是解法三头插法使用的思想是在遍历原链表的过程中,头插入节点(也就是将当前节点的指针指向头节点,再将当前节点赋给头节点),而该思想是使用两个变量,开始的时候begin指向的是链表头节点,end指向链表第二个元素,当begin的下一个节点不为空的话,就先将 begin.next = end.next; 用来在遍历过程中找到end的下一个指针值,再将end.next = head; 最后返回的肯定是逆置后的头节点,也就是最后一个元素,所以在过程中要让head = end; 最后将end= begin.next;更新值
public class Solution {
public ListNode ReverseList(ListNode head) {
ListNode begin = null;
ListNode end = null;
if(head == null || head.next == null){
return head;
}
begin = head;
end = head.next;
while(begin.next != null){
begin .next = end.next;
end.next = head;
head = end;
end = begin.next;
}
return head;
}
}