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 阅读(673) 评论(0) 编辑 收藏 举报