单链表翻转,和双链表翻转

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!");
    }
}

 

posted @ 2022-07-30 22:09  TheFloorIsNotTooHot  阅读(37)  评论(0)    收藏  举报