deque和list STL容器之间有什么区别?


93

两者有什么区别?我的意思是方法都一样。因此,对于用户而言,它们的工作原理相同。

那是对的吗??


1
我对迭代性能很感兴趣..从开始到结束的速度更快?
nkint 2012年

Answers:


60

从(但仍然非常有用的)SGI STL总结deque

双端队列非常类似于矢量:类似于矢量,它是一个序列,它支持对元素的随机访问,在序列末尾进行恒定时间的元素插入和删除,以及在中间对元素的线性时间插入和删除。

双端队列与向量不同的主要方式是,双端队列还支持在序列开始时恒定时间插入和删除元素。此外,双端队列没有类似于vector的Capacity()和reserve()的任何成员函数,并且不提供与那些成员函数相关的迭代器有效性的任何保证。

这是list来自同一站点的摘要:

列表是一个双向链接列表。也就是说,它是一个序列,它支持向前和向后遍历,并且在元素的开始或结尾或中间支持(分摊)常量时间插入和删除元素。列表具有重要的属性,即插入和拼接不会使迭代器失效,甚至删除也只会使指向被删除元素的迭代器无效。迭代器的顺序可以更改(也就是说,list :: iterator在列表操作之后可能具有与之前不同的前任或后继者),但是除非该无效,否则迭代器本身不会失效或指向不同的元素。或突变是明确的。

总之,容器可能具有共享的例程,但是这些例程的时间保证因容器而异。考虑到使用的这些容器的一个任务时,这是非常重要的:考虑到如何容器将使用最频繁的(例如,更比的插入/删除搜索)走一段很长的路在指导你正确的容器。


2
std :: list还具有“ splice”方法,该方法可让您将两个列表合并在一起
Rick

23
实际上,时间保证是列表的第二重要特征。list 的重要功能是可以添加和删除元素,并且不会使迭代器无效!在(几乎所有其他所有)STL容器中,每个编辑操作都会使所有迭代器无效-因此,要“删除匹配项”,您需要在一个操作中累积匹配项,然后在另一个操作中将其删除。在列表中,您可以遍历列表,根据需要删除和添加,而不必重新计算迭代器。
汤姆·史威利

1
这些也是抽象的差异,因此请根据您的情况衡量实际情况!list和deque都具有O(1)插入/删除,但是请不要忘记这意味着k * O(1),并且k具有list和deque的不同值。就我而言,将对象添加到列表的时间比双端队列要长十倍,因为列表需要更多对new / delete的调用。显然,这取决于您拥有的STL实现。
安迪·克鲁维尔

125

让我列出差异:

  • Deque使用动态数组管理其元素 ,提供随机访问,并且具有与向量几乎相同的接口。
  • List将其元素作为双链表进行管理 ,并且不提供随机访问

  • Deque在结尾和开头均提供快速插入和删除。在中间插入和删除元素相对较慢,因为直到两端为止的所有元素都可能移动以腾出空间或填补空白。
  • List中,在每个位置(包括两端)都可以快速插入和删除元素。

  • 双端队列(Deque):除开头或末尾之外的任何元素插入或删除操作都会使所有引用双端队列的元素的指针,引用和迭代器无效。
  • List:插入和删除元素不会使指向其他元素的指针,引用和迭代器无效。

复杂

             Insert/erase at the beginning       in middle        at the end

Deque:       Amortized constant                  Linear           Amortized constant
List:        Constant                            Constant         Constant

5
@aJ:constant和之间有什么区别amortized constant
Lazer

16
从长远来看,其操作如所述。但是,单个操作可能会花费比指定时间更长的时间。例如:将一个元素插入到当前容量为10并且大小已经为9的向量中,如果容量为10并且大小也为10,则时间是线性的。这是因为它必须将所有元素分配并复制到新内存中。
aJ。

5
@aJ:双端队列如何提供随机访问权限?还有该结构如何实现?

9

std::list 基本上是一个双向链表。

std::deque另一方面,实现起来更像std::vector。它具有按索引的恒定访问时间,以及在开头和结尾处的插入和删除,这提供了与列表明显不同的性能特征。


5

