自己用java实现LinkList和arrayList

本文作者通过自行实现LinkList和ArrayList,深入理解这两种数据结构的特性。双链表使用头尾null节点确保正常操作,删除操作只需改变相邻节点指针,而数组删除元素尤其是头元素时需要大量移动元素,效率较低。
摘要由CSDN通过智能技术生成

为了加深理解,我就自己写了下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);
        }
    }

}

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值