LinkedList源碼淺析

package com.zkn.newlearn.collection;
/**
 * 
 * @author zkn 2016-06-25
 *  LinkedList的內(nèi)部數(shù)據(jù)結(jié)構(gòu)是雙向鏈表,
 *  所以定義一個內(nèi)部類与涡,用來表示一個節(jié)點(diǎn)峭梳,
 *  這個節(jié)點(diǎn)包括三個屬性,
 *      1虱而、一個用來表示當(dāng)前元素
 *      2筏餐、一個用來表示上一個元素
 *      3、一個用來表示下一個元素
 *  還需要兩個屬性節(jié)點(diǎn)用來保存鏈表的頭和尾
 */
public class ImitateLinkedListTest02<E> {
    /**
     * 表示頭部
     */
    private Node<E> first;
    /**
     * 表示尾部
     */
    private Node<E> last;
    /**
     * size的大小
     */
    private int size;
    /**
     * 元素的個數(shù)
     */
    public int size(){
        
        return size;
    }
    /**
     * add的方法
     * @param e
     */
    public void add(E e){
        //說明這個時候還沒有進(jìn)行過add操作牡拇,即鏈表中沒有元素
        if(last == null){
            //創(chuàng)建一個新的節(jié)點(diǎn)
            //對于第一個節(jié)點(diǎn)魁瞪,它的上一個元素為不存在所以為null,下一個元素同樣為null
            Node<E> newNode = new Node<E>(e,null,null);
            //在這個鏈表中惠呼,第一個元素為當(dāng)前要插入的節(jié)點(diǎn)导俘,最后一個元素同樣為當(dāng)前要插入的節(jié)點(diǎn)
            first = newNode;
            last = newNode;
        }else{
            //對于鏈表中已經(jīng)存在元素節(jié)點(diǎn)的情況
            //創(chuàng)建出來一個新的節(jié)點(diǎn)
            //對于這種鏈表中已經(jīng)有幾點(diǎn)存在的情況,它的上一個節(jié)點(diǎn)為最后一個元素剔蹋,下一個節(jié)點(diǎn)為null
            Node<E> newNode = new Node<E>(e,last,null);
            //當(dāng)前的最后一個元素的下一個節(jié)點(diǎn)應(yīng)該指向當(dāng)前要插入的這個節(jié)點(diǎn)旅薄。
            //當(dāng)前最后一個元素的下一個節(jié)點(diǎn)指向當(dāng)前要插入的節(jié)點(diǎn),當(dāng)前要插入的節(jié)點(diǎn)的上一個元素指向當(dāng)前的最后一個元素
            //這樣正好構(gòu)成了一個雙向鏈表
            last.next = newNode;
            //最后泣崩,要把最后一個元素節(jié)點(diǎn)變?yōu)楫?dāng)前插入的元素節(jié)點(diǎn)
            last = newNode;
        }
        size++;
    }
    /**
     * 根據(jù)元素位置取元素的值
     * 從這個例子中就可以看出來少梁,為什么LinkedList獲取元素比較慢洛口,因為每次取出元素都有進(jìn)行一次循環(huán)!?Α5谘妗!
     * @param size
     * @return
     */
    public E get(int index){
        checkSize(index);
        //獲取元素的值
        //如果索引小于當(dāng)前元素個數(shù)的一半妨马,就從頭部開始循環(huán)挺举,否則從尾部開始循環(huán)
        if(index < (size >> 1)){
            //把頭給節(jié)點(diǎn),便于下面遞歸循環(huán)
            Node<E> node = first;
            for(int i=0;i<index;i++){
                //循環(huán)遞歸
                node = node.next;
            }
            //返回節(jié)點(diǎn)中的元素
            return node.item;
        }else{
            //把尾給節(jié)點(diǎn)身笤,便于下面遞歸循環(huán)
            Node<E> node = last;
            for(int i=size-1;i>index;i--){
                node = node.prev;
            }
            return node.item;
        }
    }
    /**
     * 獲取第一個元素
     * @return
     */
    public E getFirst(){
        
        if(first == null)
            return null;
        return first.item;
    }
    /**
     * 獲取最后一個元素
     * @return
     */
    public E getLast(){
        
        if(last == null)
            return null;
        return last.item;
    }
    /**
     * 移除對象
     * @return
     */
    public boolean remove(Object obj){
        
        //分兩種情況來處理
        //如果obj == null
        if(obj == null){
            for(Node<E> x = first;x != null;x = x.next){
                if(x.item == null){
                    removeElement(x);
                    return true;
                }
            }
        }else{
            for(Node<E> x = first;x != null;x = x.next){
                if(obj.equals(x.item)){
                    removeElement(x);
                    return true;
                }
            }
        }
        return false;
    }
    
