🧠 CS/자료구조
[자료구조] C++ Container Library : Sequential Containers - deque
청월누리
2025. 4. 27. 15:47
C++ 표준 라이브러리(STL)의 일부인 컨테이너 라이브러리 중 순차 컨테이너(Sequeential Containers)에 해당하는 std::deque
에 대해 정리한 글입니다.
📚 std::deque
📖 std::deque
- Double Ended Queue
- 앞쪽(Front)과 뒤쪽(Back) 둘 다 빠르게 삽입 및 삭제할 수 있는 자료 구조
➡️ vector처럼 메모리가 연속적이지는 않지만, 양쪽 끝 삽입 및 삭제가 $ O(1) $ 성능을 가지는 컨테이너
📌 std::deque
사용 예시 코드
#include <iostream>
#include <deque> // 필수 헤더
using namespace std;
int main() {
deque<int> dq; // 덱 생성
dq.push_back(1); // 뒤에 추가
dq.push_front(0); // 앞에 추가
dq.push_back(2); // 뒤에 추가
dq.pop_front(); // 앞에 하나 제거 (0 제거)
// 출력 (임의 접근)
for (size_t i = 0; i < dq.size(); ++i) {
cout << dq[i] << " "; // Random Access 가능
}
return 0;
}
<deque>
헤더를 추가하여 사용 가능- 인덱스를 이용한 임의 접근(Random Access) 가능
📖 std::vector
vs std::deque
구분 | vector |
deque |
메모리 구조 | 완전 연속적인 메모리 | 블록(block) 배열 |
끝 삽입 및 삭제 | 빠름 $ O(1) $ | 빠름 $ O(1) $ |
앞 삽입 및 삭제 | 느림 $ O(N) $ | 빠름 $ O(1) $ |
중간 삽입 및 삭제 | 느림 $ O(N) $ | 느림 $ O(N) $ |
임의 접근 | 빠름 $ O(1) $ | 빠름 $ O(1) $ ➡️ block map 계산 |
✅ deque는 앞 뒤 둘다 바르게 삽입 및 삭제할 수 있다.
✅ vector와 달리 메모리가 완전 연속적인 것은 아니다.
📖 std::deque
의 내부 구조
- deque은 거대한 배열 하나로 이루어진 구조가 아닌, 여러 개의 고정 크기 배열(블록)을 연결한 구조
- 각 블록들은 포인터 배열(
map
)로 관리 - 필요할 때 블록을 새로 추가하면서 양쪽 끝에 삽입 및 삭제 ➡️ vector는 할당된 공간이 모두 차면 배열을 통째로 새롭게 할당하는 반면, deque는 새로운 버퍼를 추가하면 되기 때문에 데이터 삽입은 항상 $ O(1) $ 시간이 소요
컴포넌트 | 설명 |
map |
블록들의 포인터를 저장하는 배열 |
block |
실제 데이터가 저장된 고정 크기 배열 |
start |
첫 번째 원소가 들어있는 블록과 그 인덱스 |
finish |
마지막 원소가 들어있는 블록과 그 인덱스 |
📌 std::vector vs std::deque 내부 구조 비교
vector | deque |
✅ start , finish , end_of_stroage 3개의 포인터로 관리 |
✅ start (block + index), finish (block + index), map (block array)로 관리 |
📌 블록(block) 크기
- 일반적으로 한 블록은 수십 개의 원소를 저장할 수 있도록 크기가 정해짐 ➡️ 정확한 블록의 크기는 구현체마다 다를 수 있음
- 대략 512 byte ~ 4 KB 정도 되는 블록을 많이 사용
📖 std::deque의 시간 복잡도
push_back()
/push_front()
: $ O(1) $pop_back()
/pop_front()
: $ O(1) $operator[]
,at()
접근 : $ O(1) $- 중간 삽입 및 삭제 : $ O(N) $
📖 deque의 주요 함수
push_front(val)
/push_back(val)
: 맹 앞 / 맨 뒤 원소(val
) 추가pop_back()
/pop_front()
: 맨 앞 / 맨 뒤 원소 제거operator[pos]
/at(pos)
: 임의 위치(pos
)의 원소 접근insert(pos, val)
: 해당 인덱스(pos
)에 원소(val
) 삽입erase(pos)
: 해당 인덱스(pos
)의 원소 제거
📖 deque 사용 시 주의할 점
- 메모리가 완전 연속적이지 않음
- 포인터 연산을 vector와 같이 사용하면 안됨
- iterator만 안전하게 사용해야 함
iterator
iterator는 컨테이너 내부 데이터를 가리키는 포인터 비슷한 개념
단순히 인덱스 접근이 아니라, 컨테이너 구조에 맞게 앞으로 가기 또는 뒤로 가기 기능을 제공하는 객체
- 중간 삽입 및 삭제는 vector와 동일하게 시간이 많이 소요됨
- 매우 많은 수의
push_front
와push_back
이 있을 때 성능이 좋음
📌 vector와 deque 선택 기준
- deque이 vector보다 대부분의 상황에서 유리하게 보일 수 있지만, deque은 메모리 연속성을 보장할 수 없음 ➡️ C 배열의 라이브러리와 상호작용을 하거나, 공간지역성을 고려해야 하는 경우 deque이 불리함
- 주로 뒤쪽에서만 원소 추가 및 삭제가 이루어짐 ➡️ vector 사용
- 앞과 뒤 모두 자주 원소 추가 및 삭제가 이루어짐 ➡️ deque 사용
- 메모리 연속성이 보장되어야 함 ➡️ vector 사용
- 매우 큰 데이터 + 빠른 양쪽 삽입 ➡️ deque 사용