STL의 디크 란 무엇입니까?


194

나는 STL 컨테이너를보고 그들이 실제로 무엇인지 파악하려고 노력했다. (즉, 사용 된 데이터 구조) deque 는 나를 막았다. 일정한 시간이지만, 나는 연산자 []가 일정한 시간에 행해야 한다는 약속에 어려움을 겪고 있습니다. 연결된 목록에서 임의 액세스는 O (n)이어야합니다.

동적 배열이라면 어떻게 일정한 시간 에 요소추가 할 수 있습니까? 재 할당이 발생할 수 있으며 O (1)은 벡터와 같이 상각 된 비용이라는 점을 언급해야합니다 .

그래서 일정한 시간에 임의의 액세스를 허용하는이 구조가 무엇인지 궁금해하며 동시에 더 큰 새로운 장소로 옮길 필요가 없습니다.



1
@Graham“dequeue”는“deque”의 또 다른 일반적인 이름입니다. “deque”가 일반적으로 표준 이름이므로 편집을 승인했습니다.
Konrad Rudolph 2016 년

@ Konrad 감사합니다. 문제는 더 짧은 철자를 사용하는 C ++ STL deque에 관한 것입니다.
Graham Borland

2
deque의미 분명히 O의 엄격한 요구 사항이 중간 요소 (1) 액세스는 C ++에 특히 비록,
마티유 M.

답변:


186

양단 큐는 다소 재귀 적 정의이다 : 내부적으로는의 덱 유지 덩어리 고정 된 크기를. 각 청크는 벡터이며 청크 자체의 큐 (아래 그림에서 "맵")도 벡터입니다.

deque의 메모리 레이아웃의 개략도

이 성능 특성의 좋은 분석입니다 그리고 그것은 비교하는 방법 vector에 이상 CodeProject의 .

GCC 표준 라이브러리 구현은 내부적으로 a T**를 사용 하여 맵을 나타냅니다. 각 데이터 블록은 T*일정한 크기로 할당됩니다 __deque_buf_size(에 따라 다름 sizeof(T)).


28
그것이 내가 배운 데로 deque의 정의이지만, 이런 식으로 지속적인 시간 액세스를 보장 할 수 없으므로 누락 된 것이 있어야합니다.
stefaanv 2016 년

14
@stefaanv, @Konrad : C ++ 구현 고정 크기 배열에 대한 포인터 배열을 사용했습니다. 이것은 실제로 push_front와 push_back이 실제로 일정하지는 않지만 똑똑한 성장 요소를 사용하면 여전히 일정 시간을 상각 할 수 있으므로 O (1)은 잘못되지 않으며 실제로는 스와핑 때문에 벡터보다 빠릅니다. 전체 객체가 아닌 단일 포인터 (그리고 객체보다 포인터가 적음).
Matthieu M.

5
지속적인 액세스가 여전히 가능합니다. 정면에 새 블록을 할당해야하는 경우 기본 벡터에서 새 포인터를 뒤로 밀고 모든 포인터를 이동하십시오.
Xeo

4
지도 (대기열 자체)가 이중 종단 목록 인 경우 O (1) 무작위 액세스를 허용하는 방법을 알 수 없습니다. 순환 버퍼로 구현되어 순환 버퍼 크기 조정의 효율성을 높일 수 있습니다. 큐의 모든 요소 대신 포인터 만 복사하십시오. 여전히 그것은 작은 이익 인 것 같습니다.
Wernight

15
@JeremyWest 왜 안돼? 인덱스 된 액세스는 i / B 번째 블록의 i % B 번째 요소 (B = 블록 크기)로 이동합니다. 이는 분명히 O (1)입니다. 상각 된 O (1)에 새 블록을 추가 할 수 있으므로 마지막에 요소를 추가하면 O (1)이 상각됩니다. 새로운 블록을 추가 할 필요가없는 한 처음에 새로운 요소를 추가하는 것은 O (1)입니다. 처음에 새로운 블록을 추가하는 것은 O (1)이 아니며, 사실 O (N)이지만 실제로는 N 요소가 아닌 N / B 포인터 만 이동하면되기 때문에 상수 계수가 매우 작습니다.
Konrad Rudolph

22

벡터로 구성된 벡터라고 상상해보십시오. 그들은 표준이 아닙니다 std::vector.