另一个重要的保证是每个不同容器将其数据存储在内存中的方式:

  • 向量是单个连续的存储块。
  • 双端队列是一组链接的存储块,每个存储块中存储了多个元素。
  • 列表是分散在内存中的一组元素,即:每个内存“块”仅存储一个元素。

请注意,双端队列被设计为试图平衡vector和list的优点而没有各自的缺点。在内存受限的平台(例如微控制器)中,它是一个特别有趣的容器。

内存存储策略经常被忽略,但是,它经常是为特定应用选择最合适的容器的最重要原因之一。


4

不。双端队列仅支持在正面和背面进行O(1)插入和删除。例如,它可以在带有环绕的向量中实现。由于它还保证了O(1)的随机访问,因此可以确保它没有使用(只是)双向链接列表。


2

其他人已经很好地解释了性能差异。我只是想补充一下,相似或什至相同的接口在面向对象的编程中很常见-这是编写面向对象软件的一般方法的一部分。您绝不应该仅仅因为两个类实现了相同的接口就假定两个类以相同的方式工作,而不是因为它们都实现了attack()和make_noise()而使马像狗一样工作。


1

这是列表,无序映射的概念验证代码使用,可提供O(1)查找和O(1)精确的LRU维护。需要(未擦除的)迭代器在擦除操作中生存下来。计划在O(1)任意大的软件托管的缓存中使用GPU内存上的CPU指针。向Linux O(1)调度程序点头(每个处理器的LRU <->运行队列)。unordered_map通过哈希表具有恒定的访问时间。

#include <iostream> 
#include <list> 
#include <unordered_map>  
using namespace std; 

struct MapEntry {
  list<uint64_t>::iterator LRU_entry;
  uint64_t CpuPtr;
};
typedef unordered_map<uint64_t,MapEntry> Table;
typedef list<uint64_t> FIFO;
FIFO  LRU;        // LRU list at a given priority 
Table DeviceBuffer; // Table of device buffers

void Print(void){
  for (FIFO::iterator l = LRU.begin(); l != LRU.end(); l++) {
    std::cout<< "LRU    entry "<< *l << "   :    " ;
    std::cout<< "Buffer entry "<< DeviceBuffer[*l].CpuPtr <<endl;
  }  
}
int main() 
{ 

  LRU.push_back(0);
  LRU.push_back(1);
  LRU.push_back(2);
  LRU.push_back(3);
  LRU.push_back(4);

  for (FIFO::iterator i = LRU.begin(); i != LRU.end(); i++) {
    MapEntry ME = { i, *i}; 
    DeviceBuffer[*i] = ME;
  }

  std::cout<< "************ Initial set of CpuPtrs" <<endl;
  Print();

  {
    // Suppose evict an entry - find it via "key - memory address uin64_t" and remove from 
    // cache "tag" table AND LRU list with O(1) operations
    uint64_t key=2;
    LRU.erase(DeviceBuffer[2].LRU_entry);
    DeviceBuffer.erase(2);
  }

  std::cout<< "************ Remove item 2 " <<endl;
  Print();

  { 
    // Insert a new allocation in both tag table, and LRU ordering wiith O(1) operations
    uint64_t key=9;
    LRU.push_front(key); 
    MapEntry ME = { LRU.begin(), key };
    DeviceBuffer[key]=ME;
  }

  std::cout<< "************ Add item 9  " <<endl;
  Print();

  std::cout << "Victim "<<LRU.back()<<endl;
} 

您在正确的位置张贴了吗?这不能回答问题。
高炉

1

deque和之间的显着差异list

  • 对于deque

    物品并排存放;

    优化用于从两侧(正面,背面)添加数据;

    由数字(整数)索引的元素。

    可以通过迭代器甚至元素的索引进行浏览。

    时间访问数据更快。

  • 对于 list

    项目“随机”存储在内存中;

    只能由迭代器浏览;

    优化用于中间的插入和移除。

    由于数据的空间位置非常差,因此对数据的时间访问速度较慢,迭代速度较慢。

    处理非常大的元素

您还可以检查以下链接,该链接比较两个STL容器(使用std :: vector)之间的性能。

希望我分享了一些有用的信息。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.