单链表反转(时间复杂度O(n), 空间复杂度O(1))的方法主要有以下三种:
- 头插法:从第二个元素开始,依次把元素插到插入到头结点和第一个元素之间。
- 指针逆转:把指向后面一个元素的指针指向前面一个元素
- 递归法:本质上跟指针逆转相同
前情提要:
设置一个链表,带有头结点。元素为1->2->3->4
倒转过来应该是:
1.头插法
从第二个元素开始,每次选取一个元素插入到头结点和第一个节点之间。
第一步:把 2 插到 head 和 1 之间
第二步:把 3 插入 head 与 2 之间
第三步:把 4 插入 head 与 3 之间
代码实现:
static ListNode reverseByHeadInsert(ListNode head){
//如果一个元素没有或者仅有一个元素,那么可以直接返回
if(head.next == null || head.next.next == null)
return head;
ListNode p = head.next; //指向第一个元素
while(p.next != null)
{
ListNode q = p.next; //指向第一个元素后面的元素
p.next = q.next;
q.next = head.next;
head.next = q;
}
return head;
}
2.指针逆转
原先next指针指向后面,把next指针指向前面,然后head指针指向最后一个元素即可。相当于 把指针方向掉了个 ,然后把head重新指向链表新的起点。
调转前
调转后
设置三个指针,分别指向 前一个元素p、后一个元素q、后一个元素后面的元素res
初始情况:
p 指向 1
q 指向 2
第一次循环:
res 指向 3
将 2 的next 指针指向 1(此时1的next仍然指向2,这个我们最后再调整也行)
p 指向 2
q 指向 3
第二次循环:
res 指向 4
将 3 的next指针指向2
p 指向 3
q 指向 4
第三次循环
res 指向null
将 4 的next指针指向3
p 指向 4
q 指向 null
q==null停止循环
static ListNode reverseByReversePoint(ListNode head){
//如果一个元素没有或者仅有一个元素,那么可以直接返回
if(head.next == null || head.next.next == null)
return head;
ListNode p = head.next; //指向前一个元素
ListNode q = p.next; //指向后一个元素
while(q != null){ //当后一个元素不为空指向前一个元素
ListNode res = q.next; // 用于记录后一个元素的后面,因为next指向前面元素后,需要保存后面的内容
q.next = p;
p = q;
q = res;
}
head.next.next = null;
head.next = p;
return head;
}
3.递归法:也是链表指针方向旋转
代码:
//这里不传入头结点,最终返回值也是最后一个元素
static ListNode reverseByRecursion(ListNode node){
//包括特殊情况
if (node == null || node.next == null)
return node;
ListNode newHead = reverseByRecursion(node.next);//注意,此处的操作是一直循环到链表末尾
node.next.next = node;//反转每个节点的指向
node.next = null;
return newHead;
}
4.代码总结
把所有代码放在一起,包括ListNode的定义。
class ListNode{
int value;
ListNode next;
ListNode(int value){
this.value = value;
}
}
public class ReverseList {
static ListNode reverseByHeadInsert(ListNode head){
//如果一个元素没有或者仅有一个元素,那么可以直接返回
if(head.next == null || head.next.next == null)
return head;
ListNode p = head.next; //指向第一个元素
while(p.next != null)
{
ListNode q = p.next; //指向第一个元素后面的元素
p.next = q.next;
q.next = head.next;
head.next = q;
}
return head;
}
static ListNode reverseByReversePoint(ListNode head){
//如果一个元素没有或者仅有一个元素,那么可以直接返回
if(head.next == null || head.next.next == null)
return head;
ListNode p = head.next; //指向前一个元素
ListNode q = p.next; //指向后一个元素
while(q != null){ //当后一个元素不为空指向前一个元素
ListNode res = q.next; // 用于记录后一个元素的后面,因为next指向前面元素后,需要保存后面的内容
q.next = p;
p = q;
q = res;
}
head.next.next = null;
head.next = p;
return head;
}
//这里不传入头结点,最终返回值也是最后一个元素
static ListNode reverseByRecursion(ListNode node){
//包括特殊情况
if (node == null || node.next == null)
return node;
ListNode newHead = reverseByRecursion(node.next);//注意,此处的操作是一直循环到链表末尾
node.next.next = node;//反转每个节点的指向
node.next = null;
return newHead;
}
static void printList(ListNode head){
if(head.next == null){
return;
}
ListNode p = head.next;
while(p != null){
System.out.print(p.value + " ");
p = p.next;
}
}
public static void main(String[] args) {
ListNode head = new ListNode(0); // 创建头结点
ListNode cur = head; // 工作指针指向头结点,用于后面创建链表
for(int i = 1; i <= 4; i++){ // 创建链表 1->2->3->4
cur.next = new ListNode(i);
cur = cur.next;
}
cur.next = null;
// reverseByHeadInsert(head);
// reverseByReversePoint(head);
head.next = reverseByRecursion(head.next);
printList(head);
}
}