链表反转(Java三种实现方式)

链表这个数据结果常常碰见,这里提供一个链表反转的java代码实现,有三种算法,一种是递归的,俩种是非递归的。

首先为了方便测试,在博文最后贴上递归实现链表建立的代码,以供读者快速上手测试,提供的代码能够复制之后直接测试

先看看Node节点把

public class Node {
    //链表用于存储值
    private final int value;
    //指向下一个节点  理解为Node next更加恰当
    private Node node;

    public Node(int value) {
        this.value = value;
        this.node = null;
    }

    public int getValue() {
        return value;
    }

    public Node getNode() {
        return node;
    }

    public void setNode(Node node) {
        this.node = node;
    }

}

看看链表反转递归方法

public Node reverserLinkedList(Node node){
        if (node.getNode() == null || node == null){
            return node;
        }
        Node newdata = reverserLinkedList(node.getNode());
        node.getNode().setNode(node);
        node.setNode(null);
        return newdata;
}
    //这个递归,返回值只是为了控制返回的是最后一个节点
    //而后经过递归经过栈的特性,这里就是让它能够从最后一个节点开始把本身的子节点的子节点改为本身
    //本身的子节点改成null
  • 递归的实现老是这么的简单,代码简练就是递归的好处,并且逻辑易于处理,只要可以出找出一层的逻辑,而后找出特殊值和出口,一个递归就已经完成啦
  • 这里出口显然就是那个if,为的是找到最后一个节点,而后就能够开始往前递归反转,同时这个if能够排除参数只有一个节点,参数为null的状况。
  • 递归的栈累计到最高层的时候(递归本质是栈,每一次递归放入一个栈,若是这层运行结束,就会弹出,运行下一层),最后一个if结束之后, 开始反转, 反转的逻辑其实很简单, 吧当前节点的下一个节点指向本身,而后本身指向null

说完了递归的算法,也了解递归其实就是栈,如今就用相同的逻辑,只不过把递归变成循环,用java自己实现的Stack数据结构编写一个更加高效的代码

public Node reverserLinkedList2(Node node){
    Stack<Node> nodeStack = new Stack<>();
    Node head = null;
    //存入栈中,模拟递归开始的栈状态
    while (node != null){
        nodeStack.push(node);
        node = node.getNode();
    }
    //特殊处理第一个栈顶元素(也就是反转前的最后一个元素,由于它位于最后,不须要反转,若是它参与下面的while,由于它的下一个节点为空,若是getNode(), 那么为空指针异常)
    if ((!nodeStack.isEmpty())){
        head = nodeStack.pop();
    }
    //排除之后就能够快乐的循环
    while (!nodeStack.isEmpty()){
        Node tempNode = nodeStack.pop();
        tempNode.getNode().setNode(tempNode);
        tempNode.setNode(null);
    }
    return head;
}

逻辑一目了然,备注上面的解释已经很清楚啦

还有一个循环写法更加简单,使用俩个指针,不须要栈结构

public Node reverserLinkedList3(Node node){
    //指向空,能够想象成位于第一个节点以前
    Node newNode = null;
    //指向第一个节点
    Node curNode = node;

    //循环中,使用第三变量事先保存curNode的后面一个节点

    while (curNode != null){
        Node tempNode = curNode.getNode();
        //把curNode反向往前指
        curNode.setNode(newNode);
        //newNode向后移动
        newNode = curNode;
        //curNode 向后移动
        curNode = tempNode;
    }

    return newNode;
}

这个的思路就是 俩个指针,把一个链表分红俩个部分, newNode是已经反转部分,curNode是为反转部分,而后经过俩个指针的配合,不断的右移直到前部反转

如今贴其余代码部分啦,先贴链表构建的

public class LinkedListCreator {
    //构建函数
    public Node createLinkedList(List<Integer> list){
        if (list.isEmpty()){
            return null;
        }
        Node headNode = new Node(list.get(0));
        Node tempNode = createLinkedList(list.subList(1, list.size()));
        headNode.setNode(tempNode);
        return headNode;
    }

    //测试方便的打印函数
    public void printList(Node node){
        while (node != null){
            System.out.print(node.getValue());
            System.out.print(" ");
            node = node.getNode();
        }
        System.out.println();
    }
}

main函数

public static void main(String[] args) {
    LinkedListCreator linkedListCreator = new LinkedListCreator();
    Node node = linkedListCreator.createLinkedList(Arrays.asList(1, 2, 3, 4, 5));
    Node node2 = linkedListCreator.createLinkedList(Arrays.asList(1, 2, 3, 4, 5));
    Node node3 = linkedListCreator.createLinkedList(Arrays.asList(1, 2, 3, 4, 5));
    LinkedListReverser linkedListReverser = new LinkedListReverser();

    Node res = linkedListReverser.reverserLinkedList(node);
    Node res2 = linkedListReverser.reverserLinkedList2(node2);
    Node res3 = linkedListReverser.reverserLinkedList3(node3);

    linkedListCreator.printList(res);
    linkedListCreator.printList(res2);
    linkedListCreator.printList(res3);
}

博文是做者本来在其余平台的,现迁移过来

相关文章
相关标签/搜索