反转有100万元素的链表资源开销并不大,反转也不是特别复杂的事情,但是用递归的话,就会调用100万次栈,这对系统的开销就非常大,所以用循环的方法反转列表
在递归中,我们会把1元素拿出来,然后把2,3,4,5,进行递归
但是在循环中,我们第一步是定义循环不变式,要定义一个断言使得在五次循环中都是成立的,要是把第1元素拿出来,就要处理很多边界条件,所以应该拿出中间随便的一个元素
假设循环了3次,1,2,3已经反转了,完成后如图
newHead:指向反转成功的链表
currentHead:指向还没反转的链表
向前推进:
问题:newHead、currentHead初始的时候,值是什么?
答案如下:起初newHead指向的是空链表,currentHead指向待反转链表,然后逐步推进,指导newHead指向反转后的链表,currentHead指向null。
代码实现:
package com.sise.recursion;
import java.util.ArrayList;
import java.util.Arrays;
public class LinkedListReverserCircle {
/*
* newHead指向反转链表
* curHead指向待反转链表
*/
public Node reverseLinkedListCircle(Node head) {
Node newHead=null;
Node curHead=head;
//先写循环里的代码,再写循环控制条件
//思路:假设已经成功循环了很多轮,循环里只是其中一轮
while(curHead!=null){ //特例:curHead being last node
//记录待反转链表头结点的下一个结点
//------curHead要是为null的话就没有getNext()------
Node next=curHead.getNext(); //next=null
//此时有3个结点,按顺序为newHead,curHead,next
//curHead指向newHead
curHead.setNext(newHead ); //curHead.next reversed
//各结点右移
newHead=curHead; //newHead points to last node
curHead=next; //curHead == null
}
return newHead;
}
public static void main(String[] args) {
// TODO Auto-generated method stub
LinkedListCreator creator=new LinkedListCreator();
LinkedListReverserCircle reversercircle=new LinkedListReverserCircle();
Node.printLinkedList(reversercircle.reverseLinkedListCircle
(creator.createLinkedList(new ArrayList<Integer>())));
Node.printLinkedList(reversercircle.reverseLinkedListCircle
(creator.createLinkedList(Arrays.asList(1))));
Node.printLinkedList(reversercircle.reverseLinkedListCircle
(creator.createLinkedList(Arrays.asList(1,2,3,4,5))));
reversercircle.reverseLinkedListCircle
(creator.createLargeLinkedList(1000000));
System.out.println("done");
}
}
package com.sise.recursion;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class LinkedListCreator {
/*
* 创建一个链表
* @return 链表的头结点,返回链表的最后一个结点的getNext()==null.
*/
public Node createLinkedList(List<Integer> data){
//假设传入空的List
if(data.isEmpty()){
return null;
}
//取出传入数据的第一个结点
Node firstNode=new Node(data.get(0));
//取走一个元素后,从第二个元素创建一个链表,
//因为返回的是Node,所以用Node来接收
//假设传入来的List有一个元素,则走到这里时sublist传入的两个参数相等
//但是sublist函数的定义可以看到fromIndex==toIndex时,返回null
/*
* <tt>fromIndex</tt> and <tt>toIndex</tt> are equal, the returned list is
*/
//与我们期望返回值一致
// Node headOfSublistNode=
// createLinkedList(data.subList(1, data.size()));
// //第一个结点的next指向规模缩小的链表返回来的头结点
// firstNode.setNext(headOfSublistNode);
//上面两行代码清理成如下代码
firstNode.setNext(createLinkedList(data.subList(1, data.size())));
return firstNode;
}
public Node createLargeLinkedList(int size) {
Node prev=null;
Node head=null;
for(int i=1;i<=size;i++){
Node node=new Node(i);
if(prev!=null){
prev.setNext(node);
}else{
head=node;
}
prev=node;
}
return head;
}
public static void main(String[] args) {
LinkedListCreator creator=new LinkedListCreator();
ArrayList arrayList=new ArrayList<>();
Node.printLinkedList(
creator.createLinkedList(arrayList)
);
Node.printLinkedList(
creator.createLinkedList(Arrays.asList(1))
);
Node.printLinkedList(
creator.createLinkedList(Arrays.asList(1,2,3,4,5))
);
}
}
package com.sise.recursion;
public class Node {
private final int value;//用户定义之后就不能修改
private Node next;
public Node(int value){
this.value=value;
this.next=null;//这样建立出来的结点都是单点Node
}
public Node getNext() {
return next;
}
public void setNext(Node next) {
this.next = next;
}
public int getValue() {
return value;
}
//打印函数
public static void printLinkedList(Node head) {
while(head!=null){
System.out.print(head.getValue());;
System.out.print(" ");
head=head.getNext();
}
System.out.println();
}
}
使用循环反转一百万个元素的运行结果:
package com.sise.recursion;
import java.util.ArrayList;
import java.util.Arrays;
public class LinkedListReverser {
/*
* 反转一个链表
* head为待反转链表的头结点
* @return 反转后的链表头结点,当然该链表也是以null结尾
*/
public Node reverseLinkedList(Node head) {
/*
*特殊处理
*/
// //空链表,sise==0
// if(head==null){
// return null;
// }
// //只有一个结点的时候,size==1
// if(head.getNext()==null){
// return head;
// }
//把上两个特殊情况合起来
if(head==null||head.getNext()==null){
return head;
}
//假设函数能够反转链表,返回头结点
//---------------此处head有可能是null,head。getNext()有可能是null-----------
Node newHead=reverseLinkedList(head.getNext());
//此时如图4状态,1的getNext就是第二个结点2,
//把第二结点2的next指向head则实现把2的指针指向1,如图5
//------------此处的getNext()有可能是null------
head.getNext().setNext(head);
head.setNext(null);//最后指向null,如图6
return newHead;
}
public static void main(String[] args) {
LinkedListCreator creator=new LinkedListCreator();
LinkedListReverser reverser=new LinkedListReverser();
ArrayList arrayList=new ArrayList<>();
Node.printLinkedList(
reverser.reverseLinkedList(creator.createLinkedList(arrayList))
);
Node.printLinkedList(
reverser.reverseLinkedList(creator.createLinkedList(Arrays.asList(1)))
);
Node.printLinkedList(
reverser.reverseLinkedList(creator.createLinkedList(Arrays.asList(1,2,3,4,5)))
);
//StackOverflow
reverser.reverseLinkedList
(creator.createLargeLinkedList(1000000));
System.out.println("done");
}
}
使用递归反转一百万元素的运行结果: