1. 程式人生 > >java 單鏈表反轉

java 單鏈表反轉

連結:https://www.jianshu.com/p/d201e6a00e3f

.準備連結串列

準備一個由DataNode組成的單向連結串列,DataNode如下:


public class DataNode {

    private int data; private DataNode next; public int getData() { return data; } public void setData(int data) { this.data = data; } public DataNode getNext() { return next; } public void setNext(DataNode next) { this.next = next; } public DataNode(int data) { this.data = data; } } 

構造連結串列

public class DataChain {
    
    private DataNode head; public DataChain(int size) { DataNode head = new DataNode(0); DataNode cur = head; for (int i = 1; i < size; i++) { DataNode tmp = new DataNode(i); cur.setNext(tmp); cur = tmp; } this.head = head; } public DataNode getHead() { return head; } public void setHead(DataNode head) { this.head = head; } public static void printChain(DataNode head) { StringBuilder sb = new StringBuilder(); DataNode cur = head; sb.append(cur.getData()); while (null != cur.getNext()) { sb.append(" -> "); sb.append(cur.getNext().getData()); cur = cur.getNext(); } System.out.println(sb.toString()); } public static void main(String... strings) { DataChain chain = new DataChain(10); printChain(chain.getHead()); } } 

執行main方法,即構造了一個包含10個node節點的單鏈表。

#執行結果
0 -> 1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> 8 -> 9

2.通過遞迴實現單鏈表反轉

考慮到程式碼的簡潔性,首先考慮的是通過遞迴實現。

    /**
     * 遞迴實現 當棧深度大於12000 則會出現StakOverflowError
     * 
     * @param head
     * @return
     */
    public static DataNode reverse1(DataNode head) { if (null == head || null == head.getNext()) return head; DataNode revHead = reverse1(head.getNext()); head.getNext().setNext(head); head.setNext(null); return revHead; } 

以上即是遞迴實現的原始碼,但是需要考慮的問題是遞迴都在java棧中進行,需要考慮jdk支援的棧的深度。在jdk1.8.0_91版本中,當上述連結串列長度大於12000則會出現StackOverFlowError錯誤。說明對於該版本jdk棧的深度不能大於12000。

3.通過遍歷實現

最通用的實現方式就是遍歷。

/**
     * 遍歷實現 通用實現方法
     * 
     * @param head
     * @return
     */
    public static DataNode reverse2(DataNode head) { if (null == head || null == head.getNext()) return head; DataNode pre = head; DataNode cur = head.getNext(); while (null != cur.getNext()) { DataNode tmp = cur.getNext(); cur.setNext(pre); pre = cur; cur = tmp; } cur.setNext(pre); head.setNext(null); return cur; } 

4.藉助stack實現

考慮到stack具有先進後出這一特性,因此可以藉助於stack資料結構來實現單向連結串列的反轉。

/**
     * 方法3 利用其他資料結構 stack 
     * @param head
     * @return
     */
    public static DataNode reverse3(DataNode head) { Stack<DataNode> stack = new Stack<DataNode>(); for (DataNode node = head; null != node; node = node.getNext()) { stack.add(node); } DataNode reHead = stack.pop(); DataNode cur = reHead; while(!stack.isEmpty()){ cur.setNext(stack.pop()); cur = cur.getNext(); cur.setNext(null); } return reHead; } 

上述實現方法在於操作簡單,對於演算法並不精通的同學可以嘗試。缺點在於需要通過其他資料結構實現,效率會降低,至於效率會降低到什麼程度,後面舉例說明。

5.三種實現方式效率分析

    public static void main(String... strings) { int size = 10; DataChain chain1 = new DataChain(size); printChain(chain1.getHead()); long reverse1_start = System.currentTimeMillis(); DataNode reNode1 = reverse1(chain1.getHead()); long reverse1_cost = System.currentTimeMillis() - reverse1_start; printChain(reNode1); System.out.println("reverse1 cost time is ["+reverse1_cost+"]ms"); DataChain chain2 = new DataChain(size); printChain(chain2.getHead()); long reverse2_start = System.currentTimeMillis(); DataNode reNode2 = reverse2(chain2.getHead()); long reverse2_cost = System.currentTimeMillis() - reverse2_start; printChain(reNode2); System.out.println("reverse2 cost time is ["+reverse2_cost+"]ms"); DataChain chain3 = new DataChain(size); printChain(chain3.getHead()); long reverse3_start = System.currentTimeMillis(); DataNode reNode3 = reverse3(chain3.getHead()); long reverse3_cost = System.currentTimeMillis() - reverse3_start; printChain(reNode3); System.out.println("reverse3 cost time is ["+reverse3_cost+"]ms"); } 

執行結果:

0 -> 1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> 8 -> 9 9 -> 8 -> 7 -> 6 -> 5 -> 4 -> 3 -> 2 -> 1 -> 0 reverse1 cost time is [0]ms 0 -> 1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> 8 -> 9 9 -> 8 -> 7 -> 6 -> 5 -> 4 -> 3 -> 2 -> 1 -> 0 reverse2 cost time is [0]ms 0 -> 1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> 8 -> 9 9 -> 8 -> 7 -> 6 -> 5 -> 4 -> 3 -> 2 -> 1 -> 0 reverse3 cost time is [1]ms 

在上述程式碼基礎上,去掉列印輸出,將size改為10000,結果如下:

reverse1 cost time is [1]ms
reverse2 cost time is [0]ms
reverse3 cost time is [6]ms 

可以看出reverse2 明顯優於其他兩種實現方法。考慮到reverse1最多隻支援12000,因此將size改為100000時,再觀察reverse2和reverse3之間的執行結果:

reverse2 cost time is [6]ms
reverse3 cost time is [25]ms

因此可以看出,最好的方法是採用遍歷的方式進行反轉。