算法与数据结构 其二 数组和链表 的实现

数组和链表的实现

程序 = 算法 + 数据结构 这句话道出算法和数据结构的联系
(PS:虽然从知乎听来另一句话 程序 [ ] ≠ 软件,23333)

那么针对我们日常开发中,使用了别人封装好处理数据的类,是否有必要究其实现的原理,其实我觉得还是有必要的。因为在java中使用不同的集合类处理数据,虽然能达到同样的目的,但是性能方面却有所差异,同种效果的方法间的时间复杂度也不同(不知道时间复杂度是什么的同学点我)

现在来探讨下我们常用的ArrayList和LinkedList的实现吧:)

ArrayList

public class MyArrayList<E> implements Iterable<E>{

    //默认长度
    private static final int DEFAULT_SIZE =10;
    //长度
    private int thisSize;
    //数组
    private E [] es;

    //构造器
    public MyArrayList(){
        clear();
    }

    //清除
    private void clear() {
        thisSize=0;
        //让数字组恢复默认长度
        returnDefaultSize(DEFAULT_SIZE);

    }

    //长度
    public int size(){
        return thisSize;
    }
    //是否为空
    public boolean isEmpty(){
        return thisSize==0;
    }

    //固定长度
    public void trimToSize(){
        returnDefaultSize(thisSize);
    }

    //获取第N个元素
    public E get(int index){
        if(index<0||index>=size())
            throw new ArrayIndexOutOfBoundsException();
        return es[index];
    }

    //设置第N个元素
    public E set(int index,E e){
        if(index<0||index>=size())
            throw new ArrayIndexOutOfBoundsException();
        //为了不破坏原来的数组而进行的操作
        E old = es[index];
        es[index] = e;
        return old;
    }

    //固定长度
    public void returnDefaultSize(int anyTypeLen) {
        //如果目前容量大小 大于 输入的大小,无需扩展
        if(thisSize > anyTypeLen)
            return ;
        //否则 扩展
        E[] old = es;
        es = (E[]) new Object[anyTypeLen];
        for(int i=0;i<size();i++){
            es[i] = old[i];
        }
    }

    //添加元素
    public boolean add(E e){
        add(size(),e);
        return true;
    }

    public boolean add(int index , E e){

        if(es.length == size()){
            //如果长度达到最长,扩容双倍再加一
            returnDefaultSize(size() * 2 +1);
        }
        //如果当前的长度 大于 index的长度,就要执行循环,进行移位
        for(int i=thisSize;i>index;i--){
            es[i] = es[i-1];
        }
        //数组空出来的位置 用来装入要求插入的元素
        es[index]=e;
        thisSize++;
        return true;
    }

    //删除元素
    public E remove(int index){
        if(index<0||index>size())
            throw new ArrayIndexOutOfBoundsException();
        //获取要删除的元素
        E anyType = es[index];

        //移位
        for(int i=index;i<size()-1;i++){
            es[index]=es[index+1];
        }
        thisSize--;
        return anyType;
    }

    @Override
    public Iterator<E> iterator() {
        return new ArrayListItertor(this);
    }

    public class ArrayListItertor<E> implements Iterator<E>{

        private int current=0;

        private MyArrayList<E> myArrayList;


        public ArrayListItertor(MyArrayList myArrayList){
            this.myArrayList = myArrayList;
        }

        @Override
        public boolean hasNext() {
            return current < myArrayList.size();
        }

        @Override
        public AnyType next() {
            return myArrayList.es[current++];
        }

        @Override
        public void remove() {
            MyArrayList.this.remove(--current);
        }
    }

}

LinkedList 的实现

//实现LinkedList其实是实现一个双链表的过程
public class MyLinkedList<E> implements Iterable<E> {

    private int theSize;
    private int modCount = 0;
    private Node<E> beginMarker;//开始 节点
    private Node<E> endMarker;//结束 节点

    private class Node<E>{

        private E data;//元素
        private Node<E> prev;//前驱
        private Node<E> next;//后继

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

    public MyLinkedList(){
        clear();
    }

    private void clear() {
        beginMarker = new Node<>(null,null,null);
        endMarker = new Node<>(null,beginMarker,null);
        modCount++;
    }

