Java数据结构漫谈-Vector

List除了ArrayList和LinkedList之外,还有一个最常用的就是Vector。

Vector在中文的翻译是矢量,向量,所以大家喜欢把Vector叫做矢量数组,或者向量数组。

其实就底层实现来说Vector与ArrayList的实现大同小异,都是使用数组作为底层的存储器,在上面进行了一些列的操作封装,而且都实现了List的数据接口。

最主要的区别就是Vector的大部分操作增加了线程同步的功能,这也是Vector与其他List最大不同的地方,Vector是线程安全的。

    protected Object[] elementData; //数组作为底层存储器

    protected int elementCount; //记录了当前有多少个元素了

    protected int capacityIncrement; //每次扩展的时候需要扩展的数量

    public Vector(int initialCapacity, int capacityIncrement) {
        super();
        if (initialCapacity < 0)
            throw new IllegalArgumentException("Illegal Capacity: "+
                                               initialCapacity);
        this.elementData = new Object[initialCapacity];
        this.capacityIncrement = capacityIncrement;
    }

    public Vector(int initialCapacity) {
        this(initialCapacity, 0);
    }

    public Vector() {
        this(10);
    }

    public Vector(Collection<? extends E> c) {
        elementData = c.toArray();
        elementCount = elementData.length;
        // c.toArray might (incorrectly) not return Object[] (see 6260652)
        if (elementData.getClass() != Object[].class)
            elementData = Arrays.copyOf(elementData, elementCount, Object[].class);
    }

 这里面提供了与ArrayList相同的各种操作,下面简单说明一下:

1.复制内容到指定的数组,如果数组不够大,则抛出越界错误。

    public synchronized void copyInto(Object[] anArray) {
        System.arraycopy(elementData, 0, anArray, 0, elementCount);
    }

这里使用了System.arraycopy,后面还有很多地方使用了这个函数,其时间复杂度是o(n)。

2.在使用Vector的过程中,会出现需要扩容的情况,扩容之后又删除元素,就会造成很多元素空间被浪费的情况,如果担心浪费空间,就可以调用下面的函数进行无用空间trim:

    public synchronized void trimToSize() {
        modCount++;
        int oldCapacity = elementData.length;
        if (elementCount < oldCapacity) {
            elementData = Arrays.copyOf(elementData, elementCount);
        }
    }

可以看出这里就是开辟了一个正好需要的空间,把元素都拷贝到这个空间中,原来的数组空间会在vm空闲的时候进行回收。

3.上面说到了在数组容量不够的时候,会进行扩容,这里列出了一系列的包括扩容和获取与判断数组大小的函数:

    public synchronized void ensureCapacity(int minCapacity) {//进行容量调整
        if (minCapacity > 0) {
            modCount++;
            ensureCapacityHelper(minCapacity);
        }
    }

    private void ensureCapacityHelper(int minCapacity) {//进行容量调整
        // overflow-conscious code
        if (minCapacity - elementData.length > 0)//只有指定的容量大于元素个数的时候才进行容量调整
            grow(minCapacity);
    }

    private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

    private void grow(int minCapacity) {//扩容操作
        // overflow-conscious code
        int oldCapacity = elementData.length;//目前的容量
        int newCapacity = oldCapacity + ((capacityIncrement > 0) ?
                                         capacityIncrement : oldCapacity);//计算目标容量,如果指定了每次扩展的量,直接增加,如果没有就直接翻倍
        if (newCapacity - minCapacity < 0)
            newCapacity = minCapacity;//如果目标容量小于指定的容量,则调整为指定容量,注意:也就是说如果指定的容量没有达到自动计算的目标容量,则直接采计算的目标容量
        if (newCapacity - MAX_ARRAY_SIZE > 0)
            newCapacity = hugeCapacity(minCapacity);//如果超过了容量上限,则直接使用最大上限
        elementData = Arrays.copyOf(elementData, newCapacity);//开辟一个新空间,拷贝数据到新空间,旧空间将被VM自动回收
    }

    private static int hugeCapacity(int minCapacity) {
        if (minCapacity < 0) // overflow
            throw new OutOfMemoryError();
        return (minCapacity > MAX_ARRAY_SIZE) ?//其实不明白只有8的差距,为什么这么纠结
            Integer.MAX_VALUE :
            MAX_ARRAY_SIZE;
    }

    public synchronized void setSize(int newSize) {//设置当前Vector的元素数量
        modCount++;
        if (newSize > elementCount) {//比当前的元素个数大,就扩容,还不一定需要扩,看ensureCapacityHelper就明白
            ensureCapacityHelper(newSize);
        } else {
            for (int i = newSize ; i < elementCount ; i++) {//如果比当前的元素个数少,就把多出来的元素都抹掉
                elementData[i] = null;
            }
        }
        elementCount = newSize;//调整当前元素的个数
    }

    public synchronized int capacity() {
        return elementData.length;
    }

    public synchronized int size() {
        return elementCount;
    }

    public synchronized boolean isEmpty() {
        return elementCount == 0;
    }

