http://blog.chinabyte.com/blog.php?do-showone-uid-135325-itemid-454704-type-blog.html

总结下,LinkedList的两个remove方法,remove(Object)和remove(int)的时间复杂度都是O(n),在链表元素很多 并且没有索引可用的情况下,LinkedList也并不适合做随机增删元素。在对性能特别敏感的场景下,还是需要自己实现专用的双向链表结构,真正实现 O(1)级别的随机增删。更进一步,jdk5引入的ConcurrentLinkedQueue是一个非阻塞的线程安全的双向队列实现,同样有本文提到的 问题,有兴趣可以测试一下在大量元素情况下的并发随机增删,效率跟自己实现的特定类型的线程安全的链表差距是惊人的。确保PHP安全 不能违反的四条安全规则
    理论上说,双向链表的删除的时间复杂度是O(1),你只需要将要删除的节点的前节点和后节点相连,然后将要删除的节点的前节点和后节点置为null即可,
    //伪代码
    node.prev.next=node.next;
    node.next.prev=node.prev;
    node.prev=node.next=null;
   
    这个操作的时间复杂度可以认为是O(1)级别的。但是LinkedList的实现是一个通用的数据结构,因此没有暴露内部的节点Entry对象,remove(Object)传入的Object其实是节点存储的value,这里还需要一个查找过程:
    public boolean remove(Object o) {
    if (o==null) {
    for (Entry<E> e = header.next; e != header; e = e.next) {
    if (e.element==null) {
    remove(e);
    return true;
    }
    }
    } else {
    //查找节点Entry
    for (Entry<E> e = header.next; e != header; e = e.next) {
    if (o.equals(e.element)) {
    //删除节点
    remove(e);
    return true;
    }
    }
    }
    return false;
    }
   
    java.util.LinkedList是双向链表,这个大家都知道,比如Java的基础面试题喜欢问ArrayList和LinkedList的区 别,在什么场景下用。大家都会说LinkedList随机增删多的场景比较合适,而ArrayList的随机访问多的场景比较合适。更进一步,我有时候会 问,LinkedList.remove(Object)方法的时间复杂度是什么?有的人回答对了,有的人回答错了。回答错的应该是没有读过源码。
    删除节点的操作就是刚才伪代码描述的:
    private E remove(Entry<E> e) {
    E result = e.element;
    e.previous.next = e.next;
    e.next.previous = e.previous;
    e.next = e.previous = null;
    e.element = null;
    size--;
    modCount++;
    return result;
    }
   
    因此,显然,LinkedList.remove(Object)方法的时间复杂度是O(n)+O(1),结果仍然是O(n)的时间复杂度,而非推测的O(1)复杂度。最坏情况下要删除的元素是最后一个,你都要比较N-1次才能找到要删除的元素。
   
    既然如此,说LinkedList适合随机删减有个前提,链表的大小不能太大,如果链表元素非常多,调用remove(Object)去删除一个元素的效率肯定有影响,一个简单测试,插入100万数据,随机删除1000个元素:
    final List<Integer> list = new LinkedList<Integer>();
    final int count = 1000000;
    for (int i = 0; i < count; i++) {
    list.add(i);
    }
    final Random rand=new Random();
    long start=System.nanoTime();
    for(int i=0;i<1000;i++){
    //这里要强制转型为Integer,否则调用的是remove(int)
    list.remove((Integer)rand.nextInt(count));
    }
    System.out.println((System.nanoTime()-start)/Math.pow(10, 9));
   
    在我的机器上耗时近9.5秒,删除1000个元素耗时9.5秒,是不是很恐怖?注意到上面的注释,产生的随机数强制转为Integer对象,否则调用的是 remove(int)方法,而非remove(Object)。如果我们调用remove(int)根据索引来删除:
    for(int i=0;i<1000;i++){
    list.remove(rand.nextInt(list.size()-1));
    }
    随机数范围要递减,防止数组越界,换成remove(int)效率提高不少,但是仍然需要2.2秒左右(包括了随机数产生开销)。这是因为 remove(int)的实现很有技巧,它首先判断索引位置在链表的前半部分还是后半部分,如果是前半部分则从head往前查找,如果在后半部分,则从 head往后查找(LinkedList的实现是一个环):
    Entry<E> e = header;
    if (index < (size >> 1)) {
    //前一半,往前找
    for (int i = 0; i <= index; i++)
    e = e.next;
    } else {
    //后一半,往后找
    for (int i = size; i > index; i--)
    e = e.previous;
    }
   
    最坏情况下要删除的节点在中点左右,查找的次数仍然达到n/2次,但是注意到这里没有比较的开销,并且比remove(Object)最坏情况下n次查找还是好很多。
   
    题外,ArrayList比LinkedList更不适合随机增删的原因是多了一个数组移动的动作,假设你删除的元素在m,那么除了要查找m次之外,还需要往前移动n-m-1个元素。

