LinkedList

2019-09-26  本文已影响0人  sizuoyi00

几句话证明你看过LinkedList的源码
LinkedList同时实现了List接口和Deque接口,可以当做一个链表容器,也当做一个队列(Queue),还可以当做一个栈(Stack)。
推荐栈和队列(即对两端进行操作)使用AarryDeque,根据索引位置增删使用LinkedList
链表(查询慢,增删快,线程不安全,允许元素重复和null,增删都是在中间效率会较低(源码遍历有从前或从后遍历,所以最慢的遍历是中间))

关于循环删除元素,普通for循环,不会报错,会导致下标紊乱,产生数据错误或数组越界
增强for循环,由于删除修改了modCount,导致fail-fast,所以会报错ConcurrentModificationException
迭代器删除(iterator.remove(),而不是list.remove()),会更新modCount与expectedModCount,所以支持迭代删除。

1.双向链表

成员变量包含
first头节点 last尾节点 size长度
内部类

private static class Node<E> {
        //上一节点
        Node<E> prev;
        //下一节点
        Node<E> next;
        //当前节点值
        E item;

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

2.头尾节点修饰符为transient

transient关键字了解
简单概括:实现Serilizable接口,将不需要序列化的属性前添加关键字transient,序列化对象的时候,这个属性就不会序列化到指定的目的地中

3.获取node元素效率提升小细节

/**
     * 获取指定角标元素
     */
    Node<E> node(int index) {
        // assert isElementIndex(index);

        //根据角标与长度一半对比,选择从头遍历还是从尾遍历到指定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;
        }
    }

4.add方法
插入新节点,处理前驱后继,完成链接

/**
     * 插入元素-指定节点
     * @param index
     * @param element
     */
    public void add(int index, E element) {
        checkPositionIndex(index);

        if (index == size)
            linkLast(element);
        else
            linkBefore(element, node(index));
    }

    /**
     * 插入元素-默认尾节点
     * @param e
     * @return
     */
    public boolean add(E e) {
        linkLast(e);
        return true;
    }

    /**
     * 尾节点插入元素
     */
    void linkLast(E e) {
        //“原尾节点”
        final Node<E> l = last;
        //创建以尾节点为前驱的 “新尾节点”
        final Node<E> newNode = new Node<>(l, e, null);
        //将“新尾节点”赋值给 “尾节点”
        last = newNode;

        //空链表
        if (l == null)
            //既是头节点也是尾节点
            first = newNode;
        else
            //将“原尾节点”的后置改为 “新尾节点”
            l.next = newNode;
        size++;
        modCount++;
    }

    /**
     * Inserts element e before non-null Node succ.
     */
    void linkBefore(E e, Node<E> succ) {
        // assert succ != null;
        final Node<E> pred = succ.prev;
        //创建以上一节点为前驱,当前节点为后继的 新节点
        final Node<E> newNode = new Node<>(pred, e, succ);
        //“当前节点”的前驱 为 “新节点”
        succ.prev = newNode;
        if (pred == null)
            //头节点插入节点
            //头节点为 “新节点”
            first = newNode;
        else
            //中间插入节点
            //“上一节点”的后继为“新节点”
            pred.next = newNode;
        size++;
        modCount++;
    }

5.remove方法

处理前驱后继,隔p链接

/**
     * 删除指定元素
     * @param o
     * @return
     */
    public boolean remove(Object o) {
        if (o == null) {
            for (Node<E> x = first; x != null; x = x.next) {
                if (x.item == null) {
                    unlink(x);
                    return true;
                }
            }
        } else {
            for (Node<E> x = first; x != null; x = x.next) {
                if (o.equals(x.item)) {
                    unlink(x);
                    return true;
                }
            }
        }
        return false;
    }

    /**
     * 删除指定角标元素
     * @param index
     * @return
     */
    public E remove(int index) {
        checkElementIndex(index);
        return unlink(node(index));
    }

    /**
     * Unlinks non-null node x.
     */
    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;
    }

6.fast-fail机制

linkedlist可正反双向迭代

/**
     * ListItrItr-ListIterator是Iterator(迭代器)的实现类
     */
    private class ListItr implements ListIterator<E> {
        //上一次返回的节点
        private Node<E> lastReturned;
        //下一个节点
        private Node<E> next;
        //下一个节点角标
        private int nextIndex;
        //期望的改变计数。用来实现fail-fast机制。
        private int expectedModCount = modCount;

        //从index位置开始进行迭代
        ListItr(int index) {
            // assert isPositionIndex(index);
            //半数以下 从前往后,半数以上 从前往后
            next = (index == size) ? null : node(index);
            nextIndex = index;
        }

        //是否存在下一个元素
        public boolean hasNext() {
            //通过元素角标是否等于“双向链表大小”判断
            return nextIndex < size;
        }

        //获取下一个元素
        public E next() {
            //期望的改变计数与modCount比较
            checkForComodification();
            if (!hasNext())
                throw new NoSuchElementException();

            lastReturned = next;
            next = next.next;
            nextIndex++;
            return lastReturned.item;
        }

        //是否存在上一个元素
        public boolean hasPrevious() {
            return nextIndex > 0;
        }

        //获取上一个元素
        public E previous() {
            //期望的改变计数与modCount比较
            checkForComodification();
            if (!hasPrevious())
                throw new NoSuchElementException();

            lastReturned = next = (next == null) ? last : next.prev;
            nextIndex--;
            return lastReturned.item;
        }

        public int nextIndex() {
            return nextIndex;
        }

        public int previousIndex() {
            return nextIndex - 1;
        }

        // 删除当前元素
        // 删除双向链表中的当前节点
        public void remove() {
            //期望的改变计数与modCount比较
            checkForComodification();
            if (lastReturned == null)
                throw new IllegalStateException();

            Node<E> lastNext = lastReturned.next;
            unlink(lastReturned);
            if (next == lastReturned)
                next = lastNext;
            else
                nextIndex--;
            lastReturned = null;
            expectedModCount++;
        }

        //设置当前节点为e
        public void set(E e) {
            if (lastReturned == null)
                throw new IllegalStateException();
            //期望的改变计数与modCount比较
            checkForComodification();
            lastReturned.item = e;
        }

        //将e添加到当前节点
        public void add(E e) {
            //期望的改变计数与modCount比较
            checkForComodification();
            lastReturned = null;
            if (next == null)
                linkLast(e);
            else
                linkBefore(e, next);
            nextIndex++;
            expectedModCount++;
        }

        // 判断 “modCount和expectedModCount是否相等”,依次来实现fail-fast机制。
        final void checkForComodification() {
            if (modCount != expectedModCount)
                throw new ConcurrentModificationException();
        }
    }

