Java数据结构学习之Vector和Stack

Vector

Vector<E>是JDK1.0添加的一个类,它继承了AbstractList<E>类,实现了List<E>接口,所以它是集合家族中"队列"的一员。

public class Vector<E>
    extends AbstractList<E>
    implements List<E>, RandomAccess, Cloneable, java.io.Serializable

1、Vector的构造函数:

//指定初始容量和增长系数
public Vector(int initialCapacity, int capacityIncrement) {
    super();
    if (initialCapacity < 0)//如果初始容量小于0抛异常
    throw new IllegalArgumentException("Illegal Capacity: "+initialCapacity);
    this.elementData = new Object[initialCapacity];//新建数组
    this.capacityIncrement = capacityIncrement;//指定增长系数
}

//指定初始容量(动态数组的大小)
public Vector(int initialCapacity) {
    this(initialCapacity, 0);//实际调用第一个构造函数
}

//可以看出Vector默认初始容量为:10
public Vector() {
    this(10);//实际调用第二个构造函数
}

//新建指定集合的Vector
public Vector(Collection<? extends E> c) {
    Object[] a = c.toArray();//把集合转换成数组
    elementCount = a.length;//指定数据大小
    if (c.getClass() == ArrayList.class) {
        elementData = a;//如果集合是ArrayList类型直接保存,如果不是就用工具类Arrays转换一下
    } else {
        elementData = Arrays.copyOf(a, elementCount, Object[].class);
    }
}

2、Vector的成员变量:

  • protected Object[] elementData:保存Vector存储的数据,可以看出底层是一个Object[]数组(并且是动态数组,数据超出指定容量后会扩容,具体实现后面再说)。
  • protected int elementCount:保存数据的大小。
  • protected int capacityIncrement:动态数组的增长系数,用来指定动态数组扩容时增加的大小。
  • private static final long serialVersionUID = -2767605614048989439L:序列化参数。

3、Vector常用方法分析:

(Vector中使用大量“System.arraycopy”方法,参数的介绍和方法使用可参考:https://www.cnblogs.com/Bernard94/p/16292128.html

新增:

//新增数据到动态数组指定坐标
public void add(int index, E element) {
        insertElementAt(element, index);
}
public synchronized void insertElementAt(E obj, int index) {
    modCount++;//AbstractList的变量,用于记录数据变化次数
    if (index > elementCount) {
        throw new ArrayIndexOutOfBoundsException(index+ " > " + elementCount);
    }
    ensureCapacityHelper(elementCount + 1);//先比较数据量和数组容量的大小
    System.arraycopy(elementData, index, elementData, index + 1, elementCount - index);
    elementData[index] = obj;
    elementCount++;
}
//新增数据到动态数组末尾
public synchronized boolean add(E e) {
    modCount++;
    ensureCapacityHelper(elementCount + 1);
    elementData[elementCount++] = e;
    return true;
}
//将指定集合中的所有元素插入到此向量中的指定位置
public synchronized boolean addAll(int index, Collection<? extends E> c) {
    modCount++;
    if (index < 0 || index > elementCount)
        throw new ArrayIndexOutOfBoundsException(index);

    Object[] a = c.toArray();
    int numNew = a.length;
    ensureCapacityHelper(elementCount + numNew);

    int numMoved = elementCount - index;
    if (numMoved > 0)
        System.arraycopy(elementData, index, elementData, index + numNew,
                         numMoved);

    System.arraycopy(a, 0, elementData, index, numNew);
    elementCount += numNew;
    return numNew != 0;
}
//将指定集合中的所有元素追加到该向量的末尾
public synchronized boolean addAll(Collection<? extends E> c) {
    modCount++;
    Object[] a = c.toArray();
    int numNew = a.length;
    ensureCapacityHelper(elementCount + numNew);
    System.arraycopy(a, 0, elementData, elementCount, numNew);
    elementCount += numNew;
    return numNew != 0;
}
//新增数据到动态数组末尾(和add()不同:没有返回结果)
public synchronized void addElement(E obj) {
    modCount++;
    ensureCapacityHelper(elementCount + 1);
    elementData[elementCount++] = obj;
}

private void ensureCapacityHelper(int minCapacity) {
    // 如果数据量比数组容量大,则扩容
    if (minCapacity - elementData.length > 0)
        grow(minCapacity);
}
//扩容方法
private void grow(int minCapacity) {
    // 老的数组容量
    int oldCapacity = elementData.length;
    //新的数组容量:老的数据容量加增长系数或者2倍老的数据容量
    int newCapacity = oldCapacity + ((capacityIncrement > 0) ? capacityIncrement : oldCapacity);
    //如果数据量比新的数组容量大,则用“数据量”做容量
    if (newCapacity - minCapacity < 0)
        newCapacity = minCapacity;
    //给新数据容量增加限制,最多为: Integer.MAX_VALUE
    if (newCapacity - MAX_ARRAY_SIZE > 0)
        newCapacity = hugeCapacity(minCapacity);
    elementData = Arrays.copyOf(elementData, newCapacity);
}
private static int hugeCapacity(int minCapacity) {
    if (minCapacity < 0) // 溢出
    throw new OutOfMemoryError();
    return (minCapacity > MAX_ARRAY_SIZE) ? Integer.MAX_VALUE : MAX_ARRAY_SIZE;
}

删除:

    //删除第一个出现的指定元素,如果Vector不包含元素,则它不会更改
    public boolean remove(Object o) {
        return removeElement(o);
    }
    //删除指定位置的元素
    public synchronized E remove(int index) {
        modCount++;//数据修改次数加1
        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);
        //数组最末尾置为空,并且数据量减少1
        elementData[--elementCount] = null;
        //返回被删除的值
        return oldValue;
    }
    //删除所有数据并把数据量置为0
    public synchronized void removeAllElements() {
        modCount++;
        for (int i = 0; i < elementCount; i++)
        elementData[i] = null;
        elementCount = 0;
    }
    //删除指定位置的元素
    public synchronized void removeElementAt(int 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) {
            System.arraycopy(elementData, index + 1, elementData, index, j);
        }
        elementCount--;
        elementData[elementCount] = null; 
    }
    protected synchronized void removeRange(int fromIndex, int toIndex) {
        modCount++;
        int numMoved = elementCount - toIndex;
        System.arraycopy(elementData, toIndex, elementData, fromIndex, numMoved);
        // 删除成功数组最末尾置为空,并且数据量减少1
        int newElementCount = elementCount - (toIndex-fromIndex);
        while (elementCount != newElementCount)
            elementData[--elementCount] = null;
    }

修改:

    //用指定的数据替换指定位置的数据
    public synchronized E set(int index, E element) {
        if (index >= elementCount)
            throw new ArrayIndexOutOfBoundsException(index);
        E oldValue = elementData(index);
        elementData[index] = element;
        return oldValue;
    }
    //用指定的数据替换指定位置的数据
    public synchronized void setElementAt(E obj, int index) {
        if (index >= elementCount) {
            throw new ArrayIndexOutOfBoundsException(index + " >= " + elementCount);
        }
        elementData[index] = obj;
    }
    //给Vector设置新的数据量
    public synchronized void setSize(int newSize) {
        modCount++;
        //如果比已有的数据量大则扩容
        if (newSize > elementCount) {
            ensureCapacityHelper(newSize);
        } else {
            //如果指定的比现在的数据量小则把多余的数据置为空
            for (int i = newSize ; i < elementCount ; i++) {
                elementData[i] = null;
            }
        }
        elementCount = newSize;
    }

