JDK常用数据结构

Posted IT路人乙

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JDK常用数据结构相关的知识,希望对你有一定的参考价值。

在JDK中使用到的数据结构有数组、链表、栈、队列、树、散列和堆等,这部分主要记录数组、链表、栈和队列,其他的数据结构可以参考下一部分。

数组

数组是可以再内存中连续存储多个元素的结构,在内存中的分配也是连续的,数组中的元素通过数组下标进行访问,数组下标从0开始。JDK中代表作:ArrayList<E>,默认大小为10。代码片段

public class ArrayList<E> extends AbstractList<E>
      implements List<E>, RandomAccess, Cloneable, java.io.Serializable
{
  /**
    * Default initial capacity.
    */
  private static final int DEFAULT_CAPACITY = 10;
  ...
  /**
    * The array buffer into which the elements of the ArrayList are stored.
    * The capacity of the ArrayList is the length of this array buffer. Any
    * empty ArrayList with elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA
    * will be expanded to DEFAULT_CAPACITY when the first element is added.
    */
  transient Object[] elementData; // non-private to simplify nested class access
  ...

优点

  • 按照索引查询元素速度快

  • 按照索引遍历数组方便

缺点

  • 数组的大小固定后就无法扩容了

  • 数组只能存储一种类型的数据

  • 添加,删除的操作慢,因为要移动其他的元素

适用范围

频繁查询,对存储空间要求不大,很少增加和删除的情况。

链表

  • 单向链表 - 链接方向是单向的,对链表的访问要通过顺序读取从头部开始,每个结点都有指针指向列表中的下一个结点

  • 双向链表 - 每个结点都有两个指针,分别指向直接后继和直接前驱。从双向链表中的任意一个结点开始,都可以很方便地访问它的前驱结点和后继结点

  • 循环列表 - 表中最后一个结点的指针域指向头结点,整个链表形成一个环

JDK中代表作:LinkedList<E>,为双向链表。结点代码片段

private static class Node<E> {
      E item;
      Node<E> next;
      Node<E> prev;

      Node(Node<E> prev, E element, Node<E> next) {
          this.item = element;
          this.next = next;
          this.prev = prev;
      }
}

LinkedList<E>源码片段

public class LinkedList<E>
  extends AbstractSequentialList<E>
  implements List<E>, Deque<E>, Cloneable, java.io.Serializable
{
  transient int size = 0;

  /**
    * Pointer to first node.
    * Invariant: (first == null && last == null) ||
    *           (first.prev == null && first.item != null)
    */
  transient Node<E> first;

  /**
    * Pointer to last node.
    * Invariant: (first == null && last == null) ||
    *           (last.next == null && last.item != null)
    */
  transient Node<E> last;

  /**
    * Constructs an empty list.
    */
  public LinkedList() {
  }
...

持有链表第一个结点和最后一个结点的指针。

优点

  • 不需要初始化容量,可以任意加减元素

缺点

  • 因为含有大量的指针域,占用空间较大

  • 查找元素需要遍历链表来查找,非常耗时

适用范围

数据量较小,需要频繁增加,删除操作的场景。

堆栈

堆栈是一种运算受限的线性表,限定仅在表尾进行插入和删除操作。一端被称为栈顶,另一端称为栈底。栈的特点是:先进后出,或者说是后进先出,从栈顶放入元素的操作叫入栈,取出元素叫出栈。栈的结构就像一个集装箱,越先放进去的东西越晚才能拿出来,所以,栈常应用于实现递归功能方面的场景。JDK中堆栈的实现代表:Stack<E>,源码片段

...
public class Stack<E> extends Vector<E> {
  /**
    * Creates an empty Stack.
    */
  public Stack() {
  }

  /**
    * Pushes an item onto the top of this stack. This has exactly
    * the same effect as:
    * <blockquote><pre>
    * addElement(item)</pre></blockquote>
    *
    * @param   item   the item to be pushed onto this stack.
    * @return the <code>item</code> argument.
    * @see     java.util.Vector#addElement
    */
  public E push(E item) {
      addElement(item);

      return item;
  }

  /**
    * Removes the object at the top of this stack and returns that
    * object as the value of this function.
    *
    * @return The object at the top of this stack (the last item
    *         of the <tt>Vector</tt> object).
    * @throws EmptyStackException if this stack is empty.
    */
  public synchronized E pop() {
      E       obj;
      int     len = size();

      obj = peek();
      removeElementAt(len - 1);

      return obj;
  }
...

Stack<E>继承了Vector<E>类,不过限制了后者的操作为push入栈和pop出栈。从源码中可看出,push操作是在链表的末端增加元素,pop操作则是在链表末端删除元素并返回。Vector<E>类和ArrayList<E>类相似,使用数组实现;不过不同之处是:a. 前者线程安全,后者线程不安全;b. 前者扩展为原大小的2倍,后者为1.5倍。

队列

和堆栈类似,队列也是一种特殊的线性表。特殊之处在于它只允许表的前端进行删除操作,后端进行插入操作。进行插入操作的端称为队尾,进行删除操作的端称为队头。队列具有先进先出(FIFO)的特性。JDK中实现的队列如下

总的来说,JDK中使用数组和链表实现了有界队列和无界队列,此外,还是实现了不存储数据的中转队列。其中,有界队列有: ArrayBlockingQueue<E>/LinkedBlockingQueue<E>/LinkedBlockingDeque<E>;无界队列有:PriorityBlockingQueue<E>/DelayQueue<E>/LinkedTransferQueue<E>

适用范围

LinkedBlockingDeque应用场景很少,一般用在“工作窃取”模式下,ArrayBlockingQueueLinkedBlockingQueue基本就是数组和链表的区别;PriorityBlockingQueue用在需要排序的队列中,DelayQueue可以用来做一些定时任务或者缓存过期的场景;不存储元素的队列SynchronousQueue用来处理一些高效的透传场景。

以上是关于JDK常用数据结构的主要内容,如果未能解决你的问题,请参考以下文章

JDK常用数据结构

C#常用代码片段备忘

常用python日期日志获取内容循环的代码片段

swift常用代码片段

IOS开发-OC学习-常用功能代码片段整理

21个常用代码片段