鏈表反轉(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);
}

博文是做者本來在其餘平臺的,現遷移過來

相關文章
相關標籤/搜索