【问题标题】:How is a linked list faster than an array for insert and delete operations although it takes O(n) for both data structures?尽管这两种数据结构都需要 O(n),但链表在插入和删除操作中比数组更快吗?
【发布时间】:2018-12-25 11:50:23
【问题描述】:

数组中插入和删除操作的最坏情况运行时间是 O(n),因为我们可能需要进行 n 次移位。

链表也是如此,如果我们想插入或删除第 i 个元素,我们可能需要遍历整个链表才能到达预期插入/删除的位置。所以链表也需要 O(n) 时间。

那么为什么在执行插入/删除密集操作时首选链表。

【问题讨论】:

  • O(1) 的链表插入操作假设我们停留在需要的节点。
  • 但实际情况并非如此。我们总是必须遍历本质上再次使其成为 O(n) 的元素。
  • 搜索需要的地方和插入/删除是不同的操作。是的,它们经常一起使用,但一些算法利用单列表遍历和多次插入等。请注意,由于您的原因,LL 的实际使用相当罕见。
  • 根据 Stroustrup 的说法,向量比链表快,因为时间主要是搜索而不是移位:isocpp.org/blog/2014/06/stroustrup-lists
  • 你有什么数据来支持链表是首选插入/删除密集操作的断言?

标签: arrays algorithm data-structures linked-list big-o


【解决方案1】:

如果要插入/删除数组中的第 i 个元素,由于索引,搜索只需要 O(1)。例如,您可以通过array[i] 访问数组的第 i 个元素。但是,在最坏的情况下,插入/删除该元素将花费 O(n) 时间。例如,如果您在位置 0 处插入一个元素,则必须将所有元素向右移动一个位置,这需要遍历整个数组。

如果你想插入/删除链表中的第 i 个元素,搜索将在最坏的情况下花费 O(n),因为你必须在一次遍历链表一个元素时保留一个计数和一个指针。一旦到达第 i 个节点,插入/删除只需要 O(1) 时间,因为它只是指针的重新排列,没有移位。

至于为什么在有很多插入/删除时首选链表,我想说一个原因是使用链表您不需要提前知道它有多大。而对于数组,它可能必须经常调整大小以预期更多/更少的元素。

【讨论】:

  • 在数组列表中调整数组大小需要恒定的摊销时间,通常比添加链表节点快得多。
  • @MattTimmermans 您能否详细说明或将我指向可以解释您所说内容的链接?
  • @KrishnaSai 在这里尝试接受的答案:stackoverflow.com/questions/200384/constant-amortized-time
【解决方案2】:

在这两种情况下搜索元素是相同的 (O(n))。不同之处在于您在指定位置时插入和删除。在这种情况下,插入和删除是O(1)在链表中(因为你应该重置两个指针),但需要O(n)在数组中(因为你需要O(n)移位)。

另一个区别是从一个位置遍历到另一个位置。在列表中,此遍历采用O(n),但在数组中为O(1)

【讨论】:

  • 在两种情况下查找元素是相同的 (O(n))。 不一定正确。您可以在 O(1) 中找到数组中的第 i 个元素。
【解决方案3】:

当有一个直接指向节点的附加数据结构时,从链表中删除/插入 O(1) 的好处就实现了。这可以避免列表遍历的 O(n) 成本。

一个很好的例子是有限大小的 LRU 缓存,其中键值对表示在一个映射中,该映射还保留指向链表的指针。列表代表访问顺序,这里是 LRU 利用快速链表访问的地方。从中间取出一个元素放在前面是 O(1)。

每个键访问 (O(1)) 都会将关联节点从列表中间取消链接并将其移动到列表的头部(在 O(1) 时间内)。当缓存满时,列表的尾节点(它代表最近最少使用的键/值)连同它所代表的键值对一起被移除。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-08-06
    • 1970-01-01
    • 2021-01-29
    • 2013-11-16
    • 1970-01-01
    相关资源
    最近更新 更多