Java之实现自己的ArrayList与LinkedList

我们知道List接口的两个常用实现类为ArrayListLinkedList

ArrayList底层采用数组实现,随机访问元素非常快,只需要常数时间c。但是对于删除和插入元素则比较耗时,因为它需要移动元素,需要线性时间,即O(N)。

LinkedList底层采用链表实现,它的插入与删除操作非常快,只是更改两个指针的指向,所以 需要花常数时间c。但是随机访问则比较耗时,因为它需要从头节点或者尾节点进行依次地遍历,需要线性时间,即O(N)。

现在呢,我们就采用数组和链表分别实现自己MyArrayListMyLinkedList。当然,这里只是实现最基础的功能。

1.MyArrayList

MyArrayList的默认大小为10。每次扩充数组的时候在原有的基础上乘以2再加1。加1是防止数组大小为0的情况。

package myList;

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

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

    // 默认容量
    private static final int DEFAULT_CAPACITY = 10;
    //实际大小
    private int theSize;
    // 数组
    private T[] theItems;

    public MyArrayList() {
        doClear();
    }

    public int size(){
        return theSize;
    }

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

    /**
     * 清除多余空间
     */
    public void trimToSize(){
        ensureCapacity(size());
    }

    /**
     * 根据索引获取元素
     * @param index
     * @return
     */
    public T get(int index){
        if(index < 0 || index >= size()){
            throw new IndexOutOfBoundsException();
        }
        return theItems[index];
    }

    /**
     * 设置新值,返回旧值
     * @param index
     * @param newVal
     * @return
     */
    public T set(int index, T newVal){
        if(index < 0 || index >= size()){
            throw new IndexOutOfBoundsException();
        }
        T oldVal = theItems[index];
        theItems[index] = newVal;
        return oldVal;
    }

    /**
     * 根据索引添加元素
     * @param index
     * @param x
     */
    public void add(int index, T x){
        // 扩展容量
        if(theItems.length == size()){
            ensureCapacity(size() * 2 + 1);
        }
        // 向后移动
        for(int i = theSize;i > index;i--){
            theItems[i] = theItems[i-1];
        }
        // 添加
        theItems[index] = x;
        // 实际容量增加1
        theSize++;
    }

    /**
     * 默认向最后添加
     * @param x
     * @return
     */
    public boolean add(T x){
        add(size(), x);
        return true;
    }

    /**
     * 根据索引删除节点
     * @param index
     * @return
     */
    public T remove(int index){
        T removedItem = theItems[index];
        // 向前移动
        for(int i = index;i<size()-1;i++){
            theItems[i] = theItems[i+1];
        }
        //实际容量减小1
        theSize--;
        return removedItem;
    }

    private void doClear(){
        theSize = 0;
        ensureCapacity(DEFAULT_CAPACITY);
    }

    /**
     * 数组扩展
     * @param newCapacity
     */
    public void ensureCapacity(int newCapacity){
        if(newCapacity < theSize){
            return;
        }
        T[] old = theItems;
        // 泛型不能实例化,只能这么写
        theItems = (T[])new Object[newCapacity];
        for(int i = 0;i<size();i++){
            theItems[i] = old[i];
        }
    }

    /**
     * 迭代器方法
     */
    @Override
    public Iterator<T> iterator() {
        return new ArrayListIterator();
    }

    /**
     * 迭代器。内部类
     * @author Gavin
     *
     */
    private class ArrayListIterator implements Iterator<T>{

        private int current = 0;

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

        @Override
        public T next() {
            // 如果已经没有元素了
            if(!hasNext()){
                throw new NoSuchElementException();
            }
            return theItems[current++];
        }

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

    @Override
    public String toString() {
        StringBuilder line = new StringBuilder("[");
        for(int i = 0;i<size();i++){
            line.append(theItems[i]);
            if(i != size()-1){
                line.append(", ");
            }else{
                line.append("]");
            }
        }
        return line.toString();
    }
}

2.MyLinkedList

MyLinkedList采用双向链表实现。具有头节点和尾节点,头节点没有前驱结点,而尾节点没有后继节点。

package myList;

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

public class MyLinkedList<T> implements Iterable<T>{

