单链表反转的递归方法和非递归方法

链表的节点可以定义为:

    class Node {
        T data;
        Node next;
    }

测试的输入数据,每次使用root作为方法的入参

 Node root = new Node<>();
        root.data = 0;
        Node preNode = root;
        for (int i = 1; i < 5; i++) {
            Node node = new Node<>();
            node.data = i;
            preNode.next = node;
            preNode = node;
        }

使用循环来翻转单链表

思路

翻转单链表,其实就是将当前节点指向当前节点的上一个节点,但是如果直接赋值(node.next = preNode),那么我们会丢失当前节点和下一个节点的联系,循环继续不下去,所以在这之前需要保存当前节点的下一个节点信息(nextNode = node.next),最后我们需要将指向当前节点的指针向前移动(也就是指向next),继续翻转,知道当前节点的next指向空。

image.png
    public  Node revertByLoop(Node node) {
        Node preNode = null;
        while (node != null) {
            Node nextNode = node.next;
            node.next = preNode;
            preNode = node;
            node = nextNode;
        }
        return preNode;
    }

使用递归来翻转单链表

思路

递归首先是直接“找到”最后一个节点“(反向链表的根节点)并返回,以后每次递归完成都返回这个根节点。假设此时程序执行到返回根节点处,下一步我们需要将根节点指向当前递归的节点(node.next.next = node。这里没有使用header.next = node是因为我们每次需要返回这个header,如果使用header.next那么每次赋值都会覆盖上一次的结果),并将当前节点的next置为null,然后返回根节点。

递归和循环的不同是,每次递归并没有覆盖当前节点的next,而是覆盖”当前节点的下一个节点(原始顺序)“的next

image.png
    public  Node revertByRecursive(Node node) {
        if (node.next == null) {
            return node;
        }
        Node root = revertByRecursive(node.next);
        node.next.next = node;
        node.next = null;
        return root;
    }

其他

其实递归也有一种和循环相似的写法,需要自己保存根节点,我这里是浅拷贝了一个根节点

    public  Node revert(Node node) {
        Node root = new Node<>();
        revert(root, node);
        return root;
    }
    
    public  Node revert(Node root, Node node) {
        if (node.next != null) {
            Node child = revert(root, node.next);
            child.next = node;
        } else {
            root.data = node.data;
            root.next = node.next;
            return root;
        }
        node.next = null;
        return node;
    }

你可能感兴趣的:(单链表反转的递归方法和非递归方法)