Language agnostic 是否有索引链表的已知实现?

Language agnostic 是否有索引链表的已知实现?,language-agnostic,list,indexing,linked-list,Language Agnostic,List,Indexing,Linked List,我的直觉告诉我没有好的方法来实现这一点,但是,与Stephen Colbert先生不同,我宁愿相信一个开发者社区而不是我的直觉 有没有一种已知的方法可以有效地实现“两个世界中最好的”列表,一种像链表一样通过索引和O(1)插入/删除提供随机访问的列表 我预见到两种可能的结果:要么“不,这是不可能的,因为以下明显的原因……”要么“嗯,是的,这已经完成了;请看这里、这里和这里。”我认为插入和查找都不可能得到O(1)。当您添加一个数组(甚至是奇特的可拆分向量)时,插入就变成了O(n) 根据列表的预期行为

我的直觉告诉我没有好的方法来实现这一点,但是,与Stephen Colbert先生不同,我宁愿相信一个开发者社区而不是我的直觉

有没有一种已知的方法可以有效地实现“两个世界中最好的”列表,一种像链表一样通过索引O(1)插入/删除提供随机访问的列表


我预见到两种可能的结果:要么“不,这是不可能的,因为以下明显的原因……”要么“嗯,是的,这已经完成了;请看这里、这里和这里。”

我认为插入和查找都不可能得到
O(1)
。当您添加一个数组(甚至是奇特的可拆分向量)时,插入就变成了
O(n)

根据列表的预期行为,有一些方法可以减轻损害。如果查找的次数比插入/删除的次数多得多,那么最好只使用向量(可变大小的数组)——它们相当有效,不像数组,但比遍历列表要好(由于这些元素往往是数组列表,从技术上讲,它仍然在遍历一个列表,但列表中的每个元素通常都有其大小,这使得它更高效)

如果插入和删除更频繁,则可以使索引生成为惰性索引,以便仅在需要时执行。例如,插入和删除只会更改链接列表部分(并将索引标记为脏索引)-只有当有人尝试使用索引时,才会重新生成索引并将其标记为干净索引

您甚至可以通过保留第一个脏项的记录来优化重建。这意味着,如果您只在列表的后半部分插入或删除,当有人想使用它时,您不需要重建整个索引

我曾经实施的一个解决方案是2D列表。我的意思是:

        +-----------+    +-----------+    +-----------+
List -> | count = 7 | -> | Count = 4 | -> | Count = 6 | -> null
        +-----------+    +-----------+    +-----------+
              |                |                |
              V                V                V
        +-----------+    +-----------+    +-----------+
        |    [0]    |    |    [7]    |    |   [11]    |
        +-----------+    +-----------+    +-----------+
              |                |                |
              V                V                V
        +-----------+    +-----------+    +-----------+
        |    [1]    |    |    [8]    |    |   [12]    |
        +-----------+    +-----------+    +-----------+
              |                |                |
              :                :                :
              :                :                :
              |                |                |
              V                V                V
        +-----------+    +-----------+    +-----------+
        |    [6]    |    |   [10]    |    |   [16]    |
        +-----------+    +-----------+    +-----------+
              |                |                |
              V                V                V
             null             null             null
在纯数组解决方案中,查找是
O(1)
,插入是
O(n)
。对于纯链表,插入是
O(1)
(一旦找到插入点,当然是一个本身就是
O(n)
)的操作,而查找是
O(n)

二维列表是
O(n)
两者都适用,但系数较低。如果要插入,只需检查每列的第一行即可找到正确的列。然后遍历列本身,查找正确的行。然后插入项并增加该列的计数。对于删除,情况类似,尽管在这种情况下,计数是递减的sed,当其计数达到零时,整个列将被删除

对于索引查找,可以遍历列以找到正确的列,然后遍历列中的项以获得正确的项


而且,它甚至可以通过尝试保持最大高度和宽度大致相同来自动调整。

我不知道插入时的确切BigO(因为这会根据样本大小和增长而变化),但Java的
Java.util.LinkedList会立即浮现在我的脑海中

编辑:是的,显然它下面仍然是一个真正的链表,因此索引的get可以是O(n/2),这当然是形式上的O(n)


您可以浪费一大堆空间,实现一个列表实现,它实现了一个并行链表和数组,它具有延迟插入/删除。

当我在类中实现一个链表时,我想通过存储3个附加字段来优化访问时间:列表中间的节点,最右边的索引。y访问的节点和最近访问的节点本身

要按索引检索节点,我首先查看所有可用路径,以到达给定索引处的节点,然后选择最便宜的方法。方法如下:

  • 从开始到所需的索引
  • 从最近访问的节点转到所需索引(转发)
  • 从最近访问的节点转到所需索引(向后)
  • 从中间节点到所需索引(向前)
  • 从中间节点到所需索引(向后)
  • 从节点的末尾到所需索引
  • 所需索引和起始索引之间差异最小的路径将是最便宜的选择。如果尚未访问任何节点,则最近访问的节点可以设置为中间节点。当然,对于偶数个元素,没有实际的中间节点,因此我只选择n/2的楼层


    无论如何,我从来没有真正实现过这个优化,甚至没有真正分析过它,但我希望我能帮上忙。

    Java的
    LinkedList
    对索引的get有O(n)访问权。
    LinkedList
    扩展了
    AbstractSequentialList
    ,表明它不提供O(1)个索引的get

    我建议您看看。它提供了O(logn)插入/删除和O(1)索引查找。

    如果您这样认为,
    退房:

    • ,O(logN)在每次操作中
    • ,O(logN)在每次操作中

      • 你的直觉是正确的

        链表是O(1)插入/删除,因为插入或删除某些内容的操作只是切换两个指针(插入对象上的一个或两个指针,以及其他一个或两个对象上的一个或两个指针)。这显然不会因列表的大小而改变

        跳过列表将为您提供O(logn)查找,但由于您维护的是索引,因此也意味着O(logn)插入/删除,因为该索引需要保持最新

        您用于查找的任何并行数据结构都需要维护,因此您的复杂性将根据该索引的复杂性进行扩展

        你有没有想解决的问题

        例如,如果你能保证一个完美的散列,你可以得到O(n)的插入、删除和查找