順序存儲線性表是數據結構入門的核心內容,本文提供一個基於泛型、支援動態擴容(模擬)、完整 CRUD 操作的 Java 實現,並對關鍵邏輯進行深度解析,適合教學演示與面試準備。
package com.ncu.list;
/**
* 順序存儲線性表(教學演示版)
*
* 特性:泛型、固定容量、1-based 索引對外、基礎 CRUD
*
*/
public class SquenceList {
private int capacity; // 最大容量
private Object[] elements; // 底層數組
private int size = 0; // 當前元素個數
public SquenceList() {
this(10); // 默認容量 10
}
public SquenceList(int capacity) {
if (capacity <= 0) throw new IllegalArgumentException("Capacity must be positive");
this.capacity = capacity;
this.elements = new Object[capacity];
}
// ==================== 核心輔助方法 ====================
/**
* 索引合法性檢查(1-based)
*/
private void checkIndex(int index) {
if (index < 1 || index > size) {
throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + size);
}
}
/**
* 插入位置合法性檢查(1-based,允許 size+1 即尾插)
*/
private void checkInsertIndex(int index) {
if (index < 1 || index > size + 1) {
throw new IndexOutOfBoundsException("Insert index: " + index + ", Size: " + size);
}
}
/**
* 容量檢查
*/
private void ensureCapacity() {
if (size >= capacity) {
throw new IllegalStateException("List is full, capacity: " + capacity);
}
}
// ==================== 基礎查詢 ====================
public int size() {
return size;
}
public boolean isEmpty() {
return size == 0;
}
/**
* 獲取指定位置元素(1-based)
*/
@SuppressWarnings("unchecked")
public T get(int index) {
checkIndex(index);
return (T) elements[index - 1];
}
// ==================== 插入操作 ====================
/**
* 尾部插入
*/
public void add(T element) {
ensureCapacity();
elements[size++] = element;
}
/**
* 指定位置插入(1-based)
* 將 index 及之後元素向後移動一位
*/
public void add(T element, int index) {
checkInsertIndex(index);
ensureCapacity();
// 從後向前移動,避免覆蓋
for (int i = size; i >= index; i--) {
elements[i] = elements[i - 1];
}
elements[index - 1] = element;
size++;
}
// ==================== 刪除操作 ====================
/**
* 按位置刪除(1-based)
*/
@SuppressWarnings("unchecked")
public T remove(int index) {
checkIndex(index);
T removed = (T) elements[index - 1];
// 從前向後移動,覆蓋被刪位置
for (int i = index; i < size; i++) {
elements[i - 1] = elements[i];
}
elements[--size] = null; // 幫助 GC
return removed;
}
/**
* 按元素刪除首次出現
*/
public boolean removeElement(T element) {
for (int i = 0; i < size; i++) {
if (element == null ? elements[i] == null : element.equals(elements[i])) {
remove(i + 1); // 轉 1-based
return true;
}
}
return false;
}
// ==================== 其他操作 ====================
/**
* 刪除最後一個元素
*/
public void deleteLast() {
if (isEmpty()) {
throw new IllegalStateException("List is empty");
}
elements[--size] = null;
}
/**
* 清空列表
*/
public void clear() {
for (int i = 0; i < size; i++) {
elements[i] = null;
}
size = 0;
}
/**
* 打印所有元素
*/
public void showList() {
if (isEmpty()) {
System.out.println("List is empty");
return;
}
for (int i = 0; i < size; i++) {
System.out.println("[" + (i + 1) + "] " + elements[i]);
}
System.out.println("------------ size=" + size);
}
// ==================== 測試入口 ====================
public static void main(String[] args) {
SquenceList list = new SquenceList<>(10);
// 尾插
list.add(10);
list.add(20);
list.add(30);
System.out.println("After tail insert:");
list.showList(); // [1]10 [2]20 [3]30
// 指定位置插入
list.add(15, 2); // 在位置 2 插入 15
System.out.println("After insert 15 at pos 2:");
list.showList(); // [1]10 [2]15 [3]20 [4]30
// 獲取元素
System.out.println("Element at pos 3: " + list.get(3)); // 20
// 按位置刪除
list.remove(2); // 刪除 15
System.out.println("After remove pos 2:");
list.showList(); // [1]10 [2]20 [3]30
// 按元素刪除
list.removeElement(30);
System.out.println("After remove element 30:");
list.showList(); // [1]10 [2]20
// 邊界測試
try {
list.add(99, 5); // 非法位置
} catch (IndexOutOfBoundsException e) {
System.out.println("Expected exception: " + e.getMessage());
}
}
}
for (int i = size; i >= index; i--) {
elements[i] = elements[i - 1];
}
for (int i = index; i < size; i++) {
elements[i - 1] = elements[i];
}
elements[--size] = null;
教材習慣 1-based,Java 數組 0-based。本實現採用公共方法統一轉換策略:
| 功能 | 實現思路 |
|---|---|
| 動態擴容 | `ensureCapacity()` 中 `Arrays.copyOf(elements, newCapacity)`,擴容因子 1.5 |
| 實現 List 接口 | `implements List |
| 迭代器支援 | 實現 `Iterable |
| 序列化 | 實現 `Serializable`,`elements` 标记 `transient`,自定義 `writeObject/readObject` |
| 並發安全 | 加 `ReentrantReadWriteLock` 或使用 `CopyOnWriteArrayList` 替代 |
掌握順序表底層機制,是理解 ArrayList、Vector、ArrayDeque 等容器源碼的基石。建議手寫一次完整實現,再對比 JDK 源碼深化理解。