栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

ArrayList 为啥添加元素时会比较慢?

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

ArrayList 为啥添加元素时会比较慢?

一 、ArrayList 与 linkList 的区别

相同点:

1. 都是List的子类。
2. 允许空值

区别:

ArrayList:
	1. 内部是数组结构实现
	2. 数据的插入和删除都需要对数组复制和重排序(删除和插入比较慢)
	3. 有序可以重复
	4. 插入和删除比较慢
	5. 查找效率高
linkList:
	1. 双向链表结构,对每一个元素都有指向前后元素的指针
	2. 顺序读取效率比较高,随机读取元素效率比较低
	3. 删除、插入效率高
	4. 查询比较慢
二、ArrayList 添加元素

在查看源代码过程当中可以发现:当我们使用add(index,element) ; 方法时,在某个位置添加一个元素的操作,举例:add(0,5),在第一个位置加入一个5的元素。

    public void add(int index, E element) {
        // 比对下标和数据长度或者下标小于0,否则抛出数据下标越界
        rangeCheckForAdd(index);
		//DEFAULT_CAPACITY = 10 默认的容量是 10 ,最小值和默认参数对比(取最大的那个作为最小容量)
        ensureCapacityInternal(size + 1);  // Increments modCount!!
    
        //移位复制 arraycopy,将 index 的位置空出去,本地方法C/c++写的。
	
        System.arraycopy(elementData, index, elementData, index + 1,size - index);
        //添加index元素
        elementData[index] = element;
        //数组长度自增
        size++;
    } 
    //10容量
    private void ensureExplicitCapacity(int minCapacity) {
        modCount++;
        // overflow-conscious code
        //对比是否需要扩容
        if (minCapacity - elementData.length > 0)
            grow(minCapacity);
    }
    //计算容量
    private void grow(int minCapacity) {
        // overflow-conscious code
        int oldCapacity = elementData.length;
        int newCapacity = oldCapacity + (oldCapacity >> 1);
        if (newCapacity - minCapacity < 0)
            newCapacity = minCapacity;
        if (newCapacity - MAX_ARRAY_SIZE > 0)
            newCapacity = hugeCapacity(minCapacity);
        // minCapacity is usually close to size, so this is a win:
        //复制过去
        elementData = Arrays.copyOf(elementData, newCapacity);
    }

直接add的方式:

    public boolean add(E e) {
    	//自增容量,跟前面的指定位置存放是一样的
        ensureCapacityInternal(size + 1);  // Increments modCount!!
        elementData[size++] = e;
        return true;
    }
    
    private void ensureCapacityInternal(int minCapacity) {
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
            minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
        }

        ensureExplicitCapacity(minCapacity);
    }
三、ArrayList 删除元素

删除的方法都是:remove(Object / index)
第一种:list 删除指定位置(index)的数据

	
    public E remove(int index) {
        //检查是否下标越界
        rangeCheck(index);
        modCount++;
        
        //获取需要删除的元素 
        E oldValue = elementData(index);

        int numMoved = size - index - 1;
        //元素移动,左移
        if (numMoved > 0)
            System.arraycopy(elementData, index+1, elementData, index, numMoved);
            
        elementData[--size] = null; // clear to let GC do its work
	
        return oldValue;
    }

第二种:list 删除数据对象,不管在哪个位置

	//返回是否删除
    public boolean remove(Object o) {
        if (o == null) {
      	 	
            for (int index = 0; index < size; index++)
                if (elementData[index] == null) {
                    fastRemove(index);
                    return true;
                }
        } else {
        	//并非null的时候,是在全数组的方式遍历获取在删除的。
            for (int index = 0; index < size; index++)
                if (o.equals(elementData[index])) {
                    fastRemove(index);
                    return true;
                }
        }
        return false;
    }
	
    private void fastRemove(int index) {
        modCount++;
        int numMoved = size - index - 1;
        if (numMoved > 0)
            System.arraycopy(elementData, index+1, elementData, index,
                             numMoved);
        elementData[--size] = null; // clear to let GC do its work
    }
四、linkList 添加元素
   
    public boolean add(E e) {
      	//默认方式
        linkLast(e);
        return true;
    }
    
    //添加元素
    void linkLast(E e) {
        final Node l = last;
        final Node newNode = new Node<>(l, e, null);
        last = newNode;
        if (l == null)
        //第一次添加元素
            first = newNode;
        else
        //节点的下一个值
            l.next = newNode;
        size++;
        modCount++;
    }
五、linkList 删除元素

第一种方式:index

    public E remove(int index) {
        
        checkElementIndex(index);
        //
        return unlink(node(index));
    }

	
    Node node(int index) {
        // assert isElementIndex(index);
		
		// size >> 1  如果size = 32,size >> 1 = 16 ,分成两部分查找
        if (index < (size >> 1)) {
            Node x = first;
            //遍历节点
            for (int i = 0; i < index; i++)
                x = x.next;
            return x;
        } else {
            Node x = last;
            for (int i = size - 1; i > index; i--)
                x = x.prev;
            return x;
        }
    }

	
	E unlink(Node x) {
        // assert x != null;
        final E element = x.item;
        final Node next = x.next;
        final Node prev = x.prev;

        if (prev == null) {
            first = next;
        } else {
            prev.next = next;
            x.prev = null;
        }

        if (next == null) {
            last = prev;
        } else {
            next.prev = prev;
            x.next = null;
        }

        x.item = null;
        size--;
        modCount++;
        return element;
    }

第二种方式:object

	
    public boolean remove(Object o) {
        if (o == null) {
            for (Node x = first; x != null; x = x.next) {
                if (x.item == null) {
                    unlink(x);
                    return true;
                }
            }
        } else {
            for (Node x = first; x != null; x = x.next) {
                if (o.equals(x.item)) {
                    unlink(x);
                    return true;
                }
            }
        }
        return false;
    }
四、总结

通过上述的源代码方式:我们可以看出ArrayList的添加和删除是通过移位复制,并且是系统本地方法(具体想深入研究的和话可以下载arrayCopy C++ 代码实现),删除会遍历所有的元素,不确定性很大。所以在删除和添加操作是比较慢的

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/457280.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号