1、連結串列
連結串列是一種鏈式儲存的線性表,所有元素的記憶體地址不一定是連續的。
2、介面設計
連結串列的大部分介面與 動態陣列 是一致的。因此可以將這些方法設計成一個介面List。
public interface List<E> { //元素未找到 public static final int ELEMENT_NOT_FOUNT = -1; /** * 清除所有元素 */ void clear(); /** * 元素的數量 * @return */ int size(); /** * 是否為空 * @return */ boolean isEmpty(); /** * 是否包含某個元素 * @param element * @return */ boolean contains(E element); /** * 新增元素到尾部 * @param element */ void add(E element); /** * 獲取index位置的元素 * @param index * @return */ E get(int index); /** * 設定index位置的元素 * @param index * @param element * @return 原來的元素ֵ */ E set(int index, E element); /** * 在index位置插入一個元素 * @param index * @param element */ void add(int index, E element); /** * 刪除index位置的元素 * @param index * @return */ E remove(int index); /** * 檢視元素的索引 * @param element * @return */ int indexOf(E element); }
在動態陣列和連結串列的實現類中,存在一些重複程式碼,可以設計一個抽象類AbstractList,由該抽象類實現介面List,在由動態陣列和連結串列的實現類繼承即可。
public abstract class AbstractList<E> implements List<E> { //元素數量 protected int size = 0; /** * 返回元素的數量 * @return */ public int size() { return this.size; } /** * 是否為空 * @return */ public boolean isEmpty() { return size == 0; } /** * 是否包含某個元素 * @param element * @return */ public boolean contains(E element) { return indexOf(element) != ELEMENT_NOT_FOUNT; } /** * 新增元素到尾部 * @param element */ public void add(E element) { this.add(size, element); } //設定成protected,可由子類呼叫 protected void outOfBounds(int index) { throw new IndexOutOfBoundsException("Index: " + index + ",Size: " + size); } protected void rangeCheck(int index) { if (index < 0 || index >= size) { outOfBounds(index); } } protected void rangeCheckForAdd(int index) { if (index < 0 || index > size) { outOfBounds(index); } } }
3、連結串列程式碼實現
注意:在編寫連結串列過程中,要注意邊界測試,比如 index 為 0 、size – 0 、size 時
package com.xpp; public class LinkedList<E> extends AbstractList<E> { private Node<E> first; @Override public void clear() { size = 0; first = null; } @Override public E get(int index) { return node(index).element; } @Override public E set(int index, E element) { Node<E> node = node(index); E old = node.element; node.element = element; return old; } /** * 在index位置新增元素 * @param index * @param element */ @Override public void add(int index, E element) { rangeCheckForAdd(index); if (index == 0) {//注意 0 位置 first = new Node<>(element, first); } else { Node<E> prev = node(index - 1); prev.next = new Node<>(element, prev.next); } size++; } /** * 獲取index位置對應的節點物件 * @param index * @return */ private Node<E> node(int index) { rangeCheck(index); Node<E> node = first; for (int i = 0; i < index; i++) { node = node.next; } return node; } @Override public E remove(int index) { rangeCheck(index); Node<E> node = first; if (index == 0) { first = first.next; } else { Node<E> prev = node(index - 1); node = prev.next; prev.next = prev.next.next; } size--; return node.element; } @Override public int indexOf(E element) { if (element == null) { Node<E> node = first; for (int i = 0; i < size; i++) { if (node.element == null) { return i; } node = node.next; } } else { Node<E> node = first; for (int i = 0; i < size; i++) { if (element.equals(node.element)) { return i; } node = node.next; } } return ELEMENT_NOT_FOUNT; } private static class Node<E> { E element; Node<E> next; public Node(E element, Node<E> next) { this.element = element; this.next = next; } } @Override public String toString() { StringBuilder str = new StringBuilder(); str.append("Size: ").append(size).append(", elements=["); Node<E> node = first; for (int i = 0; i < size; i++) { if (i != 0) { str.append(", "); } str.append(node.element); node = node.next; } str.append("]"); return str.toString(); } }