大话数据结构之Vector, Stack

作者: DevCW | 来源:发表于2018-04-12 15:46 被阅读99次
    上篇回顾

    上一篇讲解了ArrayList的实现, 讲述了ArrayList中最重要的两个实现: 移位和扩容。 那么本篇Vector同ArrayList相似,因此不懂这两个概念的可以先去看一下上一篇中关于这部分的讲解。传送
    顺序表之ArrayList

    本篇东西很少,因为Vector的实现与ArrayList极其相似。因此本篇的内容

    1. Vector与ArrayList的区别
    2. Vector实现讲解

    为什么一直强调Vector与ArrayList相似呢? 我们来看一下

    Vector的实现
     /**
         * The array buffer into which the components of the vector are
         * stored. The capacity of the vector is the length of this array buffer,
         * and is at least large enough to contain all the vector's elements.
         *
         * <p>Any array elements following the last element in the Vector are null.
         *
         * @serial
         */
        protected Object[] elementData;
    
     /**
         * Constructs an empty vector so that its internal data array
         * has size {@code 10} and its standard capacity increment is
         * zero.
         */
        public Vector() {
            this(10);
        }
    
    

    同样的实现机制-内部数组,同样的初始容量10。

    Vector的增删改查
     /**
         * Returns the element at the specified position in this Vector.
         *
         * @param index index of the element to return
         * @return object at the specified index
         * @throws ArrayIndexOutOfBoundsException if the index is out of range
         *            ({@code index < 0 || index >= size()})
         * @since 1.2
         */
        public synchronized E get(int index) {
            if (index >= elementCount)
                throw new ArrayIndexOutOfBoundsException(index);
    
            return elementData(index);
        }
    
    /**
         * Replaces the element at the specified position in this Vector with the
         * specified element.
         *
         * @param index index of the element to replace
         * @param element element to be stored at the specified position
         * @return the element previously at the specified position
         * @throws ArrayIndexOutOfBoundsException if the index is out of range
         *         ({@code index < 0 || index >= size()})
         * @since 1.2
         */
        public synchronized E set(int index, E element) {
            if (index >= elementCount)
                throw new ArrayIndexOutOfBoundsException(index);
    
            E oldValue = elementData(index);
            elementData[index] = element;
            return oldValue;
        }
    
     /**
         * Appends the specified element to the end of this Vector.
         *
         * @param e element to be appended to this Vector
         * @return {@code true} (as specified by {@link Collection#add})
         * @since 1.2
         */
        public synchronized boolean add(E e) {
            modCount++;
            ensureCapacityHelper(elementCount + 1);
            elementData[elementCount++] = e;
            return true;
        }
    
     /**
         * Deletes the component at the specified index. Each component in
         * this vector with an index greater or equal to the specified
         * {@code index} is shifted downward to have an index one
         * smaller than the value it had previously. The size of this vector
         * is decreased by {@code 1}.
         *
         * <p>The index must be a value greater than or equal to {@code 0}
         * and less than the current size of the vector.
         *
         * <p>This method is identical in functionality to the {@link #remove(int)}
         * method (which is part of the {@link List} interface).  Note that the
         * {@code remove} method returns the old value that was stored at the
         * specified position.
         *
         * @param      index   the index of the object to remove
         * @throws ArrayIndexOutOfBoundsException if the index is out of range
         *         ({@code index < 0 || index >= size()})
         */
        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; /* to let gc do its work */
        }
    

    如果你认真看,你会发现两个问题:
    1) 增删改查的实现同ArrayList真的几乎一模一样
    2) 所有的方法都带锁, synchronized

    当然它也提供了自己的方法,而且很详尽,如elementAt(), firstElement(), lastElement()等。而且Vector是Stack的父类,因此提供的这些方法可能是为了给Stack提供足够的便利。

    腻了吧!现在来说点不一样的。

    1.Vector是什么?

    说了这么多,还不知道Vector是什么,先引入百度百科的定义

    Vector 是在 java 中可以实现自动增长的[对象数组]

    它也是一个线性数组,而且可以实现自动增长。好的,那么我们来追踪一下自增长的实现。

    自增长

    如果你看它的源码,你会发现这么一个变量

    /**
         * The amount by which the capacity of the vector is automatically
         * incremented when its size becomes greater than its capacity.  If
         * the capacity increment is less than or equal to zero, the capacity
         * of the vector is doubled each time it needs to grow.
         *
         * @serial
         */
        protected int capacityIncrement;
    

    这是一个记录自增长的变量,你可以设置它来设置自增长的幅度。如

     /**
         * Constructs an empty vector with the specified initial capacity and
         * capacity increment.
         *
         * @param   initialCapacity     the initial capacity of the vector
         * @param   capacityIncrement   the amount by which the capacity is
         *                              increased when the vector overflows
         * @throws IllegalArgumentException if the specified initial capacity
         *         is negative
         */
        public Vector(int initialCapacity, int capacityIncrement) {
            super();
            if (initialCapacity < 0)
                throw new IllegalArgumentException("Illegal Capacity: "+
                                                   initialCapacity);
            this.elementData = new Object[initialCapacity];
            this.capacityIncrement = capacityIncrement;
        }
    

    既然是自增长,肯定是在扩容策略的一种实现,那么我们再来看一下扩容

     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);
        }
    

    相比于ArrayList, 我们的第一次系统扩容因子不同了,换为了以下代码

     int newCapacity = oldCapacity + ((capacityIncrement > 0) ?
                                             capacityIncrement : oldCapacity);
    

    有设置扩容幅度,则按幅度进行扩容。否则以原数组长度等比扩容。这时的扩容因子是1,记住,不是0.5了。后面的实现同ArrayList就一致了,不再赘述。看,就多了这么点东西。


    那么现在来总结一下ArrayList与Vector的区别

    1) ArrayList不是线程安全的, Vector是线程安全的
    2) Vector的扩容策略不同于ArrayList, Vector是按扩容幅度进行扩容

    其实差别真的很小,不过Vector是线程安全的,切记。


    顺带一提
    Queue队列是FIFO(先进先出)的,表现在它不会给你提供插入和删除的功能,只提供进和出两个方法。意味着你只能调用入(从队列尾部进入),出(从队列头部取出);而不会允许你对中间的元素进行操作。如

    image.png

    Stack栈是LIFO(后进先出)的,它也不会给你提供操作中间元素的机会,只有入和出。不过它是后入先出的。如

    image.png

    顺便看一下Stack的源码,它是继承自Vector的

    public
    class Stack<E> extends Vector<E> {
        /**
         * Creates an empty Stack.
         */
        public Stack() {
        }
    
        /**
         * Pushes an item onto the top of this stack. This has exactly
         * the same effect as:
         * <blockquote><pre>
         * addElement(item)</pre></blockquote>
         *
         * @param   item   the item to be pushed onto this stack.
         * @return  the <code>item</code> argument.
         * @see     java.util.Vector#addElement
         */
        public E push(E item) {
            addElement(item);
    
            return item;
        }
    
        /**
         * Removes the object at the top of this stack and returns that
         * object as the value of this function.
         *
         * @return  The object at the top of this stack (the last item
         *          of the <tt>Vector</tt> object).
         * @throws  EmptyStackException  if this stack is empty.
         */
        public synchronized E pop() {
            E       obj;
            int     len = size();
    
            obj = peek();
            removeElementAt(len - 1);
    
            return obj;
        }
    
        /**
         * Looks at the object at the top of this stack without removing it
         * from the stack.
         *
         * @return  the object at the top of this stack (the last item
         *          of the <tt>Vector</tt> object).
         * @throws  EmptyStackException  if this stack is empty.
         */
        public synchronized E peek() {
            int     len = size();
    
            if (len == 0)
                throw new EmptyStackException();
            return elementAt(len - 1);
        }
    
        /**
         * Tests if this stack is empty.
         *
         * @return  <code>true</code> if and only if this stack contains
         *          no items; <code>false</code> otherwise.
         */
        public boolean empty() {
            return size() == 0;
        }
    
        /**
         * Returns the 1-based position where an object is on this stack.
         * If the object <tt>o</tt> occurs as an item in this stack, this
         * method returns the distance from the top of the stack of the
         * occurrence nearest the top of the stack; the topmost item on the
         * stack is considered to be at distance <tt>1</tt>. The <tt>equals</tt>
         * method is used to compare <tt>o</tt> to the
         * items in this stack.
         *
         * @param   o   the desired object.
         * @return  the 1-based position from the top of the stack where
         *          the object is located; the return value <code>-1</code>
         *          indicates that the object is not on the stack.
         */
        public synchronized int search(Object o) {
            int i = lastIndexOf(o);
    
            if (i >= 0) {
                return size() - i;
            }
            return -1;
        }
    
        /** use serialVersionUID from JDK 1.0.2 for interoperability */
        private static final long serialVersionUID = 1224463164541339165L;
    }
    

    主要看一下它提供的核心方法。

     /**
         * Pushes an item onto the top of this stack. This has exactly
         * the same effect as:
         * <blockquote><pre>
         * addElement(item)</pre></blockquote>
         *
         * @param   item   the item to be pushed onto this stack.
         * @return  the <code>item</code> argument.
         * @see     java.util.Vector#addElement
         */
        public E push(E item) {
            addElement(item);
    
            return item;
        }
    

    Push是入的方法,类似ArrayList的add()。

    /**
         * Removes the object at the top of this stack and returns that
         * object as the value of this function.
         *
         * @return  The object at the top of this stack (the last item
         *          of the <tt>Vector</tt> object).
         * @throws  EmptyStackException  if this stack is empty.
         */
        public synchronized E pop() {
            E       obj;
            int     len = size();
    
            obj = peek();
            removeElementAt(len - 1);
    
            return obj;
        }
    
      public synchronized E peek() {
            int     len = size();
    
            if (len == 0)
                throw new EmptyStackException();
            return elementAt(len - 1);
        }
    
    

    pop是出的方法, 先执行了peek,peek是取最后一个元素;然后删除最后一个元素。在数组中,越往后加入的元素,会存储于数组底部。

    认真看的话,你会发现,Stack是线程安全的。Activity的保存与取出也是采用栈策略。

    好了,关于Vector和Stack的讲解结束了,你明白了吗?

    相关文章

      网友评论

        本文标题:大话数据结构之Vector, Stack

        本文链接:https://www.haomeiwen.com/subject/iqaxkftx.html