[C++, 자료구조] 덱(Deque)

2025. 12. 22. 16:53·C++/자료구조
728x90

■ 덱(Deque)

스택은 같은 한쪽(Top)에서 데이터를 넣고 빼는 구조였고, 큐는 뒤에서 데이터를 넣고 앞에서 데이터를 꺼내는 자료구조였다.

[Deque]

덱은 앞으로도 뒤로도 넣을 수 있고, 앞으로도 뒤로도 뺄 수 있는, 스택과 큐의 특성을 모두 갖추고 있는 자료구조이다.

  • Deque는 ‘디큐’로 읽기 쉬운데, 이러면 큐의 Dequeue연산과 발음이 같아져 “덱”으로 발음한다
    • Double-Ended Queue의 줄임말이다.

▶ 덱의 추상 자료형

덱의 특성을 살펴봤으니, 이번엔 덱의 추상 자료형에 대해 살펴보자.

정의 설명
void InitDeque(Deque* dq) 덱의 초기화를 진행한다. 덱 생성 후 가장 먼저 호출한다.
bool IsEmpty(Deque* dq) 덱이 빈 경우 ture, 그렇지 않은 경우는 false를 반환한다.
void PushFront(Deque* dq, Data data) 덱의 머리에 데이터를 저장한다.
void PushBack(Deque* dq, Data data) 덱의 꼬리에 데이터를 저장한다.
Data PopFront(Deque* dq) 덱의 머리에 위치한 데이터를 반환 및 소멸한다.
Data PopBack(Deque* dq) 덱의 꼬리에 위치한 데이터를 반환 및 소멸한다.
Data GetFirst(Deque* dq) 덱의 머리에 위치한 데이터를 소멸하지 않고 반환한다.
Data GetLast(Deque* dq) 덱의 꼬리에 위치한 데이터를 소멸하지 않고 반환한다.

 

덱도 마찬가지로 배열, 혹은 리스트를 기반으로 작성할 수 있지만 데이터의 삽입 특징에 따라 가장 어울리는 “양방향 연결 리스트”를 사용하여 구현할 것이다.

 

■ 덱의 구현

1. Deque.h

#pragma once
typedef int Data;

struct DequeNode
{
	DequeNode* prev = nullptr;
	DequeNode* next = nullptr;
	Data data;
}; typedef DequeNode Node;

struct Deque
{
	Node* head = nullptr;
	Node* tail = nullptr;
};

void InitDeque(Deque* dq);

void push_front(Deque* dq, Data value);
void push_back(Deque* dq, Data value);
Data pop_front(Deque* dq);
Data pop_back(Deque* dq);

Data get_front(Deque* dq);
Data get_back(Deque* dq);

bool IsEmpty(Deque* dq);

 

앞서 정리한 추상 자료형을 기반으로 헤더 파일을 작성하였다.

[꼬리가 있는 양방향 연결 리스트]

머리를 가리키는 Head 포인터를 덱의 앞으로, 꼬리를 가리키는 Tail 포인터를 덱의 끝으로 설정하여 데이터를 추가하거나 반환한다.

  • 기존 양방향 리스트와 크게 차이는 없지만, 추상 자료형이 다르기 때문에 코드까지 완전히 동일하진 않다.

 

2. Deque.cpp

1. InitDeque() / IsEmpty()

void InitDeque(Deque* dq)
{
	if(dq->head != nullptr)
	{
		while (IsEmpty(dq) == false)
		{
			pop_front(dq);
		}
	}

	dq->head = nullptr;
	dq->tail = nullptr;
}

bool IsEmpty(Deque* dq)
{
	return dq->head == nullptr;   // 헤드 노드가 nullptr이라면, 덱은 비어있다.
}

 

덱을 초기화하고 나서 가장 먼저 호출하는 함수이다.

  • 이전과 동일하게 덱에 데이터가 있는 상태에서 head와 tail을 nullptr로 만들어버리면, 기존 데이터에는 접근이 불가능하니 pop_front() 함수를 사용하여 할당된 메모리를 해제한다.

 

2. push_front()

