|
|
|
|
移动端

3.3.4 例子: remove方法对LinkedList类的使用

《数据结构与算法分析:Java语言描述(原书第3版)》第3章表、栈和队列,本章讨论最简单和最基本的三种数据结构。实际上, 每一个有意义的程序都将显式地至少使用一种这样的数据结构, 而栈则在程序中总是要被间接地用到, 不管我们在程序中是否做了声明。本节为大家介绍例子: remove方法对LinkedList类的使用。

作者:冯舜玺/陈越 译来源:机械工业出版社|2016-04-13 12:08

技术沙龙 | 6月30日与多位专家探讨技术高速发展下如何应对运维新挑战!


3.3.4 例子: remove方法对LinkedList类的使用

作为一个例子, 我们提供一个例程, 将一个表中所有具有偶数值的项删除。于是, 如果表包含6,5,1,4,2, 则在该方法调用之后, 表中仅有元素5,1。

当遇到表中的项时将其从表中删除的算法有几种可能的想法: 当然, 一种想法是构造一个包含所有的奇数的新表, 然后清除原表, 并将这些奇数拷贝回原表。不过, 我们更有兴趣的是写一个干净的避免拷贝的表, 并在遇到那些偶数值的项时将它们从表中删除。

对于ArrayList这几乎就是一个失败策略。因为从一个ArrayList的几乎是任意的地方进行删除都是昂贵的操作。不过, 在LinkedList中却存在某种希望, 因为我们知道, 从已知位置的删除操作都可以通过重新安排某些链而被有效地完成。

图3-10显示第一种想法。在一个ArrayList上, 我们知道, remove的效率不是很高的, 因此该程序花费的是二次时间。LinkedList暴露两个问题。首先, 对get调用的效率不高, 因此例程花费二次时间。而且, 对remove的调用同样地低效, 因为达到位置i的代价是昂贵的。

图3-11显示矫正该问题的一种思路。我们不是用get, 而是使用一个迭代器一步步遍历该表。这是高效率的。65但是我们使用Collection的remove方法来删除一个偶数值的项。这不是高效的操作, 因为remove方法必须再次搜索该项, 它花费线性时间。但是我们运行这个程序会发现情况更糟: 该程序产生一个异常, 因为当一项被删除时, 由增强的for循环所使用的基础迭代器是非法的。(图3-10中的代码解释为什么这样的原因: 我们不能期待增强的for循环懂得只有当一项不被删除时它才必须向前推进。)

图3-12指出一种成功的想法: 在迭代器找到一个偶数值项之后, 我们可以使用该迭代器来删除这个它刚看到的值。对于一个LinkedList, 对该迭代器的remove方法的调用只花费常数时间, 因为该迭代器位于需要被删除的节点(或在其附近)。因此, 对于LinkedList, 整个程序花费线性时间, 而不是二次时间。对于一个ArrayList, 即使迭代器位于需要被删除的节点上, 其remove方法仍然是昂贵的, 因为数组的项必须要移动, 正如所料, 对于ArrayList, 整个程序仍然花费二次时间。

如果我们传递一个LinkedList<Integer>运行图3-12中的程序, 对于一个400000项的lst, 花费的时间是0.031秒, 而对于一个800000项的LinkedList则花费0.062秒, 显然这是线性时间例程, 因为运行时间与输入大小增加相同的倍数。当我们传递一个ArrayList<Integer>时, 对于一个400000项的ArrayList程序几乎花费2.5分钟, 而对于800000项的ArrayList程序花费大约10分钟; 当输入增加到2倍时运行时间增加到4倍, 这与二次的特征是一致的。


喜欢的朋友可以添加我们的微信账号:

51CTO读书频道二维码


51CTO读书频道活动讨论群:342347198

【责任编辑:book TEL:(010)68476606】

回书目   上一节   下一节
点赞 0
分享:
大家都在看
猜你喜欢

读 书 +更多

网管员必读——故障排除

本书是《网管员世界》杂志社推出的一本集知识性和实用性于一身的网络管理技术书籍,书中收集了《网管员世界》自创刊以来“故障诊断”栏目中...

订阅51CTO邮刊

点击这里查看样刊

订阅51CTO邮刊