这个问题其实来源于Leetcode的一道题目,也就是上一篇日志 LRU Cache。在使用LinkedList超时后,换成ArrayList居然AC了,而问题居然是在于List.remove(Object o)这个方法。
我们知道,链表和数组相比,最主要的特点就是add和remove的操作是O(1)的。Java中的链表一般使用LinkedList这个类型,数组一般使用ArrayList。它们同时implements了List这个interface,所以都有remove(int index)和remove(Object o)这两个方法。
普通意义上认为链表的remove操作是O(1)的,是因为对于某个给定的节点node,可以将它的前置节点的next直接置为node的下一个。而数组,则需要删除index处的元素,再将后面n个元素前移,所以需要O(n)的时间。
但是,在Java中果真如此吗?
细看JDK的源码,就可以发现,LinkedList的remove(int index)和remove(Object o)这两个方法都做不到O(1)的时间,而是O(n)。这是因为上面说的数据结构中的O(1)时间,是对于某个已经确定的节点。而LinkedList中,首先必须通过一个循环,找到第一个出现的Object o,或者走到index这个位置,再进行操作。也就是,有一个get的过程。
这时,虽然ArrayList的remove(int index)和remove(Object o)也是O(n)时间,但是移动耗费的时间远比LinkedList中往后寻址来的快得多,特别是元素很多的时候。JDK的源码里,这个操作是用System.arraycopy()来做的。所以,这时,LinkedList的最为坑爹的地方,也是最令人不解的地方就出现了——remove的操作居然比ArrayList还慢,而且慢的多!
而且,LinkedList需要内部维护一个数据结构,JDK 6中叫Entry,JDK 7中叫Node,这需要很多额外的内存。所以,除非急切需要LinkedList的Deque功能,任何情况下都应该使用ArrayList。其实,即使要用Deque,也有ArrayDeque。
所以,有时面试会问,在一个LinkedList list的遍历for循环中,不断执行remove(i)操作,时间复杂度是多少?其实是O(n^2),而不是O(n)。但是,如果使用iterator,it.remove()的时间复杂度就是O(1)了,因为这时元素已经给定。并且,for循环中进行remove(i)操作是要影响下标的。remove过后每次i都必须i--。使用iterator可以有效避免这个问题。这里可以看到,虽然for循环比较直观,但是有时iterator还是非常好的。
转载-Java中LinkedList的一些方法—addFirst addFirst getFirst geLast removeFirst removeLast
Java中LinkedList的一些方法—addFirst addFirst getFirst geLast removeFirst removeLast 版权声明:本文为博主原创文章,遵循CC 4. ...
java中substring的使用方法
java中substring的使用方法 str=str.substring(int beginIndex);截取掉str从首字母起长度为beginIndex的字符串,将剩余字符串赋值给str: str ...
Java中Set的contains()方法
Java中Set的contains()方法 -- hashCode与equals方法的约定及重写原则 翻译人员: 铁锚 翻译时间: 2013年11月5日 原文链接: Java hashCode() a ...
[java,2017-05-16] java中清空StringBuffer的方法以及耗费时间比较
java中清空StringBuffer的方法,我能想到的有4种: 1. buffer.setLength(0); 设置长度为0 2. buffer.delete(0, buffer.length() ...
java中BorderLayout的使用方法
相关设置: 使用BorderLayout布局上下左右中布局5个按键,单击中间的那个按键时就关闭窗口 代码: /**** *java中BorderLayout的使用方法 * 使用BorderLayout ...
【Java】Java中常用的String方法
本文转载于:java中常用的String方法 1 length()字符串的长度 String a = "Hello Word!"; System.out.println(a.len ...
Java中Set的contains()方法——hashCode与equals方法的约定及重写原则
转自:http://blog.csdn.net/renfufei/article/details/14163329 翻译人员: 铁锚 翻译时间: 2013年11月5日 原文链接: Java hashC ...
java中equals和hashCode方法随笔二
前几天看了篇关于java中equals和hashCode方法的解析 1.Object类中的equals方法和hashCode方法. Object类中的equals和hashCode方法简单明了,所有的 ...
java中static变量和方法的总结
转自:http://blog.csdn.net/haobo920/article/details/5921621 java中static变量和方法的总结 java中一切皆是对象 一个类中对象的定义一般 ...
随机推荐
纯命令行的编辑利器:用好 awk 与 sed
awk 的基本语法 awk 是模式查找与处理语言,是文本处理的利器.使用 awk 可以只用一条简单的命令完成复杂的文本数据处理. awk 命令的基本结构为: awk '模式 {处理}' 文件 比如,打 ...
android内部培训视频_第二节 布局基础
第二节:布局入门 一.线性布局 需要掌握的属性: 1.orientation:排列方式 vertical:垂直 Horizontal:水平 2.weight:水平布局的权重 3.gravity:子控件 ...
MC3190终端配置冷启动自动恢复的方法
一. 网络配置的恢复 将当前文件夹下的注册表文件MC3190 Start Config.reg(见附件)复制到终端的Application文件夹内(可以通过数据线或ftp方式传送文件); 导出终端的网 ...
Dojo学习_组件属性
注意组件的引用顺序,避免出现对象不是构造函数或属性undefined的情况! 1.修改文本 require([ 'dojo/dom', 'dojo/domReady!' ], function (d ...
HDU-2604_Queuing
题目:Problem Description Queues and Priority Queues are data structures which are known to most comput ...
我的TDD实践---SVN架设篇
我的TDD实践---SVN架设篇 “我的TDD实践”系列之SVN架设 写在前面: 我的TDD实践这几篇文章主要是围绕测试驱动开发所展开的,其中涵盖了一小部分测试理论,更多的则是关注工具的使用及环境的搭 ...
python3爬虫 - cookie登录实战
http://blog.csdn.net/pipisorry/article/details/47948065 实战1:使用cookie登录哈工大ACM网站 获取网站登录地址 http://acm.h ...
Python unittest使用小结
unittest是Python自带的单元测试框架,其中最核心的四个概念是:test case, test suite, test runner, test fixture. 流程:TestLoader ...
python--logging日志
一个非常详细的日志使用请看这里:http://www.cnblogs.com/dkblog/archive/2011/08/26/2155018.html # 导入日志模块 import loggin ...
关于linq的几个小例子
private void button1_Click(object sender, EventArgs e) { ] { ,,,,,,}; var result0 = from num in numb ...