模仿LinkedList和它的Iterator

LinkedList使用链表结构实现(jdk1.6之前包括jdk1.6使用双向循环链表,自1.7开始使用双向链表)。

链表的添加节点与删除节点花费的时间要远比数组小,因为链表只涉及插入位置的两个节点的变动。

但是链表的查询却是需要遍历查询,花费的时间要比数组更多。

package cn.yangwanhao.collection.list;

import java.util.ConcurrentModificationException;
import java.util.Iterator;
import java.util.NoSuchElementException;

/**
 * Title: MyLinkedList类<br>
 * Description: 模仿LinkedList和Iterator
 * Company: 卓瀛工作室
 *
 * @author 杨万浩
 * @version 1.0
 */
public class MyLinkedList<E> implements Iterable<E> {

    /**
     * 集合的大小
     */
    private int theSize;
    /**
     * 集合变动的次数
     */
    private int modCount = 0;
    /**
     * 集合的头
     */
    private Node<E> beginMarker;
    /**
     * 集合的尾
     */
    private Node<E> endMarker;

    public MyLinkedList() {
        doClear();
    }

    public void clear() {
        doClear();
    }

    /**
     * 初始化集合
     */
    private void doClear() {
        // 初始化链表头部
        beginMarker = new Node<E>(null, null, null);
        // 初始化链表尾部
        endMarker = new Node<E>(null, beginMarker, null);
        // 因为一开始endMarker还没初始化,所以beginMarker的next为null,此时将beginMarker的next指向endMarker
        beginMarker.next = endMarker;
        // 初始化集合的大小为0
        theSize = 0;
        modCount++;
    }

    public int size() {
        return theSize;
    }

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

    public boolean add(E data) {
        add(size(), data);
        return true;
    }

    public void add(int idx, E data) {
        addBefore(getNode(idx, 0, size()), data);
    }

    /**
     * 在节点之前插入一条数据
     * @param p 指定在哪个节点之前插入数据
     * @param data 要插入的数据
     */
    private void addBefore(Node<E> p, E data) {
        // 创建一个node对象,它的next为传入的那个节点
        // 即要在它之前插入,所以插入后新节点的next是p,previous是p的上一个节点
        Node<E> newNode = new Node<E>(data, p.previous, p);
        // 把新节点的上一个节点的尾节点指向新节点
        newNode.previous.next = newNode;
        // 把指定节点的上一个节点换成新节点
        p.previous = newNode;
        // 长度和操作次数+1
        theSize++;
        modCount++;
    }

    public E get(int idx) {
        return getNode(idx).data;
    }

    public E set(int idx, E newVal) {
        // 通过下标得到指定的节点
        Node<E> p = getNode(idx);
        // 得到旧的数据
        E oldVal = p.data;
        // 把新的数据赋值给该节点的数据
        p.data = newVal;
        return oldVal;
    }

    public E remove(int idx) {
        return remove(getNode(idx));
    }

    /**
     * 删除指定的节点
     * @param p 要删除的节点
     * @return 被删除的节点的数据
     */
    private E remove(Node<E> p) {
        //把下一个节点的头结点指向上一个节点
        p.next.previous = p.previous;
        //把上一个节点的尾节点指向下一个节点
        p.previous.next = p.next;
        //长度-1,操作次数+1
        theSize--;
        modCount++;
        return p.data;
    }

    private Node<E> getNode(int idx) {
        return getNode(idx, 0, size()-1);
    }
    private Node<E> getNode(int idx, int lower, int upper) {
        Node<E> p;
        if(idx < lower || idx > upper) {
            throw new IndexOutOfBoundsException();
        }
        //如果索引的位置在表的前半部分,那么从前往后遍历,否则从后往前遍历
        if(idx < (size()>>1)) {
            p = beginMarker.next;
            for (int i = 0; i < idx; i++) {
                p = p.next;
            }
        } else {
            p = endMarker;
            for (int i = size(); i > idx; i--) {
                p = p.previous;
            }
        }
        return p;
    }

    @Override
    public Iterator<E> iterator() {
        return new MyLinkedListIterator();
    }
    private static class Node<E> {
        public E data;
        public Node<E> previous;
        public Node<E> next;
        public Node(E data, Node<E> previous, Node<E> next) {
            this.data = data;
            this.previous = previous;
            this.next = next;
        }
    }

    private class MyLinkedListIterator implements Iterator<E> {

        /**
         * 初始化头结点
         */
        private Node<E> current = beginMarker.next;
        private int expectModCount = modCount;
        private boolean okToRemove = false;

        @Override
        public boolean hasNext() {
            return current != endMarker;
        }

        @Override
        public E next() {
            if(modCount != expectModCount) {
                throw new ConcurrentModificationException();
            }
            if(!hasNext()) {
                throw new NoSuchElementException();
            }
            E nextItem = current.data;
            current = current.next;
            okToRemove = true;
            return nextItem;
        }

        @Override
        public void remove() {
            if(modCount != expectModCount) {
                throw new ConcurrentModificationException();
            }
            if(!okToRemove) {
                throw new IllegalStateException();
            }
            //指向next()方法后,指针已经指向下一个节点,所以要删除的节点是current的上一个节点
            MyLinkedList.this.remove(current.previous);
            okToRemove = false;
        }
    }
}
posted @ 2019-04-09 11:23  砖厂繁忙在下告辞  阅读(109)  评论(0编辑  收藏  举报