查询:

    //返回指定数组下标的数据
    public synchronized E elementAt(int index) {
        if (index >= elementCount) {
            throw new ArrayIndexOutOfBoundsException(index + " >= " + elementCount);
        }
        return elementData(index);//此处方法返回值为:elementData[index],坐标比数据量小1
    }
    //返回指定数组下标的数据
    public synchronized E get(int index) {
        if (index >= elementCount)
            throw new ArrayIndexOutOfBoundsException(index);
        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);
    }
    //返回此向量中指定元素的第一次出现的索引,从index搜索,如果未找到该元素,则返回-1。
    public synchronized int indexOf(Object o, int 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;
    }
    //返回此向量中指定元素的第一次出现的索引,从坐标0开始搜索,如果未找到该元素,则返回-1。
    public int indexOf(Object o) {
        return indexOf(o, 0);
    }
    //返回此向量中指定元素的最后一次出现的索引,从index向后搜索,如果未找到元素,则返回-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--)
                if (o.equals(elementData[i]))
                    return i;
        }
        return -1;
    }
    //返回此向量中指定元素的最后一次出现的索引,从坐标0向后搜索,如果未找到元素,则返回-1。
    public synchronized int lastIndexOf(Object o) {
        return lastIndexOf(o, elementCount-1);
    }

其他:

    //返回数据量大小
    public synchronized int size() {
        return elementCount;
    }
    //返回动态数组容量
    public synchronized int capacity() {
        return elementData.length;
    }
    //判断数据量是否为0
    public synchronized boolean isEmpty() {
        return elementCount == 0;
    }
    //删除所有数据
    public void clear() {
        removeAllElements();
    }
    //判断是否包含指定数据
    public boolean contains(Object o) {
        return indexOf(o, 0) >= 0;
    }
    //返回Vector的数据并转换为数组
    public synchronized Object[] toArray() {
        return Arrays.copyOf(elementData, elementCount);
    }

总结:

1、Vector和常见的ArrayList一样是个队列的数据结构,不同的是Vector的关键方法都用了关键字:synchronized 用来保证线程安全,当然相对的效率会下降。

2、它现在被淘汰应该是因为它新增于JDK1.0,当时对应用场景的考虑无法做到完美,所以随着技术的提升,它保证线程安全的能力和效率都有更好的替代方式。

Stack

栈(stack)是只能在某一端插入和删除的特殊线性表。栈是一种FILO的数据结构,它按照先进后出的原则存储数据,先进入的数据被压入栈底,最后的数据在栈顶,需要读数据的时候从栈顶开始弹出数据。

1、源码分析

public class Stack<E> extends Vector<E> {

    //构造函数
    public Stack() {
    }

    //压栈,添加数据
    public E push(E item) {
        addElement(item);//父级Vector的addElement方法,往Object[]数组里添加数据
        return item;
    }

    //先调peek方法返回数组最后一位,然后再调用父级方法删除
    public synchronized E pop() {
        E       obj;
        int     len = size();
        obj = peek();
        removeElementAt(len - 1);//父级Vector的removeElementAt方法
        return obj;
    }

    //返回数组最后一位下标的数据(末尾下标等于数组长度减一)
    public synchronized E peek() {
        int len = size();//父级Vector的size方法
        if (len == 0)
            throw new EmptyStackException();
        return elementAt(len - 1);//父级Vector的elementAt方法
    }

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

    //判断对象是否存在
    public synchronized int search(Object o) {
        int i = lastIndexOf(o);//返回最后一位出现目标对象的下标
        if (i >= 0) {
            return size() - i;//此处我的理解是到栈顶的距离
        }
        return -1;//不存在则返回-1
    }

    //序列化参数
    private static final long serialVersionUID = 1224463164541339165L;
}

总结:

1、Stack是个继承Vector的“类”,它的增删底层依赖与父级Vector,实际上底层也是对动态数组的各种操作。

2、Stack的增、删、查都有关键字“synchronized”,所以它也是线程安全的数据结构。(addElement方法也有关键字synchronized)

addElement
posted @ 2022-05-20 14:13  请别耽误我写BUG  阅读(93)  评论(0编辑  收藏  举报