외부 벡터는 내부 벡터에 대한 포인터를 포함합니다. 모든 빈 공간을 끝에 할당하는 대신 재 할당을 통해 용량을 변경 std::vector하면 빈 공간이 벡터의 시작과 끝에서 동일한 부분으로 분할됩니다. 이렇게 허용 push_frontpush_back양쪽이 벡터 상각 O (1) 시간에 발생한다.

내부 벡터 동작은 전면 또는 후면에 따라 변경되어야합니다 deque. 뒷면 std::vector에서는 끝에서 자라며 push_backO (1) 시간에 발생 하는 표준으로 작동 할 수 있습니다 . 앞에서는 반대로 시작해야합니다 push_front. 실제로 이것은 전면 요소에 대한 포인터와 크기와 함께 성장 방향을 추가하여 쉽게 달성됩니다. 이 간단한 수정 push_front으로 O (1) 시간 이 될 수도 있습니다.

모든 요소에 액세스하려면 O (1)에서 발생하는 적절한 외부 벡터 인덱스로 오프셋하고 나누고 O (1) 인 내부 벡터로 인덱싱해야합니다. 이것은 내부 벡터가의 시작 또는 끝에있는 것을 제외한 모든 고정 크기라고 가정합니다 deque.


1
내부 벡터는 고정 용량
Caleth

18

deque = 더블 엔드 큐

어느 방향 으로든 성장할 수있는 용기.

양단이되는 전형적 A와 구현 vectorvectors(일정한 시간을 랜덤 액세스를 제공 할 수없는 벡터의리스트). 2 차 벡터의 크기는 구현에 따라 다르지만 일반적인 알고리즘은 바이트 단위로 일정한 크기를 사용하는 것입니다.


6
아니고 아주 내부적으로 벡터. 내부 구조는 처음 과 끝 에서 할당되었지만 사용되지 않은 용량을 할당 할 수 있습니다.
Mooing Duck

@MooingDuck : 실제로 정의 된 구현이며, 배열 또는 벡터로 구성된 벡터 또는 표준에 의해 규정 된 동작 및 복잡성을 제공 할 수있는 모든 것이 될 수 있습니다.
Alok 저장

1
@ Als : 나는 array아무것도 생각하지 않거나 vector상각 된 O(1)push_front를 약속 할 수있는 것은 없습니다 . 두 구조의 내부는 최소한 push_front 를 가질 수 있어야 하며 O(1), 이는 어느 것도 보장 할 수 array없습니다 vector.
Mooing Duck

4
@MooingDuck 첫 번째 청크가 상향식이 아닌 하향식으로 커지면 요구 사항을 쉽게 충족 할 수 있습니다. 분명히 표준 vector은 그렇게하지 않지만 그렇게하기에 충분히 간단합니다.
Mark Ransom

3
@ Mooing Duck, push_front와 push_back은 단일 벡터 구조로 상각 된 O (1)에서 쉽게 수행 할 수 있습니다. 그것은 원형 버퍼를 조금 더 많이 유지하는 것입니다. 0에서 99까지의 위치에 100 개의 요소를 가진 용량 1000의 정규 벡터가 있다고 가정합니다. 이제 push_Front가 발생하면 끝 (예 : 위치 999, 998 등)에서 두 끝이 만나기 전까지 만 누르면됩니다. 그런 다음 평범한 벡터를 사용하는 것처럼 암모 세트 상수를 보장하기 위해 지수 성장으로 재 할당합니다. 따라서 효과적으로 첫 번째 엘에 대한 하나의 추가 포인터가 필요합니다.
plamenko

14

(이것은 내가 다른 스레드 에서 제공 한 답변 입니다. 본질적으로 단일을 사용하는 상당히 순진한 구현조차도 vector"일정하지 않은 푸시 푸시 {{front, back}"의 요구 사항을 준수 한다고 주장하고 있습니다. , 이것이 불가능하다고 생각하지만, 놀라운 맥락에서 문맥을 정의하는 다른 관련 인용문을 발견했습니다. 내가 참아주세요.이 답변에서 실수를 한 경우 어떤 것을 식별하는 것이 매우 도움이 될 것입니다 나는 정확하게 그리고 내 논리가 무너진 곳이라고 말했다.)