void push_front(Deque* dq, Data value)
{
	auto newNode = new Node;

	newNode->data = value;
	newNode->next = dq->head;

	if(IsEmpty(dq))
	{
		dq->tail = newNode;
	}
	else
	{
		dq->head->prev = newNode;
	}

	dq->head = newNode;
}

 

노드를 생성하고, 인자로 전달된 데이터를 초기화한다. 새롭게 생성된 노드의 next 포인터는 기존 head가 가리키는 노드를 가리키도록 만든다.

[데이터가 추가되는 경우]

  • 처음으로 데이터가 추가되는 경우라면(dq→head == null), tail도 newNode를 가리켜야 한다.
  • 기존 데이터가 존재하는 경우라면, head가 가리키는 노드의 prev 포인터를 newNode를 가리키게 한 뒤, head노드를 옮긴다.

 

3. push_back()

void push_back(Deque* dq, Data value)
{
	auto newNode = new Node;

	newNode->data = value;
	newNode->prev = dq->tail;

	if(IsEmpty(dq))
	{
		dq->head = newNode;
	}
	else
	{
		dq->tail->next = newNode;
	}

	dq->tail = newNode;
}

 

push_front()와 동일한 원리로 노드를 추가한다. 데이터가 끝(tail)에 추가된다는 점만 조심해 주면 된다.

 

4. pop_front()

Data pop_front(Deque* dq)
{
	if(IsEmpty(dq))
	{
		cout << "Deque is empty!" << endl;
		return -1;
	}

	auto delNode = dq->head;
	auto retData = delNode->data;

	dq->head = delNode->next;
	delete delNode;

	if(dq->head == nullptr)
	{
		dq->tail = nullptr;
	}
	else
	{
		dq->head->prev = nullptr;
	}

	return retData; 
}

 

head가 가리키는 노드의 포인터 정보와 데이터 정보를 저장하고, Head의 위치를 삭제될 노드의 다음 위치로 옮긴다.

[데이터를 반환하는 경우]

데이터를 추가할 때와 마찬가지로, 반환하고 소멸시킬 때도 확인해야 할 경우가 있다.

  • dq->head == nullptr : 더이상 남아있는 데이터가 없으므로, tail 역시 nullptr로 변경한다.
  • dq->head != nullptr : 옮겨진 head가 가리키는 prev가 소멸되었으니, nullptr로 변경한다.

 

5. pop_back()

Data pop_back(Deque* dq)
{
	if(IsEmpty(dq))
	{
		cout << "Deque is empty!" << endl;
		return -1;
	}

	auto delNode = dq->tail;
	auto retData = delNode->data;

	dq->tail = delNode->prev;
	delete delNode;

	if(dq->tail == nullptr)
	{
		dq->head = nullptr;
	}
	else
	{
		dq->tail->next = nullptr;
	}

	return retData;
}

pop_back() 함수 역시 pop_front()와 같은 구조이므로 따로 설명은 하지 않고 넘어가겠다.

 

▼ 전체 코드

#include "Deque.h"
#include <iostream>
using namespace std;

void InitDeque(Deque* dq)
{
	if(dq->head != nullptr)
	{
		while (IsEmpty(dq) == false)
		{
			pop_front(dq);
		}
	}

	dq->head = nullptr;
	dq->tail = nullptr;
}

void push_front(Deque* dq, Data value)
{
	auto newNode = new Node;

	newNode->data = value;
	newNode->next = dq->head;

	if(IsEmpty(dq))
	{
		dq->tail = newNode;
	}
	else
	{
		dq->head->prev = newNode;
	}

	dq->head = newNode;
}

void push_back(Deque* dq, Data value)
{
	auto newNode = new Node;

	newNode->data = value;
	newNode->prev = dq->tail;

	if(IsEmpty(dq))
	{
		dq->head = newNode;
	}
	else
	{
		dq->tail->next = newNode;
	}

	dq->tail = newNode;
}