7.队列,栈相关操作
https://www.cnblogs.com/skywang12345/p/3308807.html

8.自定义LinkedList练习

public class MyLinkedList<E> implements MyList<E> {

    Node<E> first;

    Node<E> last;

    private int size;

    @Override
    public int size() {
        return size;
    }

    @Override
    public boolean isEmpty() {
        return size == 0;
    }

    @Override
    public boolean contains(Object o) {
        return indexOf(o) == -1;
    }

    /**
     * 创建以最后节点为前驱的 新节点
     *
     * @param e
     * @return
     */
    @Override
    public boolean add(E e) {
        //“原尾节点”
        final Node<E> oldLast = last;

        //创建以尾节点为前驱的 “新尾节点”
        Node<E> newLast = new Node(last, null, e);

        //将“新尾节点”赋值给 “尾节点”
        last = newLast;

        //空链表
        if (oldLast == null) {
            //既是头节点也是尾节点
            first = newLast;
        } else {
            //将“原尾节点”的后置改为 “新尾节点”
            oldLast.next = newLast;
        }

        size++;
        return true;
    }

    @Override
    public boolean remove(Object o) {
        if (o == null) {
            for (Node<E> node = first; node != null; node = node.next) {
                if (node.item == null) {
                    unlink(node);
                    return true;
                }
            }
        } else {
            for (Node<E> node = first; node != null; node = node.next) {
                if (o.equals(node.item)) {
                    unlink(node);
                    return true;
                }
            }
        }

        return false;
    }

    private void unlink(Node<E> node) {
        //上一节点
        Node<E> prev = node.prev;
        //下一节点
        Node<E> next = node.next;

        //头节点
        if (prev == null) {
            first = next;
        } else {
            prev.next = next;
            //方便垃圾回收
            node.prev = null;

        }

        //尾节点
        if (next == null) {
            last = prev;
        } else {
            next.prev = prev;
            //方便垃圾回收
            node.next = null;
        }

        //方便垃圾回收
        node.item = null;
        size--;
    }

    @Override
    public E get(int index) {
        return node(index).item;
    }

    @Override
    public E set(int index, E element) {
        Node<E> node = node(index);
        E oldItem = node.item;
        node.item = element;
        return oldItem;
    }

    @Override
    public void add(int index, E e) {

        //获取节点
        Node<E> oldNode = node(index);
        //尾部插入节点
        if (index == size) {
            add(e);
            return;
        }

        final Node<E> prev = oldNode.prev;
        Node newNode = new Node(prev, oldNode, e);
        oldNode.prev = newNode;
        //头部插入节点
        if (prev == null) {
            first = newNode;
        } else {
            //中间插入节点
            prev.next = newNode;
        }

        size++;
    }

    private Node<E> node(int index) {
        //LinkedList思想
        //半数以下 从前往后
        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;
        }
    }

    @Override
    public E remove(int index) {
        final Node<E> delNode = node(index);

        final E item = delNode.item;
        unlink(delNode);

        return item;
    }

    @Override
    public int indexOf(Object o) {
        int index = 0;
        if (o == null) {
            for (Node<E> x = first; x != null; x = x.next) {
                if (x.item == null) {
                    return index;
                }
                index++;
            }
        } else {
            Node<E> x = first;
            while (x != null) {
                if (o.equals(x.item)) {
                    return index;
                }
                x = x.next;
                index++;
            }
        }

        return -1;
    }

    public static void main(String[] args) {

        MyList<String> list = new MyLinkedList<>();
        System.out.println(list.isEmpty());
        list.add("0");
        list.add("1");
        System.out.println(list);

        list.add(0, "new0");
        System.out.println(list);

        list.add(list.size(), "4");
        System.out.println(list.size());

        System.out.println(list.get(2));

        System.out.println(list.indexOf("new0"));

        list.set(0, "nn0");

        list.remove(0);
        System.out.println(list);

        list.remove(list.size() - 1);
        System.out.println(list);
    }

    private static class Node<E> {
        //上一节点
        Node<E> prev;
        //下一节点
        Node<E> next;
        //当前节点值
        E item;

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

参考:
https://www.cnblogs.com/skywang12345/

上一篇下一篇

猜你喜欢

热点阅读