package class04;
import java.util.ArrayList;
import java.util.List;
/**
* 单链表翻转,和双链表翻转
*/
public class Code01_ReverseList {
private static void printNode(Node head) {
while (head != null) {
System.out.print(head.value + "->");
head = head.next;
}
System.out.println("null");
}
public static void f(Node n1) {
// n1 = n1.next;
// System.out.println("n1.value2 = " + n1.value);//2
n1 = n1.next.next;
System.out.println("n1.value3 = " + n1.value);//3
}
public static class Node {
int value;
Node next;
public Node(int value) {
this.value = value;
}
}
//单链表翻转
public static Node reverseLinkedList(Node head) {//入参为原列表的头节点
//首先定义head的pre,和head的next为null。
Node pre = null;
Node next = null;
//只要head不为空,就一直翻转下去
while (head != null) {
//**这第一步很关键**,将next指向head的下一个节点,即head.next。
//也就是在修改head的next(第二步是修改head的next)之前,必须提前记录一下head的next(即head的下一个节点),这个节点的位置。
next = head.next;
head.next = pre;//第二步,将head指向下一个节点的指针,修改为指向左边(即翻转)。也就是pre(此时pre为null)。
pre = head;//将pre指向head(pre这个节点向右跳了一步)。
head = next;//将head指向next(head这个节点向右跳了一步)。
}
return pre;
}
//单链表翻转,方式2
public static Node reverseLinkedList2(Node head) {
if (head == null) {
return null;
}
ArrayList<Node> list = new ArrayList<>();
//将所有的节点,都添加到list中
while (head != null) {
list.add(head);
head = head.next;//head往下跳一步
}
//将原顺序的第一个节点的next,指向null。原来是指向第二个节点。
list.get(0).next = null;
int N = list.size();
//这个的i是从1开始的,即从第二个元素开始,将每个元素的next,指向该元素的上一个节点。
for (int i = 1; i < N; i++) {
list.get(i).next = list.get(i - 1);
}
//跳出for循环后,就完成了单链表的翻转,并返回最后一个节点。
return list.get(N - 1);
}
/***
* 流程示意图:
* --------> 代表:next
*
* 0. NodeA-------->NodeB-------->NodeC-------->NodeD-------->null null null
* ^ ^ ^
* | | |
* | | |
* head pre next
*
* ================================================================================================================
* 1. null<--------NodeA NodeB-------->NodeC-------->NodeD-------->null
* ^ ^
* | |
* | |
* next
* pre head
* ================================================================================================================
* 2. null<--------NodeA<--------NodeB NodeC-------->NodeD-------->null
* ^ ^
* | |
* | |
* next
* pre head
* ================================================================================================================
* 3. null<--------NodeA<--------NodeB<--------NodeC NodeD-------->null
* ^ ^
* | |
* | |
* next
* pre head
* ================================================================================================================
* 4. null<--------NodeA<--------NodeB<--------NodeC<--------NodeD null
* ^ ^
* | |
* | |
* next
* pre head
* ================================================================================================================
* 5. return pre;单链表翻转完毕。pre为Node类型。
*/
public static class DoubleNode {
int value;
DoubleNode last;
DoubleNode next;
public DoubleNode(int data) {
value = data;
}
}
//双链表翻转
public static DoubleNode reverseDoubleList(DoubleNode head) {
DoubleNode pre = null;
DoubleNode next = null;
while (head != null) {//只要head不为null,就继续。
next = head.next;//先将next标记在head的下一个节点,即head.next。
head.next = pre;//修改head的向后的指针,为pre。此时pre为null。
head.last = next;//修改head的向前的指针,为next。即head原来的下一个节点。
pre = head;//pre跳到head上。
head = next;//head往后(右)跳一步。
}
return pre;
}
//打印双链表
public static void printDoubleNode(DoubleNode head) {
while (head != null) {
System.out.print(head.value + " ");
head = head.next;
}
System.out.println();
}
/***
* 流程示意图:
* ========> 代表:last
* --------> 代表:next
*
* 0.
* <======== NodeA <======== NodeB <======== NodeC <======== NodeD
* null NodeA --------> NodeB --------> NodeC --------> NodeD --------> null null null
* ^ ^ ^
* | | |
* | | |
* head pre next
* =========================================================================================================================
* 1.
* NodeA ========> NodeB NodeC NodeD
* NodeA <======== NodeB <======== NodeC <======== NodeD
* null <-------- NodeA NodeB --------> NodeC --------> NodeD --------> null
* ^ ^
* | |
* | |
* next
* pre head
* =========================================================================================================================
* 2.
* NodeA ========> NodeB ========> NodeC NodeD
* NodeA NodeB <======== NodeC <======== NodeD
* null <-------- NodeA <-------- NodeB NodeC --------> NodeD --------> null
* ^ ^
* | |
* | |
* next
* pre head
* =========================================================================================================================
* 3.
* NodeA ========> NodeB ========> NodeC ========> NodeD
* NodeA NodeB NodeC <======== NodeD
* null <-------- NodeA <-------- NodeB <-------- NodeC NodeD --------> null
* ^ ^
* | |
* | |
* next
* pre head
* =========================================================================================================================
* 4.
* NodeA ========> NodeB ========> NodeC ========> NodeD ========>
* NodeA NodeB NodeC NodeD
* null <-------- NodeA <-------- NodeB <-------- NodeC <-------- NodeD null
* ^ ^
* | |
* | |
* next
* pre head
* =========================================================================================================================
*/
//for test
//生成一个长度随机,每个节点的值也随机的单链表
public static Node generateRandomLinkedList(int len, int value) {
int size = (int) (Math.random() * (len + 1));
if (size == 0) {
return null;
}
size--;
Node head = new Node((int) (Math.random() * (value + 1)));
Node pre = head;
while (size != 0) {
Node cur = new Node((int) (Math.random() * (value + 1)));
pre.next = cur;
pre = cur;
size--;
}
return head;
}
//生成一个长度随机,每个节点的值也随机的双链表
public static DoubleNode generateRandomDoubleLinkedList(int len, int value) {
int size = (int) (Math.random() * (len + 1));
if (size == 0) {
return null;
}
size--;
DoubleNode head = new DoubleNode((int) (Math.random() * (value + 1)));
DoubleNode pre = head;
while (size != 0) {
DoubleNode cur = new DoubleNode((int) (Math.random() * (value + 1)));
pre.next = cur;
cur.last = pre;
pre = cur;
size--;
}
return head;
}
//for test
//获得单链表的原始顺序
public static List<Integer> getLinkedListOriginOrder(Node head) {
List<Integer> ans = new ArrayList<>();
while (head != null) {
ans.add(head.value);
head = head.next;
}
return ans;
}
public static List<Integer> getDoubleLinkedListOriginOrder(DoubleNode head) {
ArrayList<Integer> ans = new ArrayList<>();
while (head != null) {
ans.add(head.value);
head = head.next;
}
return ans;
}
/**
* @param origin 原始链表
* @param head 翻转链表后的头节点
* @return 检验链表的翻转,是否正确
*/
public static boolean checkLinkedListReverse(List<Integer> origin, Node head) {
for (int i = origin.size() - 1; i >= 0; i--) {
if (origin.get(i) != head.value) {
// if (!origin.get(i).equals(head.value)) {
return false;
}
head = head.next;
}
return true;
}
/**
* @param origin 原始链表
* @param head 翻转双链表后的头节点
* @return 检验双链表的翻转,是否正确
*/
public static boolean checkDoubleLinkedListReverse(List<Integer> origin, DoubleNode head) {
DoubleNode end = null;
for (int i = origin.size() - 1; i >= 0; i--) {
if (origin.get(i) != head.value) {
return false;
}
end = head;//end来到head的位置
head = head.next;//head向后跳一步
}
for (int i = 0; i < origin.size(); i++) {
if (origin.get(i) != end.value) {
return false;
}
end = end.last;//end向前跳一步
}
return true;//如果两个for循环中,都没有返回false,则说明双链表翻转正确,返回true
}
public static void main(String[] args) {
Node n1 = new Node(1);
n1.next = new Node(2);
n1.next.next = new Node(3);
//引用的传递
//f()函数中,虽然修改了n1的指向,但是上游的n1,丝毫不受影响。
//f()函数中的n1,其实只是一个n1的引用(可以理解为复制品,复印件。n1',这个n1'无论如何修改,即使被销毁了,也不影响原来的n1),
f(n1);//f()函数仅仅是修改了n1的指向。仅仅是为了表明:虽然f()函数修改了n1的指向,但是丝毫不影响上游的n1。
System.out.println("n1.value = " + n1.value);//1
System.out.println("==============================");
//翻转单链表
Node head = reverseLinkedList(n1);
//打印单链表
printNode(head);
System.out.println("===========");
System.out.println("===========");
DoubleNode doubleNode1 = new DoubleNode(1);
doubleNode1.next = new DoubleNode(2);
doubleNode1.next.next = new DoubleNode(3);
doubleNode1.next.next.next = new DoubleNode(4);
//翻转双链表
DoubleNode doubleNode = reverseDoubleList(doubleNode1);
//打印双链表
printDoubleNode(doubleNode);
System.out.println("==============================================================================");
/*下一段落,随机生产一个链表,获取原始链表,翻转单链表,检验链表翻转得是否正确*/
int len = 10;
int value = 100;
int testTimes = 10;
System.out.println("test began!");
for (int i = 0; i < testTimes; i++) {
System.out.println();
System.out.println(i + ":");
Node node1 = generateRandomLinkedList(len, value);
printNode(node1);
List<Integer> list = getLinkedListOriginOrder(node1);
System.out.println("list = " + list);
node1 = reverseLinkedList(node1);
if (!checkLinkedListReverse(list, node1)) {
System.out.println("Oops1!");
}
System.out.println("===");
Node node2 = generateRandomLinkedList(len, value);
printNode(node2);
List<Integer> list2 = getLinkedListOriginOrder(node2);
System.out.println("list2 = " + list2);
node2 = reverseLinkedList2(node2);
if (!checkLinkedListReverse(list2, node2)) {
System.out.println("Oops2!");
}
System.out.println("===");
DoubleNode node3 = generateRandomDoubleLinkedList(len, value);
printDoubleNode(node3);
List<Integer> list3 = getDoubleLinkedListOriginOrder(node3);
System.out.println("list3 = " + list3);
node3 = reverseDoubleList(node3);
if (!checkDoubleLinkedListReverse(list3, node3)) {
System.out.println("Oops3!");
}
System.out.println("===");
DoubleNode node4 = generateRandomDoubleLinkedList(len, value);
printDoubleNode(node4);
List<Integer> list4 = getDoubleLinkedListOriginOrder(node4);
System.out.println("list4 = " + list4);
node4 = reverseDoubleList(node4);
if (!checkDoubleLinkedListReverse(list4, node4)) {
System.out.println("Oops4!");
}
}
System.out.println("test finish!");
}
}