上面的就是整个的扩容和设置元素数量等的一些操作函数的解释。

4.查找对象所在的index是List的一个重要的操作,其对应的主要的函数如下所示:

    public boolean contains(Object o) {//判断一个对象o是否在Vector中
        return indexOf(o, 0) >= 0;
    }

    public int indexOf(Object o) {//判断一个对象o在Vector中第一次出现的位置
        return indexOf(o, 0);
    }

    public synchronized int indexOf(Object o, int index) {//判断一个对象在Vector中的index之后第一次出现的位置
        if (o == null) {
            for (int i = index ; i < elementCount ; i++)
                if (elementData[i]==null)
                    return i;
        } else {
            for (int i = index ; i < elementCount ; i++)//使用遍历对比的方式进行判断
                if (o.equals(elementData[i]))
                    return i;
        }
        return -1;
    }

    public synchronized int lastIndexOf(Object o) {//判断在Vector中自后向前查找对象o的第一次出现的位置
        return lastIndexOf(o, elementCount-1);
    }


    public synchronized int lastIndexOf(Object o, int index) {
        if (index >= elementCount)
            throw new IndexOutOfBoundsException(index + " >= "+ elementCount);

        if (o == null) {
            for (int i = index; i >= 0; i--)
                if (elementData[i]==null)
                    return i;
        } else {
            for (int i = index; i >= 0; i--)//自后向前倒着遍历这个Vector查找
                if (o.equals(elementData[i]))
                    return i;
        }
        return -1;
    }

可以看出,只要涉及到确定Vector中对象o的位置,就需要遍历对比查找,而遍历对比查找的时间复杂度是o(n)