Data pop_front(Deque* dq)
{
	if(IsEmpty(dq))
	{
		cout << "Deque is empty!" << endl;
		return -1;
	}

	auto delNode = dq->head;
	auto retData = delNode->data;

	dq->head = delNode->next;
	delete delNode;

	if(dq->head == nullptr)
	{
		dq->tail = nullptr;
	}
	else
	{
		dq->head->prev = nullptr;
	}

	return retData; 
}

Data pop_back(Deque* dq)
{
	if(IsEmpty(dq))
	{
		cout << "Deque is empty!" << endl;
		return -1;
	}

	auto delNode = dq->tail;
	auto retData = delNode->data;

	dq->tail = delNode->prev;
	delete delNode;

	if(dq->tail == nullptr)
	{
		dq->head = nullptr;
	}
	else
	{
		dq->tail->next = nullptr;
	}

	return retData;
}

Data get_front(Deque* dq)
{
	if(IsEmpty(dq))
	{
		cout << "Deque is empty!" << endl;
		return -1;
	}

	return dq->head->data;
}

Data get_back(Deque* dq)
{
	if (IsEmpty(dq))
	{
		cout << "Deque is empty!" << endl;
		return -1;
	}

	return dq->tail->data;
}

bool IsEmpty(Deque* dq)
{
	return dq->head == nullptr;
}

#include<iostream>
#include "Deque.h"
using namespace std;

int main()
{
	Deque dq;
	InitDeque(&dq);

	for(int i = 0; i <= 50; i++)
	{
		if(i % 2 == 0)
		{
			push_front(&dq, i);
		}
		else
		{
			push_back(&dq, i);
		}
	}

	PrintAllDataFromFront(&dq);

	for(int i = 0; i <= 25; i++)
	{
		cout << "Pop Front: " << pop_front(&dq) << endl;
		cout << "Pop Back: " << pop_back(&dq) << endl << endl;
	}

	return 0;
}

[Main.cpp]

0~50까지의 수 중 짝수는 덱의 앞에, 홀수는 뒤의 덱에 추가한 뒤 앞 뒤에서 하나씩 pop 하면 성공적으로 덱을 구현한 것을 확인할 수 있다.

728x90

'C++ > 자료구조' 카테고리의 다른 글

[C++, 자료구조] 큐(Queue)  (0) 2025.12.22
[C++, 자료구조] stack의 응용 : 계산기 프로그램  (0) 2025.11.11
[C++, 자료구조] 스택(Stack)  (1) 2025.11.11
[C++, 자료구조] 양방향 연결 리스트(Doubly Linked List)  (0) 2025.10.23
[C++, 자료구조] 단일 연결 리스트(Singly Linked List)  (0) 2025.10.23
'C++/자료구조' 카테고리의 다른 글
  • [C++, 자료구조] 큐(Queue)
  • [C++, 자료구조] stack의 응용 : 계산기 프로그램
  • [C++, 자료구조] 스택(Stack)
  • [C++, 자료구조] 양방향 연결 리스트(Doubly Linked List)
브라더스톤
브라더스톤
유티니, C#과 관련한 여러 정보를 끄적여둔 블로그입니다. Email : dkavmdk98@gmail.com
  • 브라더스톤
    젊은 프로그래머의 슬픔
    브라더스톤
  • 전체
    오늘
    어제
    • 개발 노트 (51) N
      • Unity,C# (30)
        • Unity 정보 (7)
        • 알고리즘 (11)
        • 자료구조 (3)
        • 절차적생성(PCG) (9)
      • 게임수학 (14)
      • C++ (7) N
        • 자료구조 (7) N
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    정렬알고리즘
    자료구조
    transform.RotateAround
    BSP
    게임수학
    c++
    unity
    pcg
    C#
    PerlinNoise
    CustomWindow
    알고리즘
    외적
    이진공간분할
    UI Toolkit
    스택
    절차적던전생성
    커스텀 윈도우
    최단경로찾기
    절차적지형생성
  • 최근 댓글

  • 최근 글

  • 250x250
  • hELLO· Designed By정상우.v4.10.3
브라더스톤
[C++, 자료구조] 덱(Deque)
상단으로

티스토리툴바