이 답변에서 나는 좋은 구현 을 식별하려고하지 않고 C ++ 표준의 복잡성 요구 사항을 해석하는 데 도움을 주려고합니다. Wikipedia 에 따르면 무료로 제공되는 최신 C ++ 11 표준화 문서 인 N3242 에서 인용하고 있습니다. (최종 표준과 다르게 구성 된 것으로 보이므로 정확한 페이지 번호를 인용하지는 않습니다. 물론 이러한 표준은 최종 표준에서 변경되었을 수도 있지만 실제로는 그렇게 생각하지 않습니다.)

deque<T>를 사용하여 A를 올바르게 구현할 수 있습니다 vector<T*>. 모든 요소는 힙에 복사되고 포인터는 벡터에 저장됩니다. (나중에 벡터에 더).

T*대신에 T? 표준에 따라

"deque의 양쪽 끝에 삽입하면 deque에 대한 모든 반복자가 무효화되지만 deque의 요소에 대한 참조의 유효성에는 영향을 미치지 않습니다. "

(내 강조). T*그것을 만족시키는 데 도움 이 됩니다. 또한이를 충족시키는 데 도움이됩니다.

"deque의 시작 또는 끝에 단일 요소를 삽입하면 항상 ..... T 생성자에 대한 단일 호출이 발생합니다 ."

이제 논란의 여지가 있습니다. 를 사용 vector하여 저장하는 이유 는 T*무엇입니까? 그것은 우리에게 랜덤 액세스를 제공합니다. 잠시 동안 벡터의 복잡성을 잊어 버리고이를 신중하게 만들어 봅시다.

표준은 "포함 된 개체에 대한 작업 수"에 대해 설명합니다. 들어 deque::push_front이 명확 1 정확히 하나 때문에 T개체가 구성되어 기존의 제로 T개체를 읽거나 어떤 방식으로 스캔됩니다. 이 숫자 1은 분명히 상수이며 현재 deque에있는 오브젝트 수와 무관합니다. 이를 통해 다음과 같이 말할 수 있습니다.

'우리의 deque::push_front경우 포함 된 개체 (Ts)에 대한 작업 수는 고정되어 있으며 이미 deque에있는 개체 수와 무관합니다.'

물론, 작업 수는 T*그다지 잘 작동하지 않습니다. (가) 때 vector<T*>너무 큰 성장, 그것은 realloced됩니다 많은 T*들 주위에 복사됩니다. 예,의 작업 수는 T*크게 다르지만 작업 수에는 T영향을 미치지 않습니다.

계산 작업 T과 계산 작업의 차이점을 왜 걱정해야 T*합니까? 표준에 따르면 다음과 같습니다.

이 절의 모든 복잡성 요구 사항은 포함 된 개체에 대한 작업 수로 만 명시됩니다.

를 들어 deque, 포함 된 개체가있는 T아닌 T*, 우리가 어떤 동작을 무시할 수 의미있는 사본 (또는 reallocs)가 T*.

나는 벡터가 deque에서 어떻게 작동하는지에 대해서는별로 말하지 않았다. 아마도 우리는 그것을 원형 버퍼로 해석 할 것입니다 (벡터는 항상 최대 값을 차지하고 capacity()벡터가 가득 찼을 때 모든 것을 더 큰 버퍼로 재 할당합니다) 세부 사항은 중요하지 않습니다.

마지막 몇 단락에서, 우리는 deque::push_front이미 deque에있는 객체 수와 포함 된 객체에 대해 push_front에 의해 수행 된 작업 수 사이의 관계를 분석 T했습니다. 그리고 우리는 그들이 서로 독립적이라는 것을 알았습니다. 표준은 복잡성이 운영시 측면에서 의무화됨에 따라 복잡성이 T일정하다고 말할 수있다.

예. Operations-On-T * -Complexity 는 (로 인해) 상각 vector되지만, 우리는 Operations-On-T-Complexity 에만 관심 이 있으며 이는 일정합니다 (비 암호화).

vector :: push_back 또는 vector :: push_front의 복잡성은이 구현과 관련이 없습니다. 이러한 고려 사항에는 작업이 포함 T*되므로 관련이 없습니다. 표준이 복잡성에 대한 '전통적인'이론적 개념을 언급하고 있다면, "포함 된 객체에 대한 작업 수"로 명시 적으로 제한되지 않았을 것입니다. 그 문장을 과도하게 해석하고 있습니까?


