为什么典型的数组列表实现不是双端的?



为什么ArrayList通常不实现为双端,支持在前面和后面快速摊销插入?

与前者相比,使用后者有缺点吗?

(我说的不仅仅是Java——我还没有看到在任何其他语言中双端数组列表是默认的,但Java只是一个很好的例子。)


*编辑:我最初称它们为"数组deques",但这对我来说是一个误解;我说的不是队列,而是双端数组列表。

ArrayList很简单;条目从0开始,您可以在末尾添加内容(这可能会延长数组),但列表中的条目#X始终是backing_array[X]

ArrayDeque会更复杂;除了必须跟踪序列的开始(因为它不再保证从0开始,除非你想要O(N)移位/取消移位),你还必须担心另一端是"空的"。这种额外的复杂性是有代价的;在更常见的情况下(列表),RTL仍然需要在deque中进行所有必要的检查和索引计算,从而无故降低应用程序的速度。条目#X变为backing_array[start+X],边界检查也有额外的数学运算。

因此,除非您确实需要deque功能,否则坚持使用列表会更简单、更高效,至少在处理数组时是这样。

当你想以先进先出或后进先出的方式访问数据时,就会使用deque,它们的公共接口既不能提供获得第n个元素的方法,你应该手动完成,事实上,如果你看一下这里的Java deque,你就会明白没有提供第n个方法。这应该足以避免在需要索引任何数据组时使用它。

好吧,您可以将deque实现为一个数组,而不是一个普通数组,但这添加了一些功能,这些功能应该在您需要时考虑,而不是默认情况下。否则,您可以为简单的问题使用更复杂的数据结构辩护,因为您可以。

IMHO这也是当今阵列之间的协同作用问题,以及当您在离机器更近的地方编写代码时如何实现/管理它们。

在Java中,ArrayDeque不实现List。我不知道为什么没有。

正常的ArrayList实现是代码的正常转到集合类型,它只需要一些可以重复向其中添加项,然后从中读取项的东西。该类型提供了更多的功能,省略其中一些功能可能会增强该类型在主要使用情况下的功能,但如果ArrayList操作慢1%,则整个宇宙中必须花费的额外CPU时间总量将非常可观。

此外,目前还不清楚对双端数组列表的索引访问应该如何进行,因为有两种合理的行为模型:它可以指定从编号较低的一端添加或删除项应该更改所有现有项的编号,也可以指定在项0之前插入的项的索引为-1(所有现有索引都将保持不变)。在项目0之前添加超过2^32个项目(同时从另一端删除足够多的项目以避免内存耗尽)将添加项目MIN_INT,然后是项目MAX_INT,再是MAX_INT-1,等等。这样的界面在某些方面可能会很尴尬,但在其他方面可能非常好(例如,一种实现可以允许在两端操作的写入器线程和读取器线程同时进行索引访问,因为想要操作元素547的写入器不必担心当它这样做时,感兴趣的元素将移动到槽#548)。

当然有各种双端集合类型的用途,但这并不意味着添加双端特性会为常见用例增加任何价值。

最新更新