·单链表反转
这次讲单链表反转,main方法:
public static void main(String[] args) {
// 新建链表
LinkNode l = getALinkList(5);
LinkNode cur;
// 若为带头节点的链表,取消这段注释
// cur = new LinkNode(-1);
// cur.next = l;
// l = cur;
cur = l;
// 反转前打印
while (cur != null){
System.out.print(cur.val+" ");
cur = cur.next;
}
// 反转
cur = reverse1(l);
// 反转后打印
System.out.println();
while (cur != null){
System.out.print(cur.val+" ");
cur = cur.next;
}
}
getALinkList方法:
// 创建有 len 个节点的链表,val 为0-99随机数
private static LinkNode getALinkList(int len){
Random random = new Random();
LinkNode l = new LinkNode(random.nextInt(99));
LinkNode cur = l;
for (int i = 0; i < len - 1 ; i++) {
cur.next = new LinkNode(random.nextInt(99));
cur = cur.next;
}
return l;
}
链表节点:
public class LinkNode {
public int val;
public LinkNode next = null;
public LinkNode(int val){
this.val = val;
}
}
链表反转一般有三种方法,原地反转,头插法反转,递归反转。其中递归反转最简单简洁,但是空间复杂度更高。下面分别介绍。
-
原地反转
首先让pre的next指向cur的next;再让cur的next指向头节点的下一个结点;这时已经反转了结点,此时链表第一个结点变成了当前反转的结点;再让头节点的next指向cur;最后移动cur到下一个要反转的结点。重复上述步骤,直到cur为null。此时头节点也指向最后一个节点了。
带头节点的链表:
static LinkNode reverse1(LinkNode l){ if(l.next == null || l.next.next == null){ return l; } LinkNode pre = l.next; // pre 不动, 移动头节点 LinkNode cur = pre.next; while(cur != null){ pre.next = cur.next; cur.next = l.next; l.next = cur; cur = pre.next; } return l; }
不带头结点的链表:
一样的做法一个指向pre,一个指向cur。而且比有头节点的更加简单。
public LinkNode reverse2(LinkNode l){ LinkNode pre = l; LinkNode cur = pre.next; while(cur != null){ LinkNode next = cur.next; cur.next = pre; pre = cur; cur = next; } l.next = null; // 记得将最开始的头节点指向null,否则形成环路 return pre; }
-
利用头插法反转
新建一个链表,遍历原链表,用头插法插入到新链表中。
值得注意的是,在遍历开始前,还要断开第一个结点和第二个结点之间的链。初始化工作做完后,从第二个结点开始遍历链表,依次插入新链表中,即实现反转。
带头节点的链表:
static LinkNode reverse3(LinkNode l){ if(l.next == null || l.next.next == null){ return l; } LinkNode cur = l.next.next; LinkNode next; l.next.next = null; while (cur != null){ next = cur.next; cur.next = l.next; l.next = cur; cur = next; } return l; }
不带头结点的链表:
static LinkNode reverse4(LinkNode l){ if(l == null || l.next == null){ return l; } LinkNode cur = l.next; LinkNode next; l.next = null; while (cur != null){ next = cur.next; cur.next = l; l = cur; cur = next; } return l; }
-
递归反转
直接递归得到最后一个节点,然后每层就是将这个节点的下一个节点指向这个节点,这个节点指向null,最后返回末尾节点。(不带头节点)
static LinkNode reverse5(LinkNode l){ if(l == null || l.next == null){ return l; } LinkNode p = reverse5(l.next); l.next.next = l; l.next = null; return p; }