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