• 模仿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;
            }
        }
    }
  • 相关阅读:
    angular js 自定义指令
    web api 解决跨域的问题
    angular 监听ngrepeat结束时间
    redis关闭和启动
    intellij idea快捷键
    mysql连接字符串
    crontab命令格式
    maven中scope属性的
    maven pom文件元素说明
    引入maven以外的jar包
  • 原文地址:https://www.cnblogs.com/yangwanhao/p/10675836.html
Copyright © 2020-2023  润新知