1. 程式人生 > 電腦技巧 >Excel 儲存格範圍公式寫法、交集、聯集教學與範例

Excel 儲存格範圍公式寫法、交集、聯集教學與範例

Java集合框架實現兩個兩種線性表,第一種是陣列的實現ArrayList,第二種則是連結串列的實現LinkedList。作為連結串列,LinkedList具有增加和刪除效率高的特點,但是其也有缺點,就是無法隨機訪問。

下面就結合LinkedList常用的方法對該實現的原始碼進行分析。

1. 概括

LinkedList實現了List, Deque,Cloneable以及Serializable介面。說明使用LinkedList不僅可以使用基本的連結串列操作,同時還能使用雙端佇列以及棧的操作。

LinkedList的結點實現是其內部定義的私有靜態類Node。Node類程式碼如下:

 1 private static class Node<E> {
 2         E item;
 3         Node<E> next;
 4         Node<E> prev;
 5 
 6         Node(Node<E> prev, E element, Node<E> next) {
 7             this.item = element;
 8             this.next = next;
 9             this.prev = prev;
10         }
11 }

很顯然從這裡我們能知道,LinkedList實際上是雙鏈表的實現。

在LlinkedList類裡關鍵的屬性有以下三個:

1     transient int size = 0;
2     transient Node<E> first;
3     transient Node<E> last;

size表示連結串列裡結點的數量,first指向連結串列的頭結點,last指向連結串列的尾結點。

2. 構造器

LinkedList提供了兩個構造器,一個是無參的預設構造器,沒有執行任何操作,另外一個是引數為Collection子類的構造器,該Collection子類的實際型別必須是LinkedList的泛型的子類,該構造器程式碼如下:

1 public LinkedList(Collection<? extends E> c) {
2         this();
3         addAll(c);
4     }
5 public boolean addAll(Collection<? extends E> c) {
6         return addAll(size, c);
7     }

這個構造器呼叫過載的addAll方法,將集合c的所有元素新增到連結串列的結尾。實質上是呼叫另外一個版本的addAll方法。下面具體展開。

首先檢查index是否合法,之後集合c變成Object陣列,檢查Object陣列的大小,如果為0則新增失敗。之後找到index位置的連結串列,從index位置開始插入,最後連線上原本的連結串列結點。

public boolean addAll(int index, Collection<? extends E> c) {
        //檢查下標是否合法
        checkPositionIndex(index);
    //將集合c轉換成Object陣列
        Object[] a = c.toArray();
        int numNew = a.length;
    //檢查Object陣列長度,如果為0說明沒有需要新增的元素
        if (numNew == 0)
            return false;
    //succ指向下標對應的結點,pred則是succ的前驅
        Node<E> pred, succ;
    //如果下標正好是連結串列長度,則
        if (index == size) {
            succ = null;
            pred = last;
        } else {
            //呼叫node方法返回特定下標的結點,查詢方法首先根據下標是否超過連結串列長度一半,超過或者等於連結串列長度一半
            //則從尾結點last開始,從尾向index查詢,如果沒有超過連結串列長度一半,則從頭結點first開始,從頭向index找
            succ = node(index);
            pred = succ.prev;
        }
    //開始將Obejct陣列的元素插入到index之後,首先new一個新的結點,其後繼是pred,之後檢查pred如果是空,說明此時newNode是頭結點(?),如果pred非空
    //則按照如圖2.1的方式連線雙鏈表的兩個結點,一直迴圈直到Object數組裡的元素都被連線上。
        for (Object o : a) {
            @SuppressWarnings("unchecked") E e = (E) o;
            Node<E> newNode = new Node<>(pred, e, null);
            if (pred == null)
                first = newNode;
            else
                pred.next = newNode;
            pred = newNode;
        }
    //如果succ為空,說明是在連結串列的結尾插入集合裡的所有元素,則last指向pred
        if (succ == null) {
            last = pred;
        } else {
   //否則直接連線之前連結串列裡的元素
            pred.next = succ;
            succ.prev = pred;
        }
    //修改連結串列的長度
        size += numNew;
    //
        modCount++;
        return true;
    }

3. add方法

add方法有兩個過載的版本,一個是隻有一個泛型引數的版本,也是最常用的版本,另外一個是往特定位置index插入的版本,下面分析最常用的版本。

add(E e)方法將元素用尾插法插入到連結串列的結尾。首先new一個前驅為last的新節點newNode,之後last指向新的尾結點newNode,最後檢查之前的尾結點如果為空,則新生成的結點作為頭結點,否則將原本的尾結點的後繼指向newNode,並給連結串列的長度加一

 1 public boolean add(E e) {
 2         linkLast(e);
 3         return true;
 4     }
 5 void linkLast(E e) {
 6         final Node<E> l = last;
 7         final Node<E> newNode = new Node<>(l, e, null);
 8         last = newNode;
 9         if (l == null)
10             first = newNode;
11         else
12             l.next = newNode;
13         size++;
14         modCount++;
15     }

4. get與contains方法

許多人在使用LinkedList的時候以為其實現的get方法能隨機訪問,實際上LinkedList實現的get方法還是要遍歷連結串列,其程式碼如下:

1 public E get(int index) {
2         checkElementIndex(index);
3         return node(index).item;
4     }

首先檢查下標是否合法,合法的話呼叫之前分析addAll時出現過的方法node(int index),這個方法返回特定下標的結點,根據下標是否超過連結串列大小的一半來決定,之前已經分析過了,就不再贅述。故在需要大量隨機訪問的情況下,還是推薦使用ArrayList實現,當然,如果連結串列長度不是很長,那也無所謂。

contains方法當連結串列裡存在引數指定的物件時返回true,這裡的存在,指的是在引數物件o非空的情況下,存在至少一個連結串列結點裡的item能使得o.equals(item)為真。contains方法本質上是呼叫indexOf方法,即返回特定元素被儲存在連結串列結點的下標,indexOf方法如果找不到則返回-1。

5. remove方法

remove方法刪除一個與引數相同的元素,準確的說是在連結串列裡刪除下標最小的與引數相同的元素。

刪除的方法是從頭向尾遍歷連結串列,找到首次出現的,與引數相同的元素,呼叫unlink方法,在雙鏈表中斷開一個結點(具體過程比較簡單就不展開了),之後將被刪除的元素存在的結點的item置為null,並返回被刪除的元素。