二、场景
列表中我们使用最多的是ArrayList,下面看看他的插入(add方法)算法,源代码如下:
public void add(int index,E element){
/*检查下标是否越界,代码不在拷贝*/
//若需要扩容,则增大底层数组的长度
ensureCapacity(size + 1);
//给index下标之后的元素(包括当前元素)的下标加1,空出index位置(将elementData从index起始,复制到index+1的职位
System.arraycopy(elementData,index,elementData,index + 1,size - index);
//赋值index位置元素
elementData[index] = element;
//列表的长度+1
size++;
}
注意看arraycopy方法,只要是插入一个元素,其后的元素就会向后移动一位,虽然arraycopy是一个本地方法,效率非常高,但频繁的插入,每次后面的元素都需要拷贝一遍,效率变低了,特别是在头位置插入元素时。
那么开发过程中确实会遇到插入元素的情况,我们一般使用LinkedList类即可。LinkedList是一个双向的链表,它的插入只是修改相邻元素next和previous引用,插入算法(add方法)如下:
public void add(int index,E element){
addBefore(element,(index==size?header:entry(index)));
}
这里调用了私有addBefore方法,该方法实现在entry元素之前插入元素e的算法,代码如下:
private Entry<E> addBefore(E e,Entry<E> entry){
//组装一个新的节点,previous指向原节点的前节点,next指向原节点
Entry<E> newEntry = new Entry<E>(e,entry,entry.previous);
//前节点的next指向自己
newEntry.previous.next = newEntry;
//后节点的previous指向自己
newEntry.next.previous = newEntry;
//长度+1
size++;
//修改计数器+1
modCount ++;
return newEntry;
}
这是一个典型的双向链表插入算法,把自己插入到链表,然后把前节点的next和后节点的previous指向自己。
经过实际测试得知,LinkedList的插入效率比ArrayList块50倍以上。
且慢,增加元素还有一个add()方法(无参数),该方法增加元素性能上基本没有什么差别,区别在于LinkedList生成一个新的Entry元素,其previous指向倒数第二个Entry,next置空;而ArrayList则是把元素追加到了数组末尾而已。差别非常微小。
ArrayList删除指定位置上的元素、删除指定值元素,删除一个下标范围内的元素集等删除动作,三者的实现原理基本相似,都是找到索引位置,然后删除。我偶们常用的删除下标的方法(remove方法)为例来看看删除动作的性能到底如何,源码如下:
public E remove(int index){
//下标校验
RangeCheck(index);
//修改计数器+1
modCount++;
//记录要删除的元素
E oldValue = (E)elementData(index);
//有多少个元素向前移动
int numMoved = size - index - 1;
if(numMoved > 0)
//index后的元素向前移动一位
System.arraycopy(elementData,index + 1,elementData,index,numMoved);
//列表长度减1,并且最后一位设为null
elementData[--size] = null;
//返回删除的值
return oldValue;
}
注意看,index位置后的元素都向前移动了一位,最后一个位置空出来了,这又是一次数组拷贝,和插入一样,如果数据量大,删除动作必然会暴露出性能和效率方面的问题。
我们再来看看LinkedList的删除动作,比如删除指定位置元素,删除头元素等。我们看看最基本的删除指定位置元素的方法remove,源代码如下:
private E remove(Entry<E> e){
//取得原始值
E result = e.element;
//前节点next指向当前节点的next
e.previous.next = e.next;
//后节点的previouse指向当前节点的previous
e.next.previous = e.previous;
//置空当前节点的next和previous
e.next = e.previous= null;
//当前元素置空
e.element = null;
//列表长度减1
size --;
//修改计数器+1
modCount++;
return result;
}
这也是双向链表的标准删除算法,没有任何耗时的操作,全部是引用指针的改变,效率自然就更高了。
实际测试可知,处理大批量的删除操作,LinkedList比ArrayList块40倍以上。
写操作还有一个动作:修改元素,在这点上LinkedList输给了ArrayList,这是因为,LinkedList是顺序存取的,因此定位元素必然是一个遍历的过程,效率大大折扣。
public E set(int index,E element){
//定位节点
Entry<E> e = entry(index);
E oldVal = e.element;
//节点元素替换
e.element = element;
return oldVal;
}
看似很简洁,这里使用了entry方法定位元素。而LinkedList这种顺序取列表的元素定位方式会折半遍历,这是一个极其耗时的操作。而ArrayList的修改动作则是数组元素的直接替换,简单高效。
在修改动作上,LinkedList比ArrayList慢的多,特别是进行大量修改的时候,完全不是在一个数量级上。
相关推荐
Java 中Linkedlist类的源代码Java 中Linkedlist类的源代码Java 中Linkedlist类的源代码Java 中Linkedlist类的源代码
java LinkedList的添加删除操作 java LinkedList的添加删除操作
使用LinkedList模拟堆栈操作,包括进栈、出栈,入队、出队
非常简单的Java LinkedList 应用实例
java中LinkedList集合类实现栈和队列.docjava中LinkedList集合类实现栈和队列.docjava中LinkedList集合类实现栈和队列.docjava中LinkedList集合类实现栈和队列.docjava中LinkedList集合类实现栈和队列.doc
【Java面试题】ArrayList和LinkedList区别
java.util.LinkedList$ListItr.checkForComodification(LinkedList.java:953) java.util.LinkedList$ListItr.next(LinkedList.java:886) JMeter.plugins.functional.samplers.websocket.ServiceSocket....
ava基础 基础知识 面向对象基础 Java基本数据类型 string和包装类 final关键字特性 Java类和包 抽象类和接口 代码块和代码执行顺序 Java自动拆箱装箱里隐藏的秘密 ...Java集合详解8:Java集合类细节精讲 JavaWeb
Java集合框架:这部分问题关注ArrayList、LinkedList、HashMap、HashSet等集合类的特性和使用。例如,比较ArrayList和LinkedList的优缺点;解释HashMap的工作原理和如何处理哈希冲突;讨论如何选择合适的集合类来...
LinkedList 是一个继承于AbstractSequentialList的双向链表。它也可以被当作堆栈、队列或双端队列进行操作。 LinkedList 实现 List 接口,能...LinkedList 实现 Deque 接口,即能将LinkedList当作双端队列使用。
实现一个链表LinkedList,要求使用链表机构实现,并提供相应的add(Object o),remove(Object o)这两个方法.
·课程中,Eclipse和IDEA这两种企业一线开发环境都使用到了 3.技术讲解更深入、更全面: ·课程共30天,715个知识视频小节,涉及主流Java使用的方方面面,全而不冗余 ·全程内容涵盖数据结构、设计模式、JVM内存...
java代码-LinkedListDome.java:8: error: cannot find symbol
栈是先进先出的原则,该类实现了栈的移入移除
使用LinkedList类编写程序,用某种集合接口的实现类作存储,实现具有自定义排序功能的包含姓名、年龄、身高、职称等内容的人事信息输入和打印。
附有面试讲解视频,不是网盘,下载既有视频,屡试不爽的面试宝典。 Java面试题01.面试的整体流程 Java面试题02.java的垮平台原理 Java面试题03....Java面试题04.java中...Java面试题80:java访问redis级redis集群 ......
java代码-【3】定义一个学生类,使用LinkedList对学生类进行管理,执行添加操作,并打印数据。 运行效果图为: 任务: 1.定义一个学生类Student (1)属性为:学号stuId(int),姓名name(String),成绩...
Map+List+ArrayList+LinkedList Java源代码,适合初学者
解决约瑟夫出圈问题的实现代码,大家共享 如果你有更好的资源,请给我来一份 package maicle; import java.util.LinkedList; public class Linklist { static int M=5;//选择第几个人出圈 static int N=10;//人数 ...