deque와 list STL 컨테이너의 차이점은 무엇입니까?


97

둘의 차이점은 무엇입니까? 방법은 모두 동일합니다. 따라서 사용자의 경우 동일하게 작동합니다.

그 맞습니까??


1
반복 성능에 관심이 있습니다. 시작부터 끝까지 ierate하는 것이 더 빠른 것은 무엇입니까?
nkint

답변:


61

(날짜이지만 여전히 매우 유용함) SGI STL 요약에서 deque:

데크는 벡터와 매우 유사합니다. 벡터와 마찬가지로 요소에 대한 임의 액세스, 시퀀스 끝에서 요소의 일정 시간 삽입 및 제거, 중간 요소의 선형 시간 삽입 및 제거를 지원하는 시퀀스입니다.

deque가 벡터와 다른 주된 방법은 deque가 시퀀스 시작 부분에서 요소의 상수 시간 삽입 및 제거를 지원한다는 것입니다. 또한 deque에는 벡터의 capacity () 및 reserve ()와 유사한 멤버 함수가 없으며 해당 멤버 함수와 관련된 반복기 유효성에 대한 보증을 제공하지 않습니다.

다음 list은 동일한 사이트 의 요약입니다 .

목록은 이중 연결 목록입니다. 즉, 순회 및 역 순회를 모두 지원하는 시퀀스이며 시작 또는 끝 또는 중간에 요소의 (상각) 일정 시간 삽입 및 제거를 지원합니다. 목록에는 삽입 및 스 플라이 싱으로 인해 목록 요소에 대한 반복기가 무효화되지 않으며 제거해도 제거 된 요소를 가리키는 반복자 만 무효화된다는 중요한 속성이 있습니다. 반복기의 순서는 변경 될 수 있지만 (즉, list :: iterator는 이전과 목록 작업 후 다른 선행 작업 또는 후속 작업을 가질 수 있음), 해당 무효화가 아닌 한 반복기 자체가 무효화되거나 다른 요소를 가리 키도록 만들지 않습니다. 또는 돌연변이가 명시 적입니다.

요약하면 컨테이너는 공유 루틴을 가질 수 있지만 이러한 루틴에 대한 시간 보장은 컨테이너마다 다릅니다 . 이는 작업에 사용할 컨테이너를 고려할 때 매우 중요 합니다 . 컨테이너가 가장 자주 사용되는 방식 (예 : 삽입 / 삭제보다 검색에 더 많이 사용)을 고려하면 올바른 컨테이너로 안내하는 데 큰 도움이됩니다. .


2
std :: list에는 또한 두 개의 목록을 병합 할 수있는 'splice'방법이 있습니다
Rick

25
실제로 시간 보장은 목록 에서 두 번째 로 중요한 기능입니다. 목록 의 가장 중요한 기능은 요소를 추가 및 제거하고 반복자를 무효화하지 않을 수 있다는 것입니다! (거의?) 다른 모든 STL 컨테이너에서 모든 편집 작업은 모든 반복자를 무효화하므로 "일치하는 항목을 삭제"하려면 한 작업에서 일치하는 항목을 누적 한 다음 다른 작업에서 삭제해야합니다. 목록에서 목록을 살펴보고 원하는대로 제거 및 추가 할 수 있으며 반복기를 다시 계산할 필요가 없습니다.
Tom Swirly 2012

2
이것들은 또한 추상적 인 차이점이므로 귀하의 경우에 대한 현실을 측정하십시오! list와 deque에는 모두 O (1) 삽입 / 삭제가 있지만 k * O (1)를 의미한다는 것을 잊지 마십시오. k는 list와 deque에 대해 다른 값을가집니다. 제 경우에는 목록에 new / delete에 대한 더 많은 호출이 필요했기 때문에 deque보다 목록에 개체를 추가하는 데 10 배 더 오래 걸렸습니다. 그것은 당신이 가지고있는 STL 구현에 따라 분명히 달라질 것입니다.
앤디 Krouwel

130

차이점을 나열하겠습니다.

  • Deque동적 배열로 요소를 관리하고 임의 액세스를 제공 하며 벡터와 거의 동일한 인터페이스를 가지고 있습니다.
  • List 는 요소를 이중 연결 목록 으로 관리하며 임의 액세스를 제공하지 않습니다 .

  • Deque 는 끝과 시작 모두에서 빠른 삽입 및 삭제를 제공합니다. 공간을 확보하거나 간격을 채우기 위해 양쪽 끝 중 하나까지 모든 요소를 ​​이동할 수 있기 때문에 중간에 요소를 삽입하고 삭제하는 것은 상대적으로 느립니다.
  • 에서는 목록 삽입 및 요소를 제거하는 단계를 포함하여 각각의 양단부 위치에서 빠르다.

  • Deque : 시작 또는 끝 부분 이외의 요소 삽입 또는 삭제는 deque의 요소를 참조하는 모든 포인터, 참조 및 반복자를 무효화합니다.
  • 목록 : 요소 삽입 및 삭제는 다른 요소에 대한 포인터, 참조 및 반복기를 무효화하지 않습니다.