8
나 한테 바람 피우는 것 같아! 작업의 복잡성을 지정하는 경우 데이터의 일부에서만 수행하지 않습니다. 작동하는 작업에 관계없이 호출중인 작업의 예상 런타임에 대한 정보를 원합니다. T에 대한 작업에 대한 논리를 따르면 작업을 수행 할 때마다 각 T *의 값이 소수인지 확인하고 T를 터치하지 않기 때문에 여전히 표준을 준수하는지 확인할 수 있습니다. 따옴표가 나오는 곳을 지정할 수 있습니까?
Zonko

2
표준 작성자는 예를 들어 메모리 할당의 복잡성과 같이 완전히 지정된 시스템이 없기 때문에 기존 복잡도 이론을 사용할 수 없다는 것을 알고 있습니다. list목록의 현재 크기에 관계없이 메모리의 새 멤버에 대해 메모리를 할당 할 수 있다고 가정하는 것은 현실적이지 않습니다 . 목록이 너무 크면 할당이 느리거나 실패합니다. 따라서 내가 알 수있는 한,위원회는 객관적으로 계산하고 측정 할 수있는 작업 만 지정하기로 결정했습니다. (PS : 나는 또 다른 답을 위해 이것에 대한 또 다른 이론을 가지고 있습니다 .)
Aaron McDaid

나는 확실하게 O(n)작업의 수가 요소 수에 무의식적으로 비례한다는 것을 의미합니다. IE, 메타 작업이 중요합니다. 그렇지 않으면 조회를로 제한하는 것은 의미가 없습니다 O(1). Ergo, 링크리스트는 자격이 없습니다.
Mooing Duck

8
이것은 매우 흥미로운 해석이지만이 논리에 의해 포인터 list로 구현 될 수도 있습니다 vector(중간에 삽입하면 목록 크기에 관계없이 단일 사본 생성자 호출 O(N)이 발생하고 포인터 의 셔플 링은 무시 될 수 있음). T 작업이 아닙니다).
Mankarse

1
이것은 훌륭한 언어 변호사입니다 (실제로 정확한지 또는이 구현을 금지하는 표준에 약간의 미묘한 점이 있는지는 언급하려고하지는 않지만). 그러나 (1) 일반적인 구현은 deque이러한 방식으로 구현되지 않으며 (2) 알고리즘 복잡성 계산이 효율적인 프로그램 작성에 도움이되지 않을 때 (표준에서 허용하는 경우에도) 이러한 방식으로 "속임수"가 되기 때문에 실제로 유용한 정보 는 아닙니다. .
Kyle Strand

13

개요에서, 당신은 생각할 수있는 dequeA와double-ended queue

데크 개요

데이터 deque는 고정 크기 벡터의 청크에 의해 저장됩니다.

로 가리키는 map(벡터 덩어리이기도하지만 크기가 변경 될 수 있음)

내부 구조를 deque

의 주요 부품 코드는 다음 deque iterator과 같습니다.

/*
buff_size is the length of the chunk
*/
template <class T, size_t buff_size>
struct __deque_iterator{
    typedef __deque_iterator<T, buff_size>              iterator;
    typedef T**                                         map_pointer;

    // pointer to the chunk
    T* cur;       
    T* first;     // the begin of the chunk
    T* last;      // the end of the chunk

    //because the pointer may skip to other chunk
    //so this pointer to the map
    map_pointer node;    // pointer to the map
}

의 주요 부품 코드는 다음 deque과 같습니다.

/*
buff_size is the length of the chunk
*/
template<typename T, size_t buff_size = 0>
class deque{
    public:
        typedef T              value_type;
        typedef T&            reference;
        typedef T*            pointer;
        typedef __deque_iterator<T, buff_size> iterator;

        typedef size_t        size_type;
        typedef ptrdiff_t     difference_type;

    protected:
        typedef pointer*      map_pointer;

        // allocate memory for the chunk 
        typedef allocator<value_type> dataAllocator;

        // allocate memory for map 
        typedef allocator<pointer>    mapAllocator;

    private:
        //data members

        iterator start;
        iterator finish;

        map_pointer map;
        size_type   map_size;
}

아래 deque에서는 주로 세 부분으로 된 핵심 코드를 제공합니다 .

  1. 반복자

  2. 구성하는 방법 deque

1. 반복자 ( __deque_iterator)

반복자의 주요 문제는 ++ 일 때-반복자가 다른 청크로 건너 뛸 수 있다는 것입니다 (청크의 가장자리를 가리키는 경우). 예를 들어, 세 개의 데이터 청크가 : chunk 1, chunk 2, chunk 3.