    private E removeElement(Node<E> node) {
        E itemElement = node.item;
        //用來保存prev節(jié)點(diǎn)豹悬,防止后面 當(dāng)node節(jié)點(diǎn)是最后一個節(jié)點(diǎn)的時候, node.prev=null液荸,last為null
        Node<E> prevNode = node.prev;
        //說明node為first節(jié)點(diǎn)
        if(node.prev == null){
            //first節(jié)點(diǎn)的時候需要把node.next變?yōu)閒irst
            first = node.next;
        }else{
            //如果node不是first節(jié)點(diǎn)瞻佛,則把他的上個節(jié)點(diǎn)的指向變成當(dāng)前node的下一個節(jié)點(diǎn)
            //然后把這個節(jié)點(diǎn)的上個節(jié)點(diǎn)的變?yōu)閚ull 相當(dāng)于打斷節(jié)點(diǎn)的左面
            node.prev.next = node.next;
            node.prev = null;
        } 
        //如果node為last節(jié)點(diǎn)
        if(node.next == null){
            //說明node的上一個節(jié)點(diǎn)為last節(jié)點(diǎn)
            last = prevNode;
        }else{
            //說明如果node不是last幾點(diǎn),則把node節(jié)點(diǎn)的指向的下一個元素的上一個節(jié)點(diǎn)變?yōu)楫?dāng)前node的上一個節(jié)點(diǎn)
            //然后把當(dāng)前node節(jié)點(diǎn)的next變?yōu)閚ull 相當(dāng)于打斷節(jié)點(diǎn)的右面
            node.next.prev = prevNode;
            node.next = null;
        }
        node.item = null;
        size --;
        return itemElement;
    }
    /**
     * 檢查元素是否合法
     * @param size2
     */
    private void checkSize(int index) {
        if(index >= size || index < 0){
            throw new IllegalArgumentException("輸入的參數(shù)不合法娇钱,請輸入合法的參數(shù)");
        }
    }
    /**
     * 雙向鏈表的節(jié)點(diǎn)
     * @author zkn
     *
     * @param <E>
     */
    private static class Node<E>{
        //當(dāng)前元素
        E item;
        //上一個
        Node<E> prev;
        //下一個
        Node<E> next;
        
        public Node(E item, Node<E> prev, Node<E> next) {
            this.item = item;
            this.prev = prev;
            this.next = next;
        }
    }
    
    public static void main(String[] args){
        
        ImitateLinkedListTest02<String> linkedList = new ImitateLinkedListTest02<String>();
        linkedList.add("張三");
        linkedList.add("李四");
        linkedList.add("馬六");
        linkedList.add("王五");
        
        linkedList.remove("馬六1");
        
        System.out.println(linkedList.size());
        System.out.println(linkedList.getFirst());
        System.out.println(linkedList.getLast());
        for(int i=0;i<linkedList.size;i++){
            System.out.print(linkedList.get(i)+"->");
        }
        System.out.println("");
    }
}

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末伤柄,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子文搂,更是在濱河造成了極大的恐慌适刀,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,539評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件煤蹭,死亡現(xiàn)場離奇詭異笔喉,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)硝皂,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,594評論 3 396
  • 文/潘曉璐 我一進(jìn)店門常挚,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人稽物,你說我怎么就攤上這事奄毡。” “怎么了贝或?”我有些...
    開封第一講書人閱讀 165,871評論 0 356
  • 文/不壞的土叔 我叫張陵吼过,是天一觀的道長。 經(jīng)常有香客問我咪奖,道長盗忱,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,963評論 1 295
  • 正文 為了忘掉前任羊赵,我火速辦了婚禮售淡,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘慷垮。我一直安慰自己揖闸,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,984評論 6 393
  • 文/花漫 我一把揭開白布料身。 她就那樣靜靜地躺著汤纸,像睡著了一般。 火紅的嫁衣襯著肌膚如雪芹血。 梳的紋絲不亂的頭發(fā)上贮泞,一...
    開封第一講書人閱讀 51,763評論 1 307
  • 那天,我揣著相機(jī)與錄音幔烛,去河邊找鬼啃擦。 笑死,一個胖子當(dāng)著我的面吹牛饿悬,可吹牛的內(nèi)容都是我干的令蛉。 我是一名探鬼主播,決...
    沈念sama閱讀 40,468評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼狡恬,長吁一口氣:“原來是場噩夢啊……” “哼珠叔!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起弟劲,我...
    開封第一講書人閱讀 39,357評論 0 276
  • 序言:老撾萬榮一對情侶失蹤祷安,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后兔乞,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體汇鞭,經(jīng)...
    沈念sama閱讀 45,850評論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,002評論 3 338
  • 正文 我和宋清朗相戀三年庸追,在試婚紗的時候發(fā)現(xiàn)自己被綠了霍骄。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,144評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡锚国,死狀恐怖腕巡,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情血筑,我是刑警寧澤绘沉,帶...
    沈念sama閱讀 35,823評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站豺总,受9級特大地震影響车伞,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜喻喳,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,483評論 3 331
  • 文/蒙蒙 一另玖、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦谦去、人聲如沸慷丽。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,026評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽要糊。三九已至,卻和暖如春妆丘,著一層夾襖步出監(jiān)牢的瞬間锄俄,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,150評論 1 272
  • 我被黑心中介騙來泰國打工勺拣, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留奶赠,地道東北人。 一個月前我還...
    沈念sama閱讀 48,415評論 3 373
  • 正文 我出身青樓药有,卻偏偏與公主長得像毅戈,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子塑猖,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,092評論 2 355

推薦閱讀更多精彩內(nèi)容