Java核心技术笔记——数据结构(3)

来源:互联网 发布:荣耀盒子pro与网络连接 编辑:程序博客网 时间:2024/06/06 02:11

本篇主要分析链表(LinkedList),上一篇中通过分析数组列表(ArrayList)源码,发现在列表中间位置添加和删除元素时,ArrayList的元素位置要整体移动,这样效率很低,然而,LinkedList则不同,Java中的链表是双向链接的,即每个节点存储前一个节点的引用,也存储后一个节点的引用(如下图)。


这里写图片描述

1 LinkedList 类关系图


这里写图片描述

LinkedList主要实现了List、Deque、Cloneable、Serializable接口,继承了AbstractSequentialList抽象类。
List接口定义了数组列表必须实现的方法
AbstractSequentialList继承AbstractList,实现了List中的通用的方法;
Deque接口上一篇提到过,是双端队列接口;
Cloneable接口可以实现对象的克隆;
Serializable接口标识序列号;

2 LinkedList源码分析

2.1 链表节点类

/*** 链表节点类是LinkedList的静态内部类*/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;    }}

2.2 属性和构造函数

 /** * 链表大小属性 */transient int size = 0;/** * 链表首节点 */transient Node<E> first;/** * 链表尾节点 */transient Node<E> last;/** *默认无参数构造函数 */public LinkedList() {}/** * 根据传入的集合对象,构造链表 */public LinkedList(Collection<? extends E> c) {    this();    //参考2.3节添加集合到链表中方法    addAll(c);}

2.3 添加节点

/** * 暴露的添加节点方法 */public boolean add(E e) {    linkLast(e);    return true;} /** * 链接到LinkedList的末节点 */void linkLast(E e) {    //把last赋值给l    final Node<E> l = last;    //把原来的last赋值给新节点的首位置,    final Node<E> newNode = new Node<>(l, e, null);    last = newNode;    //如果添加的是第一个元素,则把构造的新节点,赋值给first     if (l == null)        first = newNode;    else       //如果添加的是中间元素,则把构造的新节点,赋值l指向下一个节点的引用,也就是顺序添加到后面        l.next = newNode;    // LinkedList 长度增加1    size++;    modCount++;}/** * 添加一个集合到链表中 */public boolean addAll(Collection<? extends E> c) {    return addAll(size, c);}/** * 添加集合到链表的index处。 */public boolean addAll(int index, Collection<? extends E> c) {    checkPositionIndex(index);    //将传入的c集合转换为Object数组    Object[] a = c.toArray();    int numNew = a.length;    //如果传入的集合为空,则返回false    if (numNew == 0)        return false;    Node<E> pred, succ;    if (index == size) {        //默认在链表末尾插入集合元素        succ = null;        pred = last;    } else {       //在指定位置插入集合元素        succ = node(index);        pred = succ.prev;    }    for (Object o : a) {        //逐个访问Object数组的元素,插入到链表中        @SuppressWarnings("unchecked") E e = (E) o;        Node<E> newNode = new Node<>(pred, e, null);        if (pred == null)            first = newNode;        else            pred.next = newNode;        pred = newNode;    }    if (succ == null) {        //如果默认插入链表末尾,将last置为null        last = pred;    } else {       //插入链表到链表中间        pred.next = succ;        succ.prev = pred;    }    //链表大小增加为size+numNew    size += numNew;    modCount++;    return true;}/** * 判断位置是否超出边界 */private boolean isPositionIndex(int index) {    return index >= 0 && index <= size;}//如果超出边界,抛出异常private void checkPositionIndex(int index) {    if (!isPositionIndex(index))        throw new IndexOutOfBoundsException(outOfBoundsMsg(index));} /** * 超出边界抛出异常信息 */private String outOfBoundsMsg(int index) {    return "Index: "+index+", Size: "+size;}

2.4 移除节点

/** * 从链表移除元素 */public boolean remove(Object o) {    if (o == null) {       //如果传入的对象为null,逐个查询链表中的对象        for (Node<E> x = first; x != null; x = x.next) {            if (x.item == null) {                //如果有null元素,删除                unlink(x);                return true;            }        }    } else {        //如果传入的对象为不为null        for (Node<E> x = first; x != null; x = x.next) {            if (o.equals(x.item)) {                //如果有相等元素,删除                unlink(x);                return true;            }        }    }    return false;}/** * 删除节点 */E unlink(Node<E> x) {    // assert x != null;    final E element = x.item;    final Node<E> next = x.next;    final Node<E> prev = x.prev;    if (prev == null) {        first = next;    } else {        prev.next = next;        x.prev = null;    }    if (next == null) {        last = prev;    } else {        next.prev = prev;        x.next = null;    }    x.item = null;    size--;    modCount++;    return element;}/** * 移除指定位置的元素 */public E remove(int index) {    checkElementIndex(index);    //删除指定位置节点    return unlink(node(index));}/** * 检查index是否超出边界 */private void checkElementIndex(int index) {    if (!isElementIndex(index))        throw new IndexOutOfBoundsException(outOfBoundsMsg(index));}/** * 返回指定位置的节点 */Node<E> node(int index) {    // assert isElementIndex(index);    if (index < (size >> 1)) {        Node<E> x = first;        for (int i = 0; i < index; i++)            x = x.next;        return x;    } else {        Node<E> x = last;        for (int i = size - 1; i > index; i--)            x = x.prev;        return x;    }}

2.5 获取节点

/** * 获取指定位置的节点 */public E get(int index) {    checkElementIndex(index);    //返回指定位置的节点值,这里访问效率不如ArrayList。    return node(index).item;}
0 0
原创粉丝点击