LinkedList原始碼淺析

weixin_33912246發表於2017-01-12
package com.zkn.newlearn.collection;
/**
 * 
 * @author zkn 2016-06-25
 *  LinkedList的內部資料結構是雙向連結串列,
 *  所以定義一個內部類,用來表示一個節點,
 *  這個節點包括三個屬性,
 *      1、一個用來表示當前元素
 *      2、一個用來表示上一個元素
 *      3、一個用來表示下一個元素
 *  還需要兩個屬性節點用來儲存連結串列的頭和尾
 */
public class ImitateLinkedListTest02<E> {
    /**
     * 表示頭部
     */
    private Node<E> first;
    /**
     * 表示尾部
     */
    private Node<E> last;
    /**
     * size的大小
     */
    private int size;
    /**
     * 元素的個數
     */
    public int size(){
        
        return size;
    }
    /**
     * add的方法
     * @param e
     */
    public void add(E e){
        //說明這個時候還沒有進行過add操作,即連結串列中沒有元素
        if(last == null){
            //建立一個新的節點
            //對於第一個節點,它的上一個元素為不存在所以為null,下一個元素同樣為null
            Node<E> newNode = new Node<E>(e,null,null);
            //在這個連結串列中,第一個元素為當前要插入的節點,最後一個元素同樣為當前要插入的節點
            first = newNode;
            last = newNode;
        }else{
            //對於連結串列中已經存在元素節點的情況
            //建立出來一個新的節點
            //對於這種連結串列中已經有幾點存在的情況,它的上一個節點為最後一個元素,下一個節點為null
            Node<E> newNode = new Node<E>(e,last,null);
            //當前的最後一個元素的下一個節點應該指向當前要插入的這個節點。
            //當前最後一個元素的下一個節點指向當前要插入的節點,當前要插入的節點的上一個元素指向當前的最後一個元素
            //這樣正好構成了一個雙向連結串列
            last.next = newNode;
            //最後,要把最後一個元素節點變為當前插入的元素節點
            last = newNode;
        }
        size++;
    }
    /**
     * 根據元素位置取元素的值
     * 從這個例子中就可以看出來,為什麼LinkedList獲取元素比較慢,因為每次取出元素都有進行一次迴圈!!!!
     * @param size
     * @return
     */
    public E get(int index){
        checkSize(index);
        //獲取元素的值
        //如果索引小於當前元素個數的一半,就從頭部開始迴圈,否則從尾部開始迴圈
        if(index < (size >> 1)){
            //把頭給節點,便於下面遞迴迴圈
            Node<E> node = first;
            for(int i=0;i<index;i++){
                //迴圈遞迴
                node = node.next;
            }
            //返回節點中的元素
            return node.item;
        }else{
            //把尾給節點,便於下面遞迴迴圈
            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節點,防止後面 當node節點是最後一個節點的時候, node.prev=null,last為null
        Node<E> prevNode = node.prev;
        //說明node為first節點
        if(node.prev == null){
            //first節點的時候需要把node.next變為first
            first = node.next;
        }else{
            //如果node不是first節點,則把他的上個節點的指向變成當前node的下一個節點
            //然後把這個節點的上個節點的變為null 相當於打斷節點的左面
            node.prev.next = node.next;
            node.prev = null;
        } 
        //如果node為last節點
        if(node.next == null){
            //說明node的上一個節點為last節點
            last = prevNode;
        }else{
            //說明如果node不是last幾點,則把node節點的指向的下一個元素的上一個節點變為當前node的上一個節點
            //然後把當前node節點的next變為null 相當於打斷節點的右面
            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("輸入的引數不合法,請輸入合法的引數");
        }
    }
    /**
     * 雙向連結串列的節點
     * @author zkn
     *
     * @param <E>
     */
    private static class Node<E>{
        //當前元素
        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("");
    }
}

相關文章