java 單鏈表反轉

最近與人瞎聊,聊到各大廠的面試題,其中有一個就是用java實現單鏈表反轉。閑來無事,決定就這個問題進行一番嘗試。

1.準備鏈表

準備一個由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

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

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,001評論 6 537
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,786評論 3 423
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,986評論 0 381
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,204評論 1 315
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,964評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,354評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,410評論 3 444
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,554評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,106評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,918評論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,093評論 1 371
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,648評論 5 362
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,342評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,755評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,009評論 1 289
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,839評論 3 395
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,107評論 2 375

推薦閱讀更多精彩內容

  • 從三月份找實習到現在,面了一些公司,掛了不少,但最終還是拿到小米、百度、阿里、京東、新浪、CVTE、樂視家的研發崗...
    時芥藍閱讀 42,328評論 11 349
  • 轉載請注明出處:http://www.lxweimin.com/p/c65d9d753c31 在上一篇博客《數據結構...
    Alent閱讀 3,525評論 4 74
  • 大學的時候不好好學習,老師在講臺上講課,自己在以為老師看不到的座位看小說,現在用到了老師講的知識,只能自己看書查資...
    和玨貓閱讀 1,467評論 1 3
  • 1 序 2016年6月25日夜,帝都,天下著大雨,拖著行李箱和同學在校門口照了最后一張合照,搬離寢室打車去了提前租...
    RichardJieChen閱讀 5,124評論 0 12
  • 總結 想清楚再編碼 分析方法:舉例子、畫圖 第1節:畫圖分析方法 對于二叉樹、二維數組、鏈表等問題,都可以采用畫圖...
    M_巴拉巴拉閱讀 1,226評論 0 7