自己用java实现LinkList和arrayList

来源:互联网 发布:linux 自动启动svn 编辑:程序博客网 时间:2024/06/05 02:08

为了加深理解,我就自己写了下LinkList和arrayList。
下面贴下代码

链表代码public class MyTwoLinkedList<AnyType> implements Iterable<AnyType> {    private int theSize;    private int modCount = 0;    private Node<AnyType> beginMarker;    private Node<AnyType> endMarker;    private static class Node<AnyType> {        public AnyType data;        public Node<AnyType> prev;        public Node<AnyType> next;        public Node(AnyType d, Node<AnyType> p, Node<AnyType> n) {            data = d;            prev = p;            next = n;        }    }    public MyTwoLinkedList() {        clear();    }    public void clear() {        beginMarker = new Node<AnyType>(null, null, null);        endMarker = new Node<AnyType>(null, beginMarker, null);        beginMarker.next = endMarker;        theSize = 0;        modCount++;    }    public int size() {        return theSize;    }    public Boolean add(AnyType x) {        add(size(), x);        return true;    }    public void add(int idx, AnyType x) {        addBefore(getNode(idx), x);    }    //搜索节点,先判断节点在前半段还是后半段,略提高效率,双链表可以从两个方向查找    private Node<AnyType> getNode(int idx) {        Node<AnyType> p;//一个引用        if (idx < 0 || idx > size())            throw new IndexOutOfBoundsException();        if (idx < size() / 2) {            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.prev;        }        return p;    }    private void addBefore(Node<AnyType> p, AnyType x) {        Node<AnyType> newNode = new Node<AnyType>(x, p.prev, p);//双链表,新增节点插入指向前后        //前后两个节点的指向变化        newNode.prev.next = newNode;        p.prev = newNode;        theSize++;        //修改次数+1        modCount++;    }    public AnyType get(int idx) {        return getNode(idx).data;    }    public AnyType set(int idx, AnyType newVal) {        //一个引用,改变节点值        Node<AnyType> p = getNode(idx);        AnyType oldVal = p.data;        p.data = newVal;        return oldVal;    }    public AnyType remove(int idx) {        return remove(getNode(idx));    }    private AnyType remove(Node<AnyType> p) {        p.next.prev = p.prev;        p.prev.next = p.next;        theSize--;        //修改次数仍+1        modCount++;        return p.data;    }    public java.util.Iterator<AnyType> iterator() {        //返回一个实例化的内部类,该类是迭代器,内部实现        return new MyTwoLinkedList.LinkedListIterator();    }    //实现Iterator接口    private class LinkedListIterator implements java.util.Iterator<AnyType> {        //在内部指向第一个元素        private Node<AnyType> current = beginMarker.next;        //检测在迭代期间集合被修改的情况,分别在next()和迭代器自己的remove()中检查,如果修改次数不同说明在迭代器迭代之外发生了修改行为        //迭代器自己的remove()调用外层类的remove,其中有modCount++,迭代器做出remove()动作后将expectecModCount++,保证迭代期间二者保持一致        private int expectedModCount = modCount;        //okToRemove在next()执行后被置为true,在迭代器自己的remove()执行完后置为false,迭代器自己的remove()执行前检查其是否为true才执行,保证迭代一次才能删除一个,没有其他迭代时删除的方式        private boolean okToRemove = false;        public boolean hasNext() {            return current != endMarker;        }        public AnyType next() {            if (modCount != expectedModCount)                //同一时间修改冲突异常!!                throw new java.util.ConcurrentModificationException();            if (!hasNext())                throw new java.util.NoSuchElementException();            //用一个引用指向并从外部类获取前一个元素数据            AnyType nextItem = current.data;            //实际是改变一个引用的指向使其前进            current = current.next;            okToRemove = true;            return nextItem;        }        public void remove() {            if (modCount != expectedModCount)                throw new java.util.ConcurrentModificationException();            //不是迭代期间调用此迭代器remove()方法            if (!okToRemove)                throw new IllegalStateException();            //调用外部类方法            //next()使current先指向下一元素,这里移除current前一个元素,这样边迭代边移除,先后移后删除前一个元素            MyTwoLinkedList.this.remove(current.prev);            okToRemove = false;            expectedModCount++;        }    }}

双链表头尾放置两个值为null的Node对象,这样使头尾节点的处理也正常化,不会是删除头尾元素成为特别的情况存在。双链表还有就是每个节点存储上下两个节点的信息。删除的开销,在链表来,只是修改删除元素首尾节点的指向而已。而且由于是双链表可以从两端开始遍历,这样,用getNode方法,确认元素是在哪个半段。这样能用最快的速度来遍历。后面的迭代器实现,主要是用modcount参数,来保证链表的一致性的。

ArrayList代码public class MyTestArrayList<AnyType> implements Iterable<AnyType> {    //    //默认容器    private static final int DEFAULT_CAPACITY = 10;    private int theSize;    private AnyType[] theItems;    public MyTestArrayList() {        clear();    }    public void clear() {        theSize = 0;        ensureCapacity(DEFAULT_CAPACITY);    }    public void ensureCapacity(int newCapacity) {        if (newCapacity < theSize) {            return;        }        AnyType[] old = theItems;        theItems = (AnyType[]) new Object[newCapacity];        for (int i = 0; i < size(); i++) {            theItems[i] = old[i];        }    }    public Boolean add(AnyType x) {        add(size(), x);        return true;    }    public void add(int idx, AnyType x) {        if (idx > size()) {            throw new IndexOutOfBoundsException("Index:" + idx + "  Size :" + size());        }        if (theItems.length == size())            ensureCapacity(size() * 2);        for (int i = theSize; i > idx; i--)            theItems[i] = theItems[i - 1];        theItems[idx] = x;        theSize++;    }    public AnyType get(int idx) {        if (idx < 0 || idx > size())            throw new ArrayIndexOutOfBoundsException();        return theItems[idx];    }    public AnyType set(int idx, AnyType x) {        if (idx < 0 || idx > size())            throw new ArrayIndexOutOfBoundsException();        AnyType oldValue = theItems[idx];        theItems[idx] = x;        return oldValue;    }    public Boolean isEmpty() {        return size() == 0;    }    public int size() {        return theSize;    }    public AnyType remove(int idx) {        AnyType deleteItem = theItems[idx];        for (int i = idx; i < size() - 1; i++) {            theItems[i] = theItems[i + 1];        }//        theSize--;        theItems[--theSize] = null;        return deleteItem;    }    public java.util.Iterator<AnyType> iterator(){        return new ArrayListIterator();    }    public class ArrayListIterator implements java.util.Iterator<AnyType> {        private int current = 0;        public boolean hasNext() {            return current < size();        }        public AnyType next(){            if(!hasNext())                throw new java.util.NoSuchElementException();            return theItems[current++];        }        public void remove(){            //MyArraList.this代表外层类MyArrayList的对象            //--current这里暂解释为remove在next方法后调用,next让current++,            //这里让current回到原来位置,删除它            //因为如果不调用next直接remove,current会出现<0情况            MyTestArrayList.this.remove(--current);        }    }}

数组相较于上面的链表感觉删除就比较坑了,毕竟不知道要删除哪个元素。如果删除头元素,那么整个数组都要进行一次循环赋值,很坑的。其他的两者基本上都有点类似了。

原创粉丝点击