线性表-单向链表

169 阅读3分钟

小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。


// 动态数组有个明显的缺点

// 可能会造成内存空间的大量浪费

// 能否用到多少就申请多少内存?

// 链表可以办到这一点

// 链表是一种链式存储的线性表,所有元素的内存地址不一定是连续的

线性表-单向链表

链表的 Node 节点的地址是随机的。

链表的设计:

线性表-单向链表

public class LinkedList<E> {
  private int size;
  private Node<E> first;
  
  private static class Node<E> {
    E element;
    Node<E> next;
    public Node(E element, Node<E> next) {
      this.element = element;
      this.next = next;
    }
  }
}

接口设计:

我们可以参考上篇文章的ArrayList,ArrayList和LinkedList其实接口是一样的,所以我们抽象出,一个接口interface

public interface List<E> {
  static final int ELEMENT_NOT_FOUND = -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);
}

考虑到 LinkedList和ArrayList有一些共用方法。我们抽象出一个抽象类

AbstractList

public abstract class AbstractList<E> implements List<E>  {
  /**
   * 元素的数量
   */
  protected int size;
  /**
   * 元素的数量
   * @return
   */
  public int size() {
    return size;
  }

  /**
   * 是否为空
   * @return
   */
  public boolean isEmpty() {
     return size == 0;
  }

  /**
   * 是否包含某个元素
   * @param element
   * @return
   */
  public boolean contains(E element) {
    return indexOf(element) != ELEMENT_NOT_FOUND;
  }

  /**
   * 添加元素到尾部
   * @param element
   */
  public void add(E element) {
    add(size, element);
  }
  
  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);
    }
  }
}

抽象出来,接口和父类之后。

先对上篇的ArrayList 改造一下,改造为 ArrayList2:

public class ArrayList2<E> extends AbstractList<E> {
  /**
   * 所有的元素
   */
  private E[] elements;
  private static final int DEFAULT_CAPACITY = 10;
  
  public ArrayList2(int capaticy) {
    capaticy = (capaticy < DEFAULT_CAPACITY) ? DEFAULT_CAPACITY : capaticy;
    elements = (E[]) new Object[capaticy];
  }
  
  public ArrayList2() {
    this(DEFAULT_CAPACITY);
  }
  
  /**
   * 清除所有元素
   */
  public void clear() {
    for (int i = 0; i < size; i++) {
      elements[i] = null;
    }
    size = 0;
    
    // 仅供参考
    if (elements != null && elements.length > DEFAULT_CAPACITY) {
      elements = (E[]) new Object[DEFAULT_CAPACITY];
    }
  }

  /**
   * 获取index位置的元素
   * @param index
   * @return
   */
  public E get(int index) { // O(1)
    rangeCheck(index);
    
    return elements[index]; 
  }

  /**
   * 设置index位置的元素
   * @param index
   * @param element
   * @return 原来的元素ֵ
   */
  public E set(int index, E element) { // O(1)
    rangeCheck(index);
    
    E old = elements[index];
    elements[index] = element;
    return old;
  }

  /**
   * 在index位置插入一个元素
   * @param index
   * @param element
   */
  public void add(int index, E element) { 
    /*
     * 最好:O(1)
     * 最坏:O(n)
     * 平均:O(n)
     */
    rangeCheckForAdd(index);
    
    ensureCapacity(size + 1);
    
    for (int i = size; i > index; i--) {
      elements[i] = elements[i - 1];
    }
    elements[index] = element;
    size++;
  } // size是数据规模

  /**
   * 删除index位置的元素
   * @param index
   * @return
   */
  public E remove(int index) {
    /*
     * 最好:O(1)
     * 最坏:O(n)
     * 平均:O(n)
     */
    rangeCheck(index);
    
    E old = elements[index];
    for (int i = index + 1; i < size; i++) {
      elements[i - 1] = elements[i];
    }
    elements[--size] = null;
    
    trim();
    
    return old;
  }

  /**
   * 查看元素的索引
   * @param element
   * @return
   */
  public int indexOf(E element) {
    if (element == null) {
      for (int i = 0; i < size; i++) {
        if (elements[i] == null) return i;
      }
    } else {
      for (int i = 0; i < size; i++) {
        if (element.equals(elements[i])) return i;
      }
    }
    return ELEMENT_NOT_FOUND;
  }
  