    private int size(){
        return theSize;
    }

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

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

    private void add(int index, E e) {
        addBefore(getNode(index),e);
    }

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

    //将原来的元素设置为现在的元素,并将原来的元素返回
    public  E set(int index,E e){
        Node<E> p = getNode(index);
        E oldAny =p.data;
        p.data = e;
        return oldAny;
    }

    private E remove(Node<E> p){

        E element = p.data;
        Node<E> next = p.next;
        Node<E> prev = p.prev; 

        if(prev == null){
            beginMarker = next;
        }else{
            prev.next = next;
            p.prve = null;
        }

        if(next == null){
            endMarker = prve;
        }else{
            next.prev = prev;
            p.next = null;
        }

        p.data = null;
        theSize -- ; //最总长度减一
        modCount ++; // 
        return element;

    }

    //参数:原来的前驱几点,新的元素
    //作用,插在队头
    private void addBefore(Node<E> p, E e) {
        Node<E> newNode = new Node<>(e,p.prev,p);
        newNode.prev.next = newNode;
        p.prev = newNode;
        theSize ++;
        modCount ++;
    }

    //拿到节点
    private Node<E> getNode(int index) {
        //开始的节点
        Node<E> p;

        if(index<0||index>size())
            throw new IndexOutOfBoundsException();

        //小于长度的二分之一,去队头查找
        if(index<size()/2){
            p = beginMarker.next;
            for(int i=0;i<index;i++){
                p = p.next;
            }
        //大于长度的二分之一,去队头查找
        }else{
            p = endMarker;
            for(int i=size();i>index;i--){
                p = p.prev;
            }
        }
        return p;
    }

    //遍历
    @Override
    public Iterator<E> iterator() {
        return new LinkedListIterator();
    }

    private class LinkedListIterator implements Iterator<E>{

        private Node<E> current = (Node<E>) beginMarker.next;
        private int expectedModCount = modCount;
        //是否可以删除
        private boolean okToRemove = false;

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

        @Override
        public E next() {

            if(modCount !=expectedModCount)
                throw new ConcurrentModificationException();

            if(!hasNext())
                throw new NoSuchElementException();

            E nextItem = current.data;
            current = (Node<E>) current.next;
            okToRemove = true;
            return current.data;
        }

        @Override
        public void remove() {
            if(modCount !=expectedModCount)
                throw new ConcurrentModificationException();
            if(!okToRemove)
                throw new IllegalStateException();

            MyLinkedList.this.remove(current.prev);
            okToRemove = false;
            expectedModCount++;
        }
    }
}

补充
上面是ArrayList和LisnkedList的实现。其中,可能有部分读者发现,这两个我都去实现了Iterable 接口,并对方法Iterator 进行了修改。为什么要这么做?这要从Iterator 接口开始说起:

Iterator 迭代器

public interface Iterator{
    //用与查找下一个元素是否存在
    public boolean hasNext() {}
    //拿到下一个元素
    public Object next() {}
    //移除下一个元素
    public void remove() {}
}

Iterable 接口中包含了iterator方法。

public interface Iterable<T> {

    Iterator<T> iterator();
    default void forEach(Consumer<? super T> action) {
        Objects.requireNonNull(action);
        for (T t : this) {
            action.accept(t);
        }
    }
     default Spliterator<T> spliterator() {
        return Spliterators.spliteratorUnknownSize(iterator(), 0);
    }

这样一来,只要实现了Iterable 的类,就可以使用内部的增强for循环观察所有的项。

Iterator 中的remove方法,该方法只能删除由next返回的最新的项。也就是说,每当你想使用remove时,确保之前next方法有返回最新的项

正确的使用
next();
remove();
next();
remove();

错误的使用
next();
remove();
remove();//没有使用next方法,游标还是停留在上一个被删除项的位置

正因为如此,Iterator 的 remove的效率会比Collection里的remove的效率高。因为后者必须先确认要删除元素所在集合中的位置。

使用这种方式还有第二个原因:当Collection 在遍历时,结构被改变(add,remove,clear)时,这个集合的Iterator就不合法,会报错异常。如果我们是直接操作Iterator,使用它自身的remove,这样的迭代器仍然是合法的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值