首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 程式設計入門

Java 實現序列列表:基於陣列的動態線性表完整原始碼解析

     編輯:Java 程式設計入門

序列列表是資料結構中最基礎的線性表實作,以陣列為底層儲存,支援動態擴容。本文提供一個泛型 LineList<E> 完整實作,涵蓋增刪改查、擴容策略、索引檢查、子列表截取等核心功能,適合教學與面試準備。

完整原始碼

import java.util.Arrays;

public class LineList<E> {
    private int size;              // 當前元素個數
    private Object[] array;        // 底層陣列
    private static final int DEFAULT_CAPACITY = 16;  // 預設容量

    /** 無參建構子:使用預設容量 */
    public LineList() {
        this.array = new Object[DEFAULT_CAPACITY];
        this.size = 0;
    }

    /** 指定初始容量 */
    public LineList(int capacity) {
        if (capacity < 0) {
            throw new IllegalArgumentException("非法容量: " + capacity);
        }
        this.array = new Object[capacity];
        this.size = 0;
    }

    /** 指定首個元素與容量 */
    public LineList(E element, int capacity) {
        if (capacity < 1) {
            throw new IllegalArgumentException("容量至少為 1");
        }
        this.array = new Object[capacity];
        this.array[0] = element;
        this.size = 1;
    }

    /** 指定首個元素 (預設容量) */
    public LineList(E element) {
        this.array = new Object[DEFAULT_CAPACITY];
        this.array[0] = element;
        this.size = 1;
    }

    // ==================== 查詢操作 ====================
    
    public int size() { return size; }
    public boolean isEmpty() { return size == 0; }
    
    public boolean contains(E e) { return indexOf(e) != -1; }
    
    public Object[] toArray() { return Arrays.copyOf(array, size); }
    
    @SuppressWarnings("unchecked")
    public E get(int index) {
        checkIndex(index);
        return (E) array[index];
    }
    
    public int indexOf(E e) {
        if (e == null) {
            for (int i = 0; i < size; i++) if (array[i] == null) return i;
        } else {
            for (int i = 0; i < size; i++) if (e.equals(array[i])) return i;
        }
        return -1;
    }
    
    public int lastIndexOf(E e) {
        if (e == null) {
            for (int i = size - 1; i >= 0; i--) if (array[i] == null) return i;
        } else {
            for (int i = size - 1; i >= 0; i--) if (e.equals(array[i])) return i;
        }
        return -1;
    }

    // ==================== 修改操作 ====================
    
    /** 尾部新增 */
    public void add(E e) {
        ensureCapacity(size + 1);
        array[size++] = e;
    }
    
    /** 指定索引插入 */
    public void add(int index, E element) {
        checkIndexForAdd(index);  // 允許 index == size (尾部插入)
        ensureCapacity(size + 1);
        System.arraycopy(array, index, array, index + 1, size - index);
        array[index] = element;
        size++;
    }
    
    /** 替換指定索引元素 */
    @SuppressWarnings("unchecked")
    public E set(int index, E element) {
        checkIndex(index);
        E old = (E) array[index];
        array[index] = element;
        return old;
    }
    
    /** 移除指定索引元素 */
    @SuppressWarnings("unchecked")
    public E remove(int index) {
        checkIndex(index);
        E removed = (E) array[index];
        fastRemove(index);
        return removed;
    }
    
    /** 移除所有符合元素 */
    public void removeAll(E e) {
        if (e == null) {
            for (int i = 0; i < size; i++) {
                if (array[i] == null) fastRemove(i);
            }
        } else {
            for (int i = 0; i < size; i++) {
                if (e.equals(array[i])) fastRemove(i);
            }
        }
    }
    
    /** 清空列表 */
    public void clear() {
        Arrays.fill(array, null);
        size = 0;
    }

    // ==================== 進階操作 ====================
    
