几乎所有编程语言都有一些使用动态数组的列表实现,动态数组在达到一定容量时会自动扩展。例如,Java有ArrayList
,C ++有std::vector
。
最近我学习了圆形阵列deques,它也是使用动态数组实现的。它们跟踪列表的起始索引,并使用模运算来访问元素。与数组列表一样,它们允许在末尾进行O(1)查找和O(1)插入,并且与O(N)成比例的空间。但是,它们也允许在开始时插入O(1)。
(虽然Java的ArrayDeque
实现了这种数据结构,但它不允许查找元素.C ++的std::deque
似乎使用了不同的实现。)
如果这些数组deques与数组列表具有相同或更好的性能特征,那么为什么不总是将它们用作列表的默认实现呢?
答案 0 :(得分:1)
如果您不需要插入列表的头部,那么圆形双端队列会产生不必要的开销,例如:索引方法。在循环双端队列中,访问索引i需要在访问底层数组之前将i添加到head元素的索引并循环(例如,使用模运算符或按位运算符),而使用vanilla向量时,在访问之前不需要对i进行操作底层数组。
为了证明这种开销,典型的deque实现可能如下所示:
template <typename T>
class Deque {
private:
T* array; // The underlying array, holding elements of the deque.
int size; // The number of elements held by the deque.
int capacity; // The size of array ** must be a power of two **.
int head; // The index of the head element within array.
public:
T& operator[](int index) {
// Notice the calculation required before accessing array.
return array[(head + index) & (capacity - 1)]
}
};
此外,如果您需要访问从索引0开始元素连续的基础数组,则无法传递deque。
请参阅问题Why would I prefer using vector to deque,这与您的问题非常相似。