What's the difference between deque and list STL containers?

前端 未结 8 1546
滥情空心
滥情空心 2020-12-07 10:08

What is the difference between the two? I mean the methods are all the same. So, for a user, they work identically.

Is that correct??

相关标签:
8条回答
  • 2020-12-07 10:42

    std::list is basically a doubly linked list.

    std::deque, on the other hand, is implemented more like std::vector. It has constant access time by index, as well as insertion and removal at the beginning and end, which provides dramatically different performance characteristics than a list.

    0 讨论(0)
  • 2020-12-07 10:46

    No. A deque only supports O(1) insertion and deletion at the front and back. It may, for example, be implemented in a vector with wrap-around. Since it also guarantees O(1) random access, you can be sure it's not using (just) a doubly linked list.

    0 讨论(0)
  • 2020-12-07 10:49

    Let me list down the differences:

    • Deque manages its elements with a dynamic array, provides random access, and has almost the same interface as a vector.
    • List manages its elements as a doubly linked list and does not provide random access.

    • Deque provides Fast insertions and deletions at both the end and the beginning. Inserting and deleting elements in the middle is relatively slow because all elements up to either of both ends may be moved to make room or to fill a gap.
    • In List, inserting and removing elements is fast at each position, including both ends.

    • Deque: Any insertion or deletion of elements other than at the beginning or end invalidates all pointers, references, and iterators that refer to elements of the deque.
    • List: Inserting and deleting elements does not invalidate pointers, references, and iterators to other elements.

    Complexity

                 Insert/erase at the beginning       in middle        at the end
    
    Deque:       Amortized constant                  Linear           Amortized constant
    List:        Constant                            Constant         Constant
    
    0 讨论(0)
  • 2020-12-07 10:58

    The performance differences have been explained well by others. I just wanted to add that similar or even identical interfaces are common in object-oriented programming -- part of the general methodology of writing object-oriented software. You should IN NO WAY assume that two classes work the same way simply because they implement the same interface, any more than you should assume that a horse works like a dog because they both implement attack() and make_noise().

    0 讨论(0)
  • 2020-12-07 11:00

    Here's a proof-of-concept code use of list, unorded map that gives O(1) lookup and O(1) exact LRU maintenance. Needs the (non-erased) iterators to survive erase operations. Plan to use in a O(1) arbitrarily large software managed cache for CPU pointers on GPU memory. Nods to the Linux O(1) scheduler (LRU <-> run queue per processor). The unordered_map has constant time access via hash table.

    #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;
    } 
    
    0 讨论(0)
  • 2020-12-07 11:04

    Another important guarantee is the way each different container stores its data in memory:

    • A vector is a single contiguous memory block.
    • A deque is a set of linked memory blocks, where more than one element is stored in each memory block.
    • A list is a set of elements dispersed in memory, i.e.: only one element is stored per memory "block".

    Note that the deque was designed to try to balance the advantages of both vector and list without their respective drawbacks. It is a specially interesting container in memory limited platforms, for example, microcontrollers.

    The memory storage strategy is often overlooked, however, it is frequently one of the most important reasons to select the most suitable container for a certain application.

    0 讨论(0)
提交回复
热议问题