    /** 截取子列表 [fromIndex, toIndex] 閉區間 */
    public LineList<E> subList(int fromIndex, int toIndex) {
        if (fromIndex < 0 || fromIndex >= size) {
            throw new IndexOutOfBoundsException("起始索引越界: " + fromIndex);
        }
        if (toIndex < 0 || toIndex >= size) {
            throw new IndexOutOfBoundsException("結束索引越界: " + toIndex);
        }
        if (fromIndex > toIndex) {
            throw new IllegalArgumentException("起始索引不可大於結束索引");
        }
        
        LineList<E> sub = new LineList<>();
        for (int i = fromIndex; i <= toIndex; i++) {
            sub.add((E) array[i]);
        }
        return sub;
    }

    // ==================== 內部輔助方法 ====================
    
    /** 擴容確保最小容量 */
    private void ensureCapacity(int minCapacity) {
        if (minCapacity - array.length > 0) {
            int newCapacity = array.length + (array.length >> 1);  // 1.5 倍擴容
            if (newCapacity < minCapacity) newCapacity = minCapacity;
            if (newCapacity > Integer.MAX_VALUE - 8) newCapacity = Integer.MAX_VALUE;
            array = Arrays.copyOf(array, newCapacity);
        }
    }
    
    /** 快速移除 (內部用,不做索引檢查) */
    private void fastRemove(int index) {
        int numMoved = size - index - 1;
        if (numMoved > 0) {
            System.arraycopy(array, index + 1, array, index, numMoved);
        }
        array[--size] = null;  // 釋放引用助 GC
    }
    
    /** 索引檢查 (查詢/修改/刪除用,範圍 [0, size-1]) */
    private void checkIndex(int index) {
        if (index < 0 || index >= size) {
            throw new IndexOutOfBoundsException("索引越界: " + index + ", size: " + size);
        }
    }
    
    /** 插入索引檢查 (範圍 [0, size]) */
    private void checkIndexForAdd(int index) {
        if (index < 0 || index > size) {
            throw new IndexOutOfBoundsException("插入索引越界: " + index + ", size: " + size);
        }
    }
}

核心設計亮點解析

特性實作細節對應 JDK ArrayList
擴容策略1.5 倍 (舊容量 + 舊容量/2)1.5 倍 (Java 8+)
擴容觸發ensureCapacity(size+1)grow(minCapacity)
插入/刪除System.arraycopy 位移元素同
null 元素支援完整支援同
快速失敗無 (未實作 modCount)有 (modCount + Iterator)
序列化支援無實作 Serializable

關鍵方法時間複雜度

與 JDK ArrayList 差異補充

  • 無 Iterator 實作:教學簡化,實際需實作 Iterable<E> 介面
  • 無 modCount 機制:多執行緒下迭代不安全,JDK 透過 modCount 實現 fail-fast
  • subList 回傳新實例:JDK 回傳 SubList 視圖,共享底層陣列,修改會同步反映
  • 未實作 Collection/List 介面:教學專用,生產環境請直接使用 ArrayList
  • 擴容上限處理:Integer.MAX_VALUE - 8 為 JVM 陣列最大長度保留空間

測試驗證範例

public static void main(String[] args) {
    LineList<String> list = new LineList<>();
    list.add("A"); list.add("B"); list.add("C");
    list.add(1, "X");  // [A, X, B, C]
    System.out.println(Arrays.toString(list.toArray()));
    
    list.remove(2);    // 移除 B -> [A, X, C]
    list.set(0, "Z");  // [Z, X, C]
    System.out.println("索引 1: " + list.get(1));  // X
    System.out.println("長度: " + list.size());    // 3
    System.out.println("包含 X: " + list.contains("X"));  // true
    System.out.println("X 索引: " + list.indexOf("X"));   // 1
    
    LineList<String> sub = list.subList(0, 1);  // [Z, X]
    System.out.println("子列表: " + Arrays.toString(sub.toArray()));
}
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved
操作時間複雜度說明
get(index) / set(index, e)O(1)陣列隨機存取
add(e) (尾部)O(1) 攤還偶爾觸發 O(n) 擴容
add(index, e) / remove(index)O(n)需位移後續元素
contains / indexOf / removeAllO(n)線性掃描
subListO(k)k = 子列表長度