【问题标题】:Java: alternative to LinkedList or int pointer data structureJava:替代 LinkedList 或 int 指针数据结构
【发布时间】:2012-08-17 10:50:07
【问题描述】:

由于 LinkedList 在内存开销方面是一场噩梦,而且在迭代元素时速度也较慢,所以我希望有类似 int poiter 数据结构的东西。

所以我有一个整数列表,我通过在开头-中间插入元素来形成它。列表准备好后,我从左侧开始逐一迭代。这是我的问题约束。

【问题讨论】:

  • Insert in middle is O(1) with LinkedList and O(n) with ArrayList or "int pointer"...我不认为你有其他选择,除非你的问题有一些您可以使用的附加信息。
  • 只是出于好奇...您所指的“内存开销方面的噩梦”是什么?每个列表节点存储一个对其值对象的引用,一个对前一个节点的引用和一个对下一个节点的引用。这似乎是链表工作的最低要求(好吧,如果您只需要使用链表进行前向迭代,则可以摆脱“以前的”引用)。但是你指的内存开销是什么?仅仅是有一个“以前的”参考吗?

标签: java pointers insert linked-list


【解决方案1】:

我会分析并尝试不同的数据结构。

话虽如此,为什么不尝试使用ArrayList;迭代甚至插入都很快,而在 O(n) 中,速度很快,因为在缓存中移动连续数据的速度快如闪电。 (如果你在插入的同时也反转列表会更快!)


更新,因为我的程序员同事不明白为什么我推荐ArrayList 解决这个特殊问题:

问题不是插入元素。在这种情况下,链表直接获胜(O(1) 与数组列表的 O(n) 相对)。 问题是要找到插入它们的位置。在这种情况下,LinkedList 真的很慢。找到插入位置的开销很大,因为它不会在“好事情”中分配内存。很多缓存未命中!

OP 没有发布任何代码,所以我们只知道 OP 想要什么,但这里是对这两种情况的算法分析(其中 C* 是常量):

LinkedList,每个要插入的元素:

  • 迭代O(C1 * n)
  • 插入 O(1)

ArrayList,每个要插入的元素:

  • 迭代O(C2 * n)
  • 插入 O(C3 * n)

因此,这两种算法都在 O(n) 中,但仔细观察常量:C1 确实很大(如上所述)。另一方面,C2C3 很小,因为在缓存中迭代和移动速度很快。

所以,如果你有足够的内存试试ArrayList

【讨论】:

  • 我想我需要反转两次。
  • 或者只反转一次,然后从末尾迭代:)
  • 是的,插入时 / 在迭代之前。或者就像你说的那样从头开始迭代并且不要反转它。 :) 更新了我为什么推荐ArrayList 的答案。
【解决方案2】:

如果你经常做list.get(index);LinkedList 的表现确实很糟糕
请改用ListIterator,这样您每次都不会一遍又一遍地遍历列表
如果您需要在列表中间添加元素,它将比ArrayList O(1) 具有更好的性能(因为您不需要移动元素)

更新:
迭代列表的正确方法是使用迭代器(隐式或显式)。使用隐式迭代器的示例:

for(E e:list){  
}  

从不

for(int i = 0; list.size(); i++{  
    E e = list.get(i);  
}  

如果列表是LinkedList,则此操作为O(N^2),因为list.get(i) 在循环的每次迭代中从头开始遍历列表。
使用带有迭代器的第一种形式只是 O(N) 几乎与 ArrayList 相同,因为迭代器“记住”最后一个访问的元素并从那里开始

【讨论】:

  • 使用Iterator 查找索引在 O(n) 中,因此在将元素插入数组列表时移动元素。 如果您可以保存指针并重复使用它会更快。
  • 如果你使用迭代器在列表中移动,你有O(1)访问,因为你移动到下一个元素。如果你每次都做list.get(idx),那么是的,你是对的O(N)但这不是迭代列表的正确方法
  • 你不懂,用迭代器不管你用什么数据结构,找到插入元素的地方都是O(n)。
  • 当然。But在链表的情况下在那个地方插入元素是O(1)
  • 是的,我知道!我想说的是:LinkedList: O(C1*n + 1) => O(n)ArrayList: O(C2*n + C3*n) => O(n)C1 是一个很大的常量,在非连续内存上迭代很慢(OP 问题),而常量 C2(在连续内存上迭代)和 C3(移动连续内存)如果与 C1 相比相当小。
【解决方案3】:

试试Gaplist,它为许多用例提供类似于 ArrayList 的性能和内存占用。如果插入主要是顺序的(在 any 索引处),则插入接近 O(1)。

【讨论】:

  • "[...] 接近 O(1)" -- 对。对于足够大的 1 值,1 等于 2。
  • @aioobe 所以它不如那里写的那么快?
  • 没有“接近 O(1)”这样的东西 :) 这没有意义。
  • Close 是一个模糊的术语,因此没有指定一个完全可量化的值或大小。所以,我很好奇,你认为什么是更好的描述?
【解决方案4】:

第一步:在LinkedList中插入元素

第二步:复制元素到ArrayList进行迭代。

顺便说一句,“噩梦”对LinkedList来说有点夸张:)

【讨论】:

  • 仍然是 O(n) 找到插入元素的位置,以便您可以直接使用数组列表。
  • 在 ArrayList 中插入是 O(n),LinkedList 是 O(1)。
  • 是的,但是要找到插入的地方是O(n)(问题:从头到中的某处插入元素)。
猜你喜欢
  • 2016-07-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-02-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-08-29
相关资源
最近更新 更多