5.根据index对Vector进行操作也有一系列的函数:

    public synchronized E elementAt(int index) {//根据index获取Vector中的元素
        if (index >= elementCount) {
            throw new ArrayIndexOutOfBoundsException(index + " >= " + elementCount);
        }

        return elementData(index);
    }

  
    public synchronized E firstElement() {//获取第一个元素
        if (elementCount == 0) {
            throw new NoSuchElementException();
        }
        return elementData(0);
    }

    public synchronized E lastElement() {//获取最后一个元素
        if (elementCount == 0) {
            throw new NoSuchElementException();
        }
        return elementData(elementCount - 1);
    }

    public synchronized void setElementAt(E obj, int index) {//设置位置为index的元素
        if (index >= elementCount) {
            throw new ArrayIndexOutOfBoundsException(index + " >= " +
                                                     elementCount);
        }
        elementData[index] = obj;//直接设置,时间复杂度是o(1)
    }

    public synchronized void removeElementAt(int index) {//删除位置为index的元素
        modCount++;
        if (index >= elementCount) {
            throw new ArrayIndexOutOfBoundsException(index + " >= " +
                                                     elementCount);
        }
        else if (index < 0) {
            throw new ArrayIndexOutOfBoundsException(index);
        }
        int j = elementCount - index - 1;
        if (j > 0) {//如果不是最后一个需要进行元素位移,这个时候的时间复杂度是o(n)
            System.arraycopy(elementData, index + 1, elementData, index, j);
        }
        elementCount--;
        elementData[elementCount] = null; /* to let gc do its work *///把最后的值为null
    }

    public synchronized void insertElementAt(E obj, int index) {//在位置中间插入一个元素,时间复杂度是o(n)
        modCount++;
        if (index > elementCount) {
            throw new ArrayIndexOutOfBoundsException(index
                                                     + " > " + elementCount);
        }
        ensureCapacityHelper(elementCount + 1);//先进行扩容
        System.arraycopy(elementData, index, elementData, index + 1, elementCount - index);//让出位置,时间复杂度是o(n)
        elementData[index] = obj;//直接赋值
        elementCount++;//计数加一
    }

    public synchronized void addElement(E obj) {
        modCount++;
        ensureCapacityHelper(elementCount + 1);
        elementData[elementCount++] = obj;//在队尾加入一个,时间复杂度是o(1)
    }

    public synchronized boolean removeElement(Object obj) {//删除Vector中出现的第一个对象obj
        modCount++;
        int i = indexOf(obj);
        if (i >= 0) {
            removeElementAt(i);
            return true;
        }
        return false;
    }

    public synchronized void removeAllElements() {//删除所有的元素,遍历,时间复杂度是o(n)
        modCount++;
        // Let gc do its work
        for (int i = 0; i < elementCount; i++)
            elementData[i] = null;

        elementCount = 0;
    }

    public synchronized Object clone() {//拷贝一个对象,时间复杂度是o(n)
        try {
            @SuppressWarnings("unchecked")
                Vector<E> v = (Vector<E>) super.clone();
            v.elementData = Arrays.copyOf(elementData, elementCount);
            v.modCount = 0;
            return v;
        } catch (CloneNotSupportedException e) {
            // this shouldn't happen, since we are Cloneable
            throw new InternalError(e);
        }
    }

    public synchronized Object[] toArray() {//转换成数组,时间复杂度是o(n)
        return Arrays.copyOf(elementData, elementCount);
    }

    @SuppressWarnings("unchecked")
    public synchronized <T> T[] toArray(T[] a) {//转换成数组,时间复杂度是o(n)
        if (a.length < elementCount)
            return (T[]) Arrays.copyOf(elementData, elementCount, a.getClass());

        System.arraycopy(elementData, 0, a, 0, elementCount);

        if (a.length > elementCount)
            a[elementCount] = null;

        return a;
    }

    @SuppressWarnings("unchecked")
    E elementData(int index) {//获取index对应的对象,时间复杂度是o(1)
        return (E) elementData[index];
    }

    public synchronized E get(int index) {//获取index对应的对象,时间复杂度是o(1)
        if (index >= elementCount)
            throw new ArrayIndexOutOfBoundsException(index);

        return elementData(index);
    }

    public synchronized E set(int index, E element) {//设置index对应的对象,时间复杂度是o(1)
        if (index >= elementCount)
            throw new ArrayIndexOutOfBoundsException(index);

        E oldValue = elementData(index);
        elementData[index] = element;
        return oldValue;
    }

    public synchronized boolean add(E e) //在最后添加一个对象,时间复杂度是o(1),但有可能触发扩容操作
        modCount++;
        ensureCapacityHelper(elementCount + 1);
        elementData[elementCount++] = e;
        return true;
    }

    public boolean remove(Object o) {//删除第一次出现的对象o,时间复杂度是o(n)
        return removeElement(o);
    }

    public void add(int index, E element) {//在inedx上添加一个元素,时间复杂度是o(n),因为会触发元素位移
        insertElementAt(element, index);
    }

    public synchronized E remove(int index) {//删除index上面的元素,时间复杂度是o(n),因为会触发元素位移
        modCount++;
        if (index >= elementCount)
            throw new ArrayIndexOutOfBoundsException(index);
        E oldValue = elementData(index);

        int numMoved = elementCount - index - 1;
        if (numMoved > 0)
            System.arraycopy(elementData, index+1, elementData, index,
                             numMoved);
        elementData[--elementCount] = null; // Let gc do its work

        return oldValue;
    }

以上是进行获取,增加和删除操作的时间复杂度。

再次强调,Vector在涉及到元素更改的函数之前都加了关键字synchronized,是线程安全的。

 

posted on 2015-12-16 17:57  yakovchang  阅读(668)  评论(0编辑  收藏  举报

导航