java的LinkedList的用法的更多相关文章

  1. 转: Java LinkedList基本用法

    LinkedList类是双向列表,列表中的每个节点都包含了对前一个和后一个元素的引用.LinkedList的构造函数如下1. public LinkedList():  ——生成空的链表2. publ ...

  2. Java:基于LinkedList实现栈和队列

    1.提供一组栈的接口,其底层关联到一个LinkedList(双端队列)实例.由于只暴露部分基于栈实现的接口,所以可以提供安全的栈实现. package junit; import java.util. ...

  3. Java集合---LinkedList源码解析

    一.源码解析1. LinkedList类定义2.LinkedList数据结构原理3.私有属性4.构造方法5.元素添加add()及原理6.删除数据remove()7.数据获取get()8.数据复制clo ...

  4. java通过LinkedList实现堆栈和队列数据结构

    package shb.java.demo3; import java.util.LinkedList; public class TestLinkedList { /** * @author sha ...

  5. java中this的用法?

    2008-07-28 08:10cztx5479 | 分类:JAVA相关 | 浏览4533次 java中this的用法? import java.awt.*; import java.awt.even ...

  6. 转:十八、java中this的用法

    http://blog.csdn.net/liujun13579/article/details/7732443 我知道很多朋友都和我一样:在JAVA程序中似乎经常见到“this”,自己也偶尔用到它, ...

  7. 设计模式 - 装饰者模式(Decorator Pattern) Java的IO类 用法

    装饰者模式(Decorator Pattern) Java的IO类 用法 本文地址: http://blog.csdn.net/caroline_wendy/article/details/26716 ...

  8. Java 集合 LinkedList的ListIterator

    Java 集合 LinkedList的ListIterator @author ixenos 摘要:ListIterator<E>是继承自Iterator<E>的接口.list ...

  9. java.util.ArrayList、java.util.vector和java.util.LinkedList (JDK 1.8.0_111)

    一.java.util.ArrayList 1.1 ArrayList 继承结构 ArrayList实现了RandomAccess,可以随机访问(其实就是通过数组下标访问):实现了Cloneable, ...

随机推荐

  1. php+mssql 已经写好的万能函数

    <?php /****************************************************************************************** ...

  2. smarty模板引擎中section循环loop与total的区别

    在smarty模板引擎的section循环中 $data=[101,102,103,105,104]; section的两个属性total与loop {section foo $data start= ...

  3. [转]详解AppDelegate/UIApplication

    一.UIApplication 1.简单介绍 (1)UIApplication对象是应用程序的象征,一个UIApplication对象就代表一个应用程序. (2)每一个应用都有自己的UIApplica ...

  4. 深入理解Azure自动扩展集VMSS(2)

    VMSS中Auto Scale基本原理及诊断 在前面的介绍中,我们看到通过定义规则可以实现虚拟机扩展集的auto scale,那么在后台执行上VMSS的扩展依赖于哪些组件,出现问题(比如自动扩展没有发 ...

  5. python的闭包以及闭包在设计里的意图和作用

    def test(func): print func(3,4) test(lambda x,y : x+y) test(lambda x,y : x-y) 这是python的一种闭包写法,他的设计意图 ...

  6. Effective Java提升Code Coverage代码涵盖率 - 就是爱Java

    虽然我们已经有了测试程序,但是如何得知是否已完整测试了主程序?,透过Code Coverage代码涵盖率,我们可以快速地得知,目前系统中,有多少程序中被测试过,不考虑成本跟投资效益比,涵盖率越高,代表 ...

  7. Netbeans7.4+Weblogic11g+Spring3.2.4操作JdbcTemplate

    第一步:在Weblgic11g管理界面:http://localhost:7001/console 中建立数据源,我建立的jndi名称为:sjsstjndi 第二步:需要导入spring的以下包:使用 ...

  8. 解决Sqlite UTF-8中文数据格式在DOS窗口下中文乱码

    问题如下图所示: 右键查看DOS属性:点击选项->当前代码页为GBK 只要将当前代码页编码值设置为UTF-8就可以了: ‘退出sqlite:.exit 输入:chcp 65001回车 右键属性: ...

  9. getResources().getXml()获取xml

    获取XML文件的基本思路是,通过getResources().getXml()获的XML原始文件,得到XmlResourceParser对象,通过该对象来判断是文档的开头还是结尾,是某个标签的开始还是 ...

  10. mysql 增量导入到elasticsearch

    <pre name="code" class="html">zjtest7-redis:/odbc_es# cat /odbc_es/run_mys ...