• 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
  • 相关阅读:
    Structured Streaming watermark总结
    技术实践第三期|HashTag在Redis集群环境下的使用
    元宇宙带来沉浸式智能登录?你学会了吗?
    技术实践第一期|友盟+开发者平台Node.js重构之路
    2021年度友盟+ APP消息推送白皮书:工作日68点通勤时间消息送达率每日最高
    技术实践第二期|Flutter异常捕获
    注意啦!还没有支持64位系统的App开发者,务必在12月底前完成这件事!
    一位大牛对于写技术博客的一些建议
    国内常用源开发环境换源(flutter换源,python换源,Linux换源,npm换源)
    初识Socket通讯编程(一)
  • 原文地址:https://www.cnblogs.com/Bernard94/p/16292037.html
Copyright © 2020-2023  润新知