pointer1받는 포인터의 시작 chunk 2때 연산자 --pointer는 말에 포인터 것이다 chunk 1그래서에 관해서 pointer2.

여기에 이미지 설명을 입력하십시오

아래에서는 주요 기능을 제공합니다 __deque_iterator.

먼저 덩어리로 건너 뜁니다.

void set_node(map_pointer new_node){
    node = new_node;
    first = *new_node;
    last = first + chunk_size();
}

chunk_size()청크 크기를 계산 하는 함수는 단순화를 위해 8을 반환한다고 생각할 수 있습니다.

operator* 청크로 데이터를 얻다

reference operator*()const{
    return *cur;
}

operator++, --

// 증분 형태의 접두사

self& operator++(){
    ++cur;
    if (cur == last){      //if it reach the end of the chunk
        set_node(node + 1);//skip to the next chunk
        cur = first;
    }
    return *this;
}

// postfix forms of increment
self operator++(int){
    self tmp = *this;
    ++*this;//invoke prefix ++
    return tmp;
}
self& operator--(){
    if(cur == first){      // if it pointer to the begin of the chunk
        set_node(node - 1);//skip to the prev chunk
        cur = last;
    }
    --cur;
    return *this;
}

self operator--(int){
    self tmp = *this;
    --*this;
    return tmp;
}
반복자 건너 뛰기 n 단계 / 임의 액세스
self& operator+=(difference_type n){ // n can be postive or negative
    difference_type offset = n + (cur - first);
    if(offset >=0 && offset < difference_type(buffer_size())){
        // in the same chunk
        cur += n;
    }else{//not in the same chunk
        difference_type node_offset;
        if (offset > 0){
            node_offset = offset / difference_type(chunk_size());
        }else{
            node_offset = -((-offset - 1) / difference_type(chunk_size())) - 1 ;
        }
        // skip to the new chunk
        set_node(node + node_offset);
        // set new cur
        cur = first + (offset - node_offset * chunk_size());
    }

    return *this;
}

// skip n steps
self operator+(difference_type n)const{
    self tmp = *this;
    return tmp+= n; //reuse  operator +=
}

self& operator-=(difference_type n){
    return *this += -n; //reuse operator +=
}

self operator-(difference_type n)const{
    self tmp = *this;
    return tmp -= n; //reuse operator +=
}

// random access (iterator can skip n steps)
// invoke operator + ,operator *
reference operator[](difference_type n)const{
    return *(*this + n);
}

2. 건설 방법 deque

공통 기능 deque

iterator begin(){return start;}
iterator end(){return finish;}

reference front(){
    //invoke __deque_iterator operator*
    // return start's member *cur
    return *start;
}

reference back(){
    // cna't use *finish
    iterator tmp = finish;
    --tmp; 
    return *tmp; //return finish's  *cur
}

reference operator[](size_type n){
    //random access, use __deque_iterator operator[]
    return start[n];
}


template<typename T, size_t buff_size>
deque<T, buff_size>::deque(size_t n, const value_type& value){
    fill_initialize(n, value);
}

template<typename T, size_t buff_size>
void deque<T, buff_size>::fill_initialize(size_t n, const value_type& value){
    // allocate memory for map and chunk
    // initialize pointer
    create_map_and_nodes(n);

    // initialize value for the chunks
    for (map_pointer cur = start.node; cur < finish.node; ++cur) {
        initialized_fill_n(*cur, chunk_size(), value);
    }

    // the end chunk may have space node, which don't need have initialize value
    initialized_fill_n(finish.first, finish.cur - finish.first, value);
}

template<typename T, size_t buff_size>
void deque<T, buff_size>::create_map_and_nodes(size_t num_elements){
    // the needed map node = (elements nums / chunk length) + 1
    size_type num_nodes = num_elements / chunk_size() + 1;

    // map node num。min num is  8 ,max num is "needed size + 2"
    map_size = std::max(8, num_nodes + 2);
    // allocate map array
    map = mapAllocator::allocate(map_size);

    // tmp_start,tmp_finish poniters to the center range of map
    map_pointer tmp_start  = map + (map_size - num_nodes) / 2;
    map_pointer tmp_finish = tmp_start + num_nodes - 1;

    // allocate memory for the chunk pointered by map node
    for (map_pointer cur = tmp_start; cur <= tmp_finish; ++cur) {
        *cur = dataAllocator::allocate(chunk_size());
    }

    // set start and end iterator
    start.set_node(tmp_start);
    start.cur = start.first;

    finish.set_node(tmp_finish);
    finish.cur = finish.first + num_elements % chunk_size();
}