복잡성

             Insert/erase at the beginning       in middle        at the end

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

6
@aJ : constant과 의 차이점은 무엇입니까 amortized constant?
Lazer 2010-04-15

17
장기적인 작업은 설명 된대로 작동합니다. 그러나 단일 작업은 지정된 것보다 오래 걸릴 수 있습니다. 예 : 현재 용량이 10이고 크기가 이미 9 인 벡터에 요소를 삽입하는 경우 용량이 10이고 크기도 10이면 시간이 선형이므로 모든 요소를 ​​새 메모리에 할당하고 복사해야하기 때문입니다. .
aJ.

5
@aJ : deque는 랜덤 액세스를 어떻게 제공합니까? 또한이 구조는 어떻게 구현됩니까?

9

std::list 기본적으로 이중 연결 목록입니다.

std::deque반면에는 std::vector. 색인 별 액세스 시간이 일정하고 시작과 끝 부분의 삽입 및 제거가있어 목록과는 매우 다른 성능 특성을 제공합니다.


5

또 다른 중요한 보장은 각 컨테이너가 메모리에 데이터를 저장하는 방식입니다.

  • 벡터는 연속 된 단일 메모리 블록입니다.
  • 데크는 연결된 메모리 블록의 집합으로, 각 메모리 블록에 둘 이상의 요소가 저장됩니다.
  • 목록은 메모리에 분산 된 요소 집합입니다. 즉, 메모리 "블록"당 하나의 요소 만 저장됩니다.

deque는 벡터와 목록의 장점을 각각의 단점없이 균형 맞추기 위해 설계되었습니다 . 마이크로 컨트롤러와 같이 메모리 제한 플랫폼에서 특히 흥미로운 컨테이너입니다.

메모리 저장 전략은 종종 간과되지만 특정 애플리케이션에 가장 적합한 컨테이너를 선택하는 가장 중요한 이유 중 하나입니다.


4

아니요. deque는 앞뒤에 O (1) 삽입 및 삭제 만 지원합니다. 예를 들어, 랩 어라운드가있는 벡터에서 구현 될 수 있습니다. 또한 O (1) 임의 액세스를 보장하기 때문에 이중 연결 목록을 사용하고 있지 않은지 확인할 수 있습니다.


2

성능 차이는 다른 사람들이 잘 설명했습니다. 객체 지향 소프트웨어를 작성하는 일반적인 방법론의 일부인 객체 지향 프로그래밍에서 유사하거나 동일한 인터페이스가 일반적이라는 점을 추가하고 싶었습니다. 두 클래스가 동일한 인터페이스를 구현하기 때문에 단순히 동일한 방식으로 작동한다고 가정해서는 안됩니다. 둘 다 attack () 및 make_noise ()를 구현하기 때문에 말이 개처럼 작동한다고 가정해야합니다.


1

다음은 O (1) 조회 및 O (1) 정확한 LRU 유지 관리를 제공하는 목록, unorded 맵의 개념 증명 코드 사용입니다. 지우기 작업에서 살아남 으려면 (지워지지 않은) 반복기가 필요합니다. GPU 메모리의 CPU 포인터에 대해 O (1) 임의로 큰 소프트웨어 관리 캐시에서 사용하도록 계획하십시오. Linux O (1) 스케줄러 (프로세서 당 LRU <-> 실행 큐)를 끄덕입니다. 무순 맵은 해시 테이블을 통해 일정 시간 액세스가 가능합니다.

#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;
} 

올바른 위치에 게시 했습니까? 이것은 질문에 대한 답이 아닙니다.
Blastfurnace

1

사이의 저명한 차이 중 dequelist

  • 대상 deque:

    나란히 보관 된 항목;

    양면 (전면, 후면)에서 데이터를 추가하는 데 최적화되었습니다.

    숫자로 인덱싱 된 요소 (정수).

    반복자 및 요소의 인덱스로 찾아 볼 수 있습니다.

    데이터 액세스 시간이 더 빠릅니다.

  • 에 대한 list

    메모리에 "무작위로"저장된 항목

    반복자 만 찾아 볼 수 있습니다.

    중간 삽입 및 제거에 최적화되었습니다.

    데이터에 대한 액세스 시간은 매우 열악한 공간적 지역성으로 인해 느리고 반복 속도가 느립니다.

    매우 큰 요소를 잘 처리합니다.

두 STL 컨테이너 (std :: vector 사용) 간의 성능을 비교 하는 다음 Link 도 확인할 수 있습니다.

유용한 정보를 공유하기를 바랍니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.