    /**
     * 节点类
     * @author Gavin
     *
     * @param <T>
     */
    private static class Node<T>{
        public T data;
        public Node<T> prev;
        public Node<T> next;
        public Node(T data,Node<T> prev, Node<T> next) {
            this.data = data;
            this.prev = prev;
            this.next = next;
        }
    }
    // 实际数据量
    private int theSize = 0;
    // 该变量用于迭代时的判断
    private int modCount = 0;
    // 头节点
    private Node<T> beginMarker;
    // 尾节点
    private Node<T> endMarker;

    public MyLinkedList(){
        doClear();
    }

    public void clear(){
        doClear();
    }

    public void doClear(){
        beginMarker = new Node<T>(null, null, null);
        endMarker = new Node<T>(null, beginMarker, null);
        beginMarker.next = endMarker;

        theSize = 0;
        modCount ++; 
    }

    /**
     * size()方法,返回实际的数据量大小
     * @return
     */
    public int size(){
        return theSize;
    }

    /**
     * 判断是否为空
     * @return
     */
    public boolean isEmpty(){
        return size() == 0;
    }

    /**
     * 私有方法。在节点p之前插入新节点,数据为x
     * @param p
     * @param x
     */
    private void addBefore(Node<T> p, T x){
        Node<T> newNode = new Node<T>(x, p.prev, p);
        newNode.prev.next = newNode;
        p.prev = newNode;
        theSize++;
        modCount++;
    }


    /**
     * 私有方法。寻找Node,索引在lower和upper之间
     * @param index
     * @param lower
     * @param upper
     * @return
     */
    private Node<T> getNode(int index, int lower,int upper){
        Node<T> p;
        if(index < lower || index > upper){
            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;
            }

            /*这里为什么不采用这种写法,是因为upper的值有可能为size()
            p = endMarker.prev;
            for(int i = size()-1;i>index;i--){
                p = p.prev;
            }
            */
        }
        return p;
    }

    /**
     * 私有方法。该方法限制index在0和size()-1之间
     * @param index
     * @return
     */
    private Node<T> getNode(int index){
        return getNode(index, 0, size()-1);
    }

    /**
     * 根据index索引获取值
     * @param index
     * @return
     */
    public T get(int index){
        return getNode(index).data;
    }

    /**
     * 设置某一个index索引位置上的值
     * @param index
     * @param newVal
     * @return
     */
    public T set(int index, T newVal){
        Node<T> p = getNode(index);
        T oldVal = p.data;
        p.data = newVal;
        return oldVal;
    }

    /**
     * 这里的index可能为0到size()之间
     * @param index
     * @param x
     */
    public void add(int index,T x){
        addBefore(getNode(index,0,size()), x);
    }

    /**
     * 该add方法直接调用add(index,x),并且index为size()
     * @param x
     * @return
     */
    public boolean add(T x){
        add(size(), x);
        return true;
    }

    /**
     * 私有方法。删除一个节点Node
     * @param p
     * @return
     */
    private T remove(Node<T> p){
        p.prev.next = p.next;
        p.next.prev = p.prev;
        theSize--;
        modCount++;
        return p.data;
    }

    /**
     * 根据索引删除节点
     * @param index
     * @return
     */
    public T remove(int index){
        return remove(getNode(index));
    }

    /**
     * 迭代器方法
     */
    @Override
    public Iterator<T> iterator() {
        return new LinkedListIterator();
    }

    /**
     * 迭代器。内部类
     * @author Gavin
     *
     */
    private class LinkedListIterator implements Iterator<T>{

        private Node<T> current = beginMarker.next;

        //此变量用于限制遍历期间,MyLinkedList不能修改
        private int expectedModCount = modCount;

        //此变量用于限制不能多次remove
        private boolean okToRemove = false;

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

        @Override
        public T next() {
            if(modCount != expectedModCount){
                throw new ConcurrentModificationException();
            }
            if(!hasNext()){
                throw new NoSuchElementException();
            }

            T nextItem = current.data;
            current = current.next;
            okToRemove = true;
            return nextItem;
        }

        public void remove(){
            if(modCount != expectedModCount){
                throw new ConcurrentModificationException();
            }
            if(!okToRemove){
                throw new IllegalStateException();
            }
            MyLinkedList.this.remove(current.prev);
            expectedModCount++;
            okToRemove = false;
        }
    }

    @Override
    public String toString() {
        StringBuilder line = new StringBuilder("[");
        Node<T> p = beginMarker.next;
        while(p!=endMarker.prev){
            line.append(p.data);
            line.append(", ");
            p = p.next;
        }
        line.append(p.data);
        line.append("]");
        return line.toString();
    }
}
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值