청크 크기가 8 인 i_deque20 개의 int 요소 0~19가 있고 이제 3 개의 요소 (0, 1, 2)를 i_deque다음 과 같이 push_back 한다고 가정 합니다 .

i_deque.push_back(0);
i_deque.push_back(1);
i_deque.push_back(2);

아래와 같은 내부 구조입니다.

여기에 이미지 설명을 입력하십시오

그런 다음 push_back을 다시 할당하면 새 청크 할당이 호출됩니다.

push_back(3)

여기에 이미지 설명을 입력하십시오

만약 우리 push_front가 prev 이전에 새로운 덩어리를 할당 할 것이다.start

여기에 이미지 설명을 입력하십시오

참고 push_back지도 및 청크 모두 채워진 경우 양단 큐에 요소, 그것은 새로운 맵을 할당 원인이, 당신이 이해하기 위의 코드가 충분히있을 수 있습니다 chunks.But을 조정합니다 deque.


"push_back 요소를 deque로 넣을 때 모든 맵과 청크가 채워지면 새 맵이 할당되고 청크가 조정됩니다." N4713에서 C ++ 표준이 "[26.3.8.4.3] deque의 시작 또는 끝에 단일 요소를 삽입하는 데 항상 일정한 시간이 걸리는 이유"가 궁금합니다. 데이터 척을 할당하는 데 일정 시간 이상이 걸립니다. 아니?
HCSF

7

Adam Drozdek가 "C ++의 데이터 구조 및 알고리즘"을 읽고 있는데 이것이 유용하다는 것을 알았습니다. HTH.

STL deque의 매우 흥미로운 측면은 구현입니다. STL deque는 링크 된 목록으로 구현되지 않고 데이터 블록 또는 배열에 대한 포인터 배열로 구현됩니다. 스토리지 수에 따라 블록 수가 동적으로 변경되고 그에 따라 포인터 배열의 크기가 변경됩니다.

가운데에는 데이터에 대한 포인터 배열 (오른쪽에 청크)이 있음을 알 수 있으며 가운데의 배열이 동적으로 변경되고 있음을 알 수 있습니다.

이미지는 천 단어의 가치가 있습니다.

여기에 이미지 설명을 입력하십시오


1
책을 추천 해 주셔서 감사합니다. 나는 그 deque부분을 읽고 꽤 좋다.
Rick

@ 좋아요. O (1)에서 어떻게 랜덤 액세스 ([] operator)를 가질 수 있는지 이해할 수 없기 때문에 어느 시점에서 deque를 파고 들었던 기억이납니다. 또한 (푸시 / 팝) _ (백 / 프런트)가 O (1) 복잡성을 상각했음을 증명하는 것은 흥미로운 '아하 모멘트'입니다.
Keloo

6

표준은 특정 구현 (일정 시간 랜덤 액세스 만)을 요구하지 않지만, 일반적으로 deque는 연속 메모리 "페이지"모음으로 구현됩니다. 필요에 따라 새 페이지가 할당되지만 여전히 임의 액세스 권한이 있습니다. 와 달리 std::vector데이터가 연속적으로 저장된다고 약속하지는 않지만 벡터와 같이 중간에 삽입하려면 많은 재배치가 필요합니다.


4
또는 중간에 삭제하려면 많은 재배치가 필요합니다
Mark Hendrickson

경우 insert재배치를 많이 필요로 실험을 4 않습니다 어떻게 여기가 보여 엄청난 차이 vector::insert()deque::insert()?
Bula

1
@ 불라 : 아마도 세부 사항의 잘못된 통신으로 인해? 데크 인서트의 복잡성은 "삽입 된 요소 수에 선형을 더하고 데크의 시작과 끝까지의 거리를 줄입니다". 이 비용을 느끼려면 현재 중간에 삽입해야합니다. 벤치 마크가하는 일입니까?
Kerrek SB

@ KerrekSB : 벤치 마크가있는 기사는 위 Konrad 답변에서 참조되었습니다. 실제로 아래 기사의 의견 섹션을 보지 못했습니다. 스레드에서 '하지만 deque에 선형 삽입 시간이 있습니까?' 저자는 모든 테스트를 통해 위치 100에서 삽입을 사용하여 결과를 좀 더 이해하기 쉽게했다고 언급했습니다.
Bula
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.