  /**
   * 保证要有capacity的容量
   * @param capacity
   */
  private void ensureCapacity(int capacity) {
    int oldCapacity = elements.length;
    if (oldCapacity >= capacity) return;
    
    // 新容量为旧容量的1.5倍
    int newCapacity = oldCapacity + (oldCapacity >> 1);
    
    // 新容量为旧容量的2倍
    // int newCapacity = oldCapacity << 1;
    E[] newElements = (E[]) new Object[newCapacity];
    for (int i = 0; i < size; i++) {
      newElements[i] = elements[i];
    }
    elements = newElements;
    
    System.out.println(oldCapacity + "扩容为" + newCapacity);
  }
  
  private void trim() {
    // 30
    int oldCapacity = elements.length;
    // 15
    int newCapacity = oldCapacity >> 1;
    if (size > (newCapacity) || oldCapacity <= DEFAULT_CAPACITY) return;
    
    // 剩余空间还很多
    E[] newElements = (E[]) new Object[newCapacity];
    for (int i = 0; i < size; i++) {
      newElements[i] = elements[i];
    }
    elements = newElements;
    
    System.out.println(oldCapacity + "缩容为" + newCapacity);
  }
  
  @Override
  public String toString() {
    // size=3, [99, 88, 77]
    StringBuilder string = new StringBuilder();
    string.append("size=").append(size).append(", [");
    for (int i = 0; i < size; i++) {
      if (i != 0) {
        string.append(", ");
      }
      
      string.append(elements[i]);
      
//      if (i != size - 1) {
//        string.append(", ");
//      }
    }
    string.append("]");
    return string.toString();
  }
}

LinkedList 链表实现代码:

public class LinkedList<E> extends AbstractList<E> {
  private Node<E> first;
  private Node<E> last;
  
  private static class Node<E> {
    E element;
    Node<E> prev;
    Node<E> next;
    public Node(Node<E> prev, E element, Node<E> next) {
      this.prev = prev;
      this.element = element;
      this.next = next;
    }
    
    @Override
    public String toString() {
      StringBuilder sb = new StringBuilder();
      
      if (prev != null) {
        sb.append(prev.element);
      } else {
        sb.append("null");
      }
      
      sb.append("_").append(element).append("_");

      if (next != null) {
        sb.append(next.element);
      } else {
        sb.append("null");
      }
      
      return sb.toString();
    }
  }

  @Override
  public void clear() {
    size = 0;
    first = null;
    last = 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;
  }

  @Override
  public void add(int index, E element) {
    rangeCheckForAdd(index);

    // size == 0
    // index == 0
    if (index == size) { // 往最后面添加元素
      Node<E> oldLast = last;
      last = new Node<>(oldLast, element, null);
      if (oldLast == null) { // 这是链表添加的第一个元素
        first = last;
      } else {
        oldLast.next = last;
      }
    } else {
      Node<E> next = node(index); 
      Node<E> prev = next.prev; 
      Node<E> node = new Node<>(prev, element, next);
      next.prev = node;
      
      if (prev == null) { // index == 0
        first = node;
      } else {
        prev.next = node;
      }
    }
    
    size++;
  }

  @Override
  public E remove(int index) {
    rangeCheck(index);

    Node<E> node = node(index);
    Node<E> prev = node.prev;
    Node<E> next = node.next;
    
    if (prev == null) { // index == 0
      first = next;
    } else {
      prev.next = next;
    }
    
    if (next == null) { // index == size - 1
      last = prev;
    } else {
      next.prev = prev;
    }
    
    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_FOUND;
  }
  
  /**
   * 获取index位置对应的节点对象
   * @param index
   * @return
   */
  private Node<E> node(int index) {
    rangeCheck(index);
    
    if (index < (size >> 1)) {
      Node<E> node = first;
      for (int i = 0; i < index; i++) {
        node = node.next;
      }
      return node;
    } else {
      Node<E> node = last;
      for (int i = size - 1; i > index; i--) {
        node = node.prev;
      }
      return node;
    }
  }
  
  @Override
  public String toString() {
    StringBuilder string = new StringBuilder();
    string.append("size=").append(size).append(", [");
    Node<E> node = first;
    for (int i = 0; i < size; i++) {
      if (i != 0) {
        string.append(", ");
      }
      
      string.append(node);
      
      node = node.next;
    }
    string.append("]");
    return string.toString();
  }
}

更多文章请关注我:

  1. 我的个人今日头条主页: www.toutiao.com/c/user/toke…

  2. 我的微信公众号:

线性表-单向链表

  1. 我的掘金主页:

juejin.cn/user/118789…