Skip to content
Home » 자료 구조 덱 | [바킹독의 실전 알고리즘] 0X07강 – 덱 답을 믿으세요

자료 구조 덱 | [바킹독의 실전 알고리즘] 0X07강 – 덱 답을 믿으세요

당신은 주제를 찾고 있습니까 “자료 구조 덱 – [바킹독의 실전 알고리즘] 0x07강 – 덱“? 다음 카테고리의 웹사이트 kk.taphoamini.com 에서 귀하의 모든 질문에 답변해 드립니다: kk.taphoamini.com/wiki. 바로 아래에서 답을 찾을 수 있습니다. 작성자 BaaarkingDog 이(가) 작성한 기사에는 조회수 3,839회 및 좋아요 61개 개의 좋아요가 있습니다.

Table of Contents

자료 구조 덱 주제에 대한 동영상 보기

여기에서 이 주제에 대한 비디오를 시청하십시오. 주의 깊게 살펴보고 읽고 있는 내용에 대한 피드백을 제공하세요!

d여기에서 [바킹독의 실전 알고리즘] 0x07강 – 덱 – 자료 구조 덱 주제에 대한 세부정보를 참조하세요

코딩테스트 대비를 위한 바킹독의 실전 알고리즘 0x07강 – 덱 입니다.
영상보다 글이 더 편하신 분은 https://blog.encrypted.gg/935 에서 보셔도 됩니다.
—————목차—————
00:00 인트로
00:15 0x00 정의와 성질
01:08 0x01 기능과 구현
03:29 0x02 STL deque
05:04 0x03 연습 문제
Github link : https://github.com/encrypted-def/basic-algo-lecture
BOJ 문제집 link : https://github.com/encrypted-def/basic-algo-lecture/blob/master/workbook.md
(문제집을 그룹 바깥으로 옮겨두었기 때문에 그룹 가입은 필요 없습니다.)

자료 구조 덱 주제에 대한 자세한 내용은 여기를 참조하세요.

[자료구조] 덱(Deque)의 이해와 구현 – 블로그

덱(deque)은 double-ended queue를 줄여서 표현한 것으로, 양방향으로 넣고 뺄 수 있다는 사실에 초점이 맞춰져 지어진 이름이다. 덱은 스택과 큐의 특성 …

+ 여기에 자세히 보기

Source: blog.naver.com

Date Published: 5/30/2021

View: 6967

[자료구조] 스택(Stack)/큐(Queue)/덱(Deque) – velog

✏️ 덱(Dequeue) … 덱이란, 양쪽에서 삽입과 삭제가 가능한 구조이며 스택과 큐의 연산을 모두 지원한다. … 덱의 연산은 collections 모듈에서 제공 …

+ 더 읽기

Source: velog.io

Date Published: 12/5/2021

View: 5993

[자료구조] 덱 (Deque : Double-Ended-Queue) 의 구조와 구현

[자료구조] 덱 (Deque : Double-Ended-Queue) 의 구조와 구현 – 덱의 전단(front)와 후단(rear)의 입출력 … 덱은, 기존의 원형 큐에서 일부 기능이 추가된, 전단과 후단 …

+ 여기에 자세히 보기

Source: dream-and-develop.tistory.com

Date Published: 10/21/2021

View: 7499

덱 (자료 구조) – 위키백과, 우리 모두의 백과사전

덱(deque, “deck”과 발음이 같음 ← double-ended queue)은 양쪽 끝에서 삽입과 삭제가 모두 가능한 자료 구조의 한 형태이다. 두 개의 포인터를 사용하여, …

+ 여기에 표시

Source: ko.wikipedia.org

Date Published: 6/2/2021

View: 3850

[자료구조] 덱 (Deque) – Suyeon’s Blog – 티스토리

덱 (Deque) 덱? 덱(Deque)이란 Double-Ended Queue의 줄임말이다. 즉, 앞쪽 front 와 뒤쪽 rear 에서 모두 삽입과 삭제가 가능한 큐를 의미한다.

+ 여기를 클릭

Source: suyeon96.tistory.com

Date Published: 11/1/2022

View: 8619

[자료구조] 덱 (Deque) – 성장하는 코더의 스토리 – 티스토리

덱 (Deque)은 Double-ended queue를 줄인 것으로, 양쪽에서 삽입과 삭제가 가능한 구조이며 스택과 큐의 연산을 모두 지원한다. 즉, 앞쪽 front와 뒤쪽 …

+ 여기를 클릭

Source: propercoding.tistory.com

Date Published: 12/19/2022

View: 8521

[자료구조] 덱 Deque(Double-ended-queue) 큐 구현 – yjglab

덱(deque)은 double-ended queue의 줄임말로써 후단(rear)으로만 데이터를 삽입했던 기존 선형 큐, 원형 큐와 달리 큐의 전단(front)와 후단(rear) …

+ 여기에 자세히 보기

Source: yjg-lab.tistory.com

Date Published: 5/9/2021

View: 6079

[자료구조] 덱(Deque, Double-ended Queue) 설명 및 구현

덱은 큐의 양쪽 끝에서 데이터의 삽입과 삭제가 모두 가능하게 만든 큐로서, 스택과 큐의 성질을 모두 가지고 있는 자료구조입니다. 덱의 구조 …

+ 여기에 더 보기

Source: leejinseop.tistory.com

Date Published: 10/25/2021

View: 4002

_8_ 자료구조 — 덱. 덱 자료구조와 연산, 시간복잡도 | Medium

덱 자료구조와 연산, 시간복잡도. “_8_ 자료구조 — 덱” is published by MJ Studio in 알고리즘은 미친짓이다.

+ 자세한 내용은 여기를 클릭하십시오

Source: medium.com

Date Published: 11/7/2021

View: 5157

덱(Deque)의 이해와 구현 – 언제나 되돌아보기 – 티스토리

스택과 큐의 구조를 이해한 사오항에서 덱의 구조는 한줄로 설명이 가능 … 어쨋든 덱은 한방향으로 넣고, 양방향으로 뺄 수 있는 자료구조이기에 …

+ 자세한 내용은 여기를 클릭하십시오

Source: comengin.tistory.com

Date Published: 5/2/2022

View: 2821

주제와 관련된 이미지 자료 구조 덱

주제와 관련된 더 많은 사진을 참조하십시오 [바킹독의 실전 알고리즘] 0x07강 – 덱. 댓글에서 더 많은 관련 이미지를 보거나 필요한 경우 더 많은 관련 기사를 볼 수 있습니다.

[바킹독의 실전 알고리즘] 0x07강 - 덱
[바킹독의 실전 알고리즘] 0x07강 – 덱

주제에 대한 기사 평가 자료 구조 덱

  • Author: BaaarkingDog
  • Views: 조회수 3,839회
  • Likes: 좋아요 61개
  • Date Published: 2020. 3. 14.
  • Video Url link: https://www.youtube.com/watch?v=0mEzJ4S1d8o

[자료구조] 스택(Stack)

👉🏻 스택이란, 한쪽에서만 자료를 넣고 뺄 수 있는 후입선출 LIFO(Last In First Out)형식의 선형 자료구조이다.

스택의 기본 개념은 영어 단어의 뜻과 같이 ‘쌓는다’는 뜻이다. 스택은 같은 구조와 크기의 자료를 정해진 방향으로만 쌓을수 있고, top으로 정한 곳을 통해서만 접근할 수 있다.

예를 들어, 박스 쌓기에 비유할 수 있다. 박스를 아래에서 위로 차곡차곡 쌓으면 아래에 있는 박스를 치우기 위해서는 맨 위의 박스부터 치워야 한다.

아래부터 1->2->3 순서로 쌓여있는 상자를 오른쪽으로 옮긴다고 가정해보자.

먼저 가장 위에 있는 3번 상자를 오른쪽으로 옮기고, 그 후에는 2번 상자를 옮기고, 다음에는 1번 상자를 옮길 것이다. 즉, 마지막에 입력된 상자가 첫 번째로 출력된다.

1->2->3의 순서로 입력되었다면, 3->2->1의 순서로 출력되는 것이다.

우리는 이것을 LIFO(Last In First Out) 형식이라고 하며 스택은 이러한 구조적 특징을 가진다.

[자료구조] 덱 (Deque : Double-Ended-Queue) 의 구조와 구현

덱은, 기존의 원형 큐에서 일부 기능이 추가된, 전단과 후단 양쪽 모두에서 삽입과 삭제의 입출력과 반환이 가능한 원형 큐이다.

원형 큐의 구조와 구현

https://dream-and-develop.tistory.com/102

덱(DEQUE : Double-Ended Queue)

덱(Deque) 은 큐의 전단(front)과 후단(rear) 에서 모두 입출력(삽입/삭제)가 가능한 큐이다.

덱의 추상 자료형은 다음과 같다.

– create(MAX) : 구조체 DequeType을 구현하여 구조체 변수를 선언하는 것과 동일하다.

– init(dq) : 덱을 초기화한다. 덱의 rear, front 멤버 변수를 각각 0으로 설정한다.

– is_empty(dq) : 큐가 공백 상태인지 체크한다. 기존의 원형 큐와 동일한 방법을 사용한다.

– is_full(dq) : 큐가 포화 상태인지 체크한다. 기존의 원형 큐와 동일한 방법

– add_front(dq, e) : 덱의 맨 앞에 요소를 추가한다. 다만, front 값을 1 감소 시킨 후, 삽입한다.

– add_rear(dq, e) : 덱의 맨 뒤에 요소를 추가한다. 기존 원형 큐의 enqueue() 연산과 동일하다. rear 값을 1 증가 후, 삽입한다.

– delete_front(dq) : 덱의 맨 앞의 요소를 반환 후 삭제한다. front 값을 1 증가 후, front가 가리키는 요소를 반환한다. 기존 원형 큐의 dequeue() 연산과 동일하다.

– delete_rear(dq) : 덱의 맨 뒤의 요소를 반환 후 삭제 한다. rear이 가리키는 요소를 반환 후, rear 값을 1 감소한다.

– get_front(dq) : 덱의 맨 앞의 요소를 반환한다. front의 값 1을 증가한 위치의 요소를 반환한다.

– get_rear(dq) : 덱의 맨 뒤의 요소를 반환한다. rear 가 가리키는 위치의 요소를 반환한다.

정리하면,

add_rear() 과 delete_front() 연산은 기존 (원형)큐의 enqueue, dequeue 연산과 동일하고,

전단과 관련된 연산들만 사용하면, 스택이 된다.

따라서, add_rear() / delete_front()을 제외한,

전단에 삽입하는 add_front() / 후단의 요소를 반환하고 삭제하는 delete_rear(),

그리고 get_rear(), get_front() 의 연산이 기존 큐에서 추가된 것이라 볼 수 있다.

위의 ADT를 코드로 구현한 것을 하나하나 자세히 살펴보자.

1. 덱의 구조체 선언

DequeType의 이름으로 typedef 시켜놓은 구조체는 다음과 같다.

element는 간단하게 정수형으로 정의하고,

MAX_QUEUE_SIZE는 10으로 정의되어 있으므로, 총 9개의 요소를 저장할 수 있는 덱의 배열,

그리고 전단(front)와 후단(rear)을 멤버 변수로 선언하였다.

(원형 큐의 공백, 포화를 구분하기 위해서 한 개의 공간은 항상 비워둔다 !)

#define MAX_QUEUE_SIZE 10 typedef int element; typedef struct { element data[MAX_QUEUE_SIZE]; int front, rear; }DequeType;

2. 덱 초기화, 공백/포화 상태 확인

각각 DequeType 구조체 포인터를 받아온다.

init_deque() – 덱의 front, rear 값을 0으로 초기화한다.

is_empty() – front와 rear 값이 같다면 덱이 공백 상태임을 체크

is_full() – rear이 front보다 한 칸 앞에 위치해 있다면, 덱이 포화 상태임을 체크

// 덱 초기화 void init_deque(DequeType* dq) {dq->front = dq->rear = 0;} // is_empty int is_empty(DequeType* dq) { return (dq->front == dq->rear); } // is_full int is_full(DequeType* dq) { return ((dq->rear + 1) % MAX_QUEUE_SIZE == dq->front); }

3. 기존 큐와 동일한 add_rear() (enqueue와 동일), delete_front() (dequeue와 동일)

add_rear() – 후단에 새로운 요소를 삽입한다. rear 값을 1 증가시킨 후, 해당 위치에 요소를 삽입한다.

delete_front() – 전단의 요소를 반환하고 삭제한다. front의 값을 1 증가시킨 후, 해당 위치의 요소를 반환한다.

(++전위 연산 후, 반환)

// add_rear void add_rear(DequeType* dq, element item) { // rear 값 1 증가 후 삽입 if (is_full(dq)) { printf(“Deque is full

“); exit(1); } dq->rear = (dq->rear + 1) % MAX_QUEUE_SIZE; dq->data[dq->rear] = item; } // delete_front element delete_front(DequeType* dq) { // front 값 1 증가 후 반환 if (is_empty(dq)) { printf(“Deque is empty

“); exit(1); } dq->front = (dq->front + 1) % MAX_QUEUE_SIZE; return dq->data[dq->front]; }

4. add_front()

전단에 새로운 요소를 삽입한다.

front는 첫번째 요소가 위치한 인덱스보다 하나 앞을 가리키고 있다.

따라서 전단에 삽입하기 위해서는, 현재 front 의 값에 요소를 삽입한 다음에,

front의 값을 1 감소시킨다.

이 때, 인덱스 0에서 음수의 값이 될 수 있는 경우를 위해,

1 감소시킨 후에 다시 MAX_QUEUE_SIZE 만큼 더한 후에, MAX_QUEUE_SIZE로 나눈 나머지 값을 대입하도록 한다.

// add_front void add_front(DequeType* dq, element item) { // front가 가리키는 곳에 삽입 후, front값 1 감소 if (is_full(dq)) { printf(“Deque is full

“); exit(1); } dq->data[dq->front] = item; dq->front = (dq->front – 1 + MAX_QUEUE_SIZE) % MAX_QUEUE_SIZE; }

5. delete_rear()

후단의 요소를 반환 후 삭제한다.

rear은 마지막 요소를 가리키고 있다. 따라서 해당 요소를 반환 후 삭제하기 위해서는,

현재의 값을 반환한 다음에, rear의 값을 감소시켜야 한다.

하지만 리턴을 하게 되는 순간, 다음 rear의 값을 감소시키는 문장은 실행되지 않게 되므로,

반환할 요소의 현재 인덱스(==현재 rear이 가리키는 위치의 인덱스값)를 prev라는 새로운 변수에 대입한다.

이후 rear의 값을 1 감소 시킨 후, 기존의 인덱스 값을 저장하는 prev의 요소를 반환한다.

이 때에도, 기존 rear의 값이 0인 경우 1을 감소시키면 음수가 되므로,

1 감소시킨 후 MAX_QUEUE_SIZE를 더한 후에, MAX_QUEUE_SIZE로 나눈 나머지의 값을 저장하도록 한다.

// delete_rear element delete_rear(DequeType* dq) { // rear이 가리키는 값 반환 후, rear 값 1 증가 int prev = dq->rear; if (is_empty(dq)) { printf(“Deque is empty

“); exit(1); } dq->rear = (dq->rear – 1 + MAX_QUEUE_SIZE) % MAX_QUEUE_SIZE; return dq->data[prev]; }

6. get – 값 반환

get_front()

front 부분의 연산을 스택의 pop, push 연산이라고 치면,

전단의 요소를 반환하기만 하는 get_front() 연산은 스택에서의 peek() 연산과 동일하다고 볼 수 있겠다.

front의 값을 1 증가시킨 후에 해당 요소를 반환한다.

get_rear()

마지막 rear이 가리키고 있는 위치의 요소를 그대로 반환한다.

//get_front element get_front(DequeType* dq) { // front 값 1 증가시킨 값의 요소를 반환 if (is_empty(dq)) { printf(“Deque is empty

“); return; } return dq->data[(dq->front + 1) % MAX_QUEUE_SIZE]; } // get_rear element get_rear(DequeType* dq) { // rear이 가리키는 값 반환 if (is_empty(dq)) { printf(“Deque is empty

“); return; } return dq->data[dq->rear]; }

전체 코드는 다음과 같다.

#include #define MAX_QUEUE_SIZE 10 typedef int element; typedef struct { element data[MAX_QUEUE_SIZE]; int front, rear; }DequeType; // 덱 초기화 void init_deque(DequeType* dq) {dq->front = dq->rear = 0;} // is_empty int is_empty(DequeType* dq) { return (dq->front == dq->rear); } // is_full int is_full(DequeType* dq) { return ((dq->rear + 1) % MAX_QUEUE_SIZE == dq->front); } // add_front void add_front(DequeType* dq, element item) { // front가 가리키는 곳에 삽입 후, front값 1 감소 if (is_full(dq)) { printf(“Deque is full

“); exit(1); } dq->data[dq->front] = item; dq->front = (dq->front – 1 + MAX_QUEUE_SIZE) % MAX_QUEUE_SIZE; } // add_rear void add_rear(DequeType* dq, element item) { // rear 값 1 증가 후 삽입 if (is_full(dq)) { printf(“Deque is full

“); exit(1); } dq->rear = (dq->rear + 1) % MAX_QUEUE_SIZE; dq->data[dq->rear] = item; } // delete_front element delete_front(DequeType* dq) { // front 값 1 증가 후 반환 if (is_empty(dq)) { printf(“Deque is empty

“); exit(1); } dq->front = (dq->front + 1) % MAX_QUEUE_SIZE; return dq->data[dq->front]; } // delete_rear element delete_rear(DequeType* dq) { // rear이 가리키는 값 반환 후, rear 값 1 증가 int prev = dq->rear; if (is_empty(dq)) { printf(“Deque is empty

“); exit(1); } dq->rear = (dq->rear – 1 + MAX_QUEUE_SIZE) % MAX_QUEUE_SIZE; return dq->data[prev]; } //get_front element get_front(DequeType* dq) { // front 값 1 증가시킨 값을 반환 if (is_empty(dq)) { printf(“Deque is empty

“); return; } return dq->data[(dq->front + 1) % MAX_QUEUE_SIZE]; } // get_rear element get_rear(DequeType* dq) { // rear이 가리키는 값 반환 if (is_empty(dq)) { printf(“Deque is empty

“); return; } return dq->data[dq->rear]; } int main() { DequeType deque; // MAX_QUEUE_SIZE = 10 init_deque(&deque); // front, rear = 0 // 0부터 9까지의 값을 add_rear for (int i = 0;i < 10;i++) { // 홀수인 경우는 후단에 삽입 if (i % 2) { add_rear(&deque, i); printf("add_rear(%d) \t front=%d, rear=%d ", get_rear(&deque), deque.front, deque.rear); } // 짝수인 경우는 전단에 삽입 else{ add_front(&deque, i); printf("add_front(%d) \t front=%d, rear=%d ", get_front(&deque), deque.front, deque.rear); } } } 마지막에 작성되어 있는 main 함수를 살펴보면, 총 9개의 요소를 저장할 수 있는 덱 deque가 초기화되었다. for문 내부에서는 제어 변수 i가 0부터 9까지 총 10번 돌아가며, i의 값이 홀수/짝수인지에 따라 홀수이면 후단 부분에, 짝수이면 전단 부분에 차례대로 삽입이 된다. 삽입이 된 후에는, front와 rear의 값을 확인해보기 위해 get_rear()과 get_front() 가 각각 실행되어 출력된다. 실행 결과는 다음과 같다. 덱의 MAX_QUEUE_SIZE가 10으로 정의되었으므로, 총 9개(0부터 8)의 요소만 삽입이 된 것을 확인할 수 있다. 그리고 i의 값이 짝수여서 전단에 삽입된 경우에는, front의 값이 0부터 1씩 감소되는 것을, i의 값이 홀수여서 후단에 삽입된 경우에는, rear의 값이 0부터 1씩 증가되는 것을 확인할 수 있다. 마지막에는 (rear+1)%MAX_QUEUE_SIZE == front 가 성립되어 9가 후단에 삽입되지 못하고 덱이 포화상태라는 문장을 출력하고 실행이 종료된다. 이중 연결 리스트 로의 확장 전단과 후단 모두에서 입출력이 이루어지는 덱(Double Ended Queue)을 살펴보았다. 포화 또는 공백 상태만 아니라면, 전단과 후단 어디에든지 요소를 삽입하고 삭제할 수 있다는 장점이 있다. 그러나 문제점은, 배열에 요소를 입출력하는 자료이므로, 정해진 크기만큼의 요소만 다룰 수 있다는 점이다. 따라서, 프로그램 실행 도중 사용자가 자유롭게 동적 메모리를 할당 받아 크기의 제한 없이 요소를 삽입하고, 더하여 원하는 위취에 삽입/삭제 가능할 수 있도록 '연결 리스트'로 구현하면 이중 연결리스트(Double Linked List) 가 된다. 이중 연결리스트를 활용한 실습 문제 https://dream-and-develop.tistory.com/64 728x90

덱 (자료 구조)

덱(deque, “deck”과 발음이 같음 ← double-ended queue)은 양쪽 끝에서 삽입과 삭제가 모두 가능한 자료 구조의 한 형태이다.

두 개의 포인터를 사용하여, 양쪽에서 삭제와 삽입을 발생시킬 수 있다. 큐와 스택을 합친 형태로 생각할 수 있다.

데크의 종류 [ 편집 ]

[자료구조] 덱 (Deque)

728×90

반응형

덱 (Deque)

덱?

덱(Deque)이란 Double-Ended Queue의 줄임말이다.

즉, 앞쪽 front 와 뒤쪽 rear 에서 모두 삽입과 삭제가 가능한 큐를 의미한다.

덱 ADT

객체

전단과 후단 양쪽에서의 삽입과 삭제를 허용하는 동일한 자료형의 요소들의 모음

연산

addFront(x) : 요소 x를 덱의 맨 앞에 추가

: 요소 x를 덱의 맨 앞에 추가 addRear(x) : 요소 x를 덱의 맨 뒤에 추가

: 요소 x를 덱의 맨 뒤에 추가 deleteFront() : 큐의 맨 앞의 요소를 삭제하고 반환

: 큐의 맨 앞의 요소를 삭제하고 반환 deleteRear() : 큐의 맨 뒤의 요소를 삭제하고 반환

: 큐의 맨 뒤의 요소를 삭제하고 반환 getFront() : 큐의 맨 앞의 요소를 삭제하지 않고 반환

: 큐의 맨 앞의 요소를 삭제하지 않고 반환 getRear() : 큐의 맨 뒤의 요소를 삭제하지 않고 반환

: 큐의 맨 뒤의 요소를 삭제하지 않고 반환 isEmpty() : 큐가 비어있으면 true 아니면 false 반환

isFull() : 큐가 가득 차 있으면 true 아니면 false 반환

size() : 큐 내의 모든 요소 개수를 반환

display() : 큐 내의 모든 요소 출력

Array로 Circular Deque 구현 (C++)

/* * array를 이용하여 Circular Deque 구현 */ #include using namespace std; #define MAX_DEQUE_SIZE 10 class Deque { private: int front; // 첫번째 요소 앞의 index int rear; // 마지막 요소 index int data[MAX_DEQUE_SIZE]; public: Deque(){ front = 0; rear = 0; } ~Deque(){} void addFront(int n){ if(isFull()){ cout << "Deque Full Error" << endl; exit(1); } data[front] = n; front = (front-1+MAX_DEQUE_SIZE)%MAX_DEQUE_SIZE; // front가 0 이하로 떨어지는 경우 max index로 순회 } void addRear(int n){ // push if(isFull()){ cout << "Deque Full Error" << endl; exit(1); } rear = (rear+1)%MAX_DEQUE_SIZE; // rear가 max를 넘어가는 경우 다시 0번째 index로 순회 data[rear] = n; } int deleteFront(){ // pop if(isEmpty()){ cout << "Deque Empty Error" << endl; exit(1); } front = (front+1)%MAX_DEQUE_SIZE; // front가 max를 넘어가는 경우 다시 0번째 index로 순회 return data[front]; } int deleteRear(){ if(isEmpty()){ cout << "Deque Empty Error" << endl; exit(1); } int tmp = data[rear]; rear = (rear-1+MAX_DEQUE_SIZE)%MAX_DEQUE_SIZE; // rear가 0 이하로 떨어지는 경우 max index로 순회 return tmp; } int getFront(){ if(isEmpty()){ cout << "Deque Empty Error" << endl; exit(1); } return data[(front+1)%MAX_DEQUE_SIZE]; } int getRear(){ if(isEmpty()){ cout << "Deque Empty Error" << endl; exit(1); } return data[rear]; } int size(){ return front<=rear ? rear-front : (rear+MAX_DEQUE_SIZE)-front; } void display(){ for(int i=front+1; i<=front+size(); i++){ cout << "[" << data[i%MAX_DEQUE_SIZE] << "]"; } cout << endl; } // circular array의 front와 rear 정보를 보기위한 메소드 void displayDetail(){ cout << "DEQUE :"; for(int i=front+1; i<=front+size(); i++){ cout << "[" << data[i%MAX_DEQUE_SIZE] << "]"; } cout << endl; cout << "index :"; for(int i=front+1; i<=front+size(); i++){ cout << " " << i%MAX_DEQUE_SIZE << " "; } cout << endl; cout << "front : " << front << ", rear : " << rear << endl; cout << endl; } bool isEmpty(){ return front == rear; } bool isFull() { return front == (rear+1)%MAX_DEQUE_SIZE; } }; int main() { Deque deque; cout << "===== addRear x3 =====" << endl; deque.addRear(1); deque.addRear(2); deque.addRear(3); cout << " size : " << deque.size() << endl; deque.displayDetail(); cout << "===== addFront x2 ======" << endl; deque.addFront(5); deque.addFront(6); cout << " size : " << deque.size() << endl; deque.displayDetail(); cout << "===== deleteRear x1 ======" << endl; deque.deleteRear(); cout << " size : " << deque.size() << endl; deque.displayDetail(); cout << "===== deleteFront x3 ======" << endl; deque.deleteFront(); deque.deleteFront(); deque.deleteFront(); cout << " size : " << deque.size() << endl; deque.displayDetail(); } LinkedList로 Circular Deque 구현 (C++) /* * 이중 Linked List를 이용하여 Deque 구현 */ #include using namespace std; // Doubly Linked List struct Node { int data; Node* prev; // 이전 Node를 가리키는 pointer Node* next; // 다음 Node를 가리키는 pointer public: Node(){ prev = nullptr; next = nullptr; data = 0; } Node(int n, Node* prevNode = nullptr, Node* nextNode = nullptr){ data = n; prev = prevNode; next = nextNode; } ~Node(){} void setPrev(Node* prevNode){ prev = prevNode; } void setNext(Node* nextNode){ next = nextNode; } }; // Deque Class class Deque { private: Node* front; // Deack의 front를 가리키는 Node pointer Node* rear; // Deack의 rear를 가리키는 Node pointer int dataSize; // Stack에 저장된 데이터 size public: Deque(){ front = nullptr; rear = nullptr; dataSize = 0; } ~Deque(){ while(!isEmpty()){ deleteFront(); //deleteRear(); } delete front; delete rear; } //새로운 node를 생성 (prev : null, next : 기존의 front node) //front를 새로운 node로 변경 //최초 생성이라면 rear = node 해줌 //이후 front가 추가될 때마다 기존 node의 prev에 새로 추가되는 node 대입 void addFront(int n){ Node* node = new Node(n, nullptr, front); if(rear == nullptr){ rear = node; }else{ front->setPrev(node); } front = node; dataSize++; } //addFront()와 같은 맥락. //새로운 node를 생성 (prev : 기존의 rear node, next : null) //rear를 새로운 node로 변경 //최초 생성이라면 front = node 해줌 //이후 rear가 추가될 때마다 기존 node의 next에 새로 추가되는 node 대입 void addRear(int n){ Node* node = new Node(n, rear, nullptr); if(front == nullptr){ front = node; }else{ rear->setNext(node); } rear = node; dataSize++; } //deque가 비어있는 경우 error occurred //그렇지 않다면, 우선 front node의 데이터를 임시 변수 ‘data’에 담아놓음 //front를 next node로 변경한 다음, 삭제된 node(front였던)는 delete 처리 (메모리자원을위해) //아까 담아놓은 ‘data’를 반환 //또한 현재 front노드의 prev를 null로 지정 int deleteFront(){ if(isEmpty()){ cout << "Deque Empty Error" << endl; exit(EXIT_FAILURE); }else{ int data = front->data; Node* node = front; front = front->next; front->setPrev(nullptr); delete node; dataSize–; return data; } } //deleteFront()와 같은 맥락. //deque가 비어있는 경우 error occurred //그렇지 않다면, 우선 rear node의 데이터를 임시 변수 ‘data’에 담아놓음 //rear를 prev node로 변경한 다음, 삭제된 node(rear였던)는 delete 처리 (메모리자원을위해) //아까 담아놓은 ‘data’를 반환 //또한 현재 rear노드의 next를 null로 지정 int deleteRear(){ if(isEmpty()){ cout << "Deque Empty Error" << endl; exit(EXIT_FAILURE); }else{ int data = rear->data; Node* node = rear; rear = rear->prev; rear->setNext(nullptr); delete node; dataSize–; return data; } } // deque의 모든 data 출력 void display(){ if(isEmpty()){ cout << "Deque is Empty" << endl; }else{ Node* node = front; while(node){ cout << "[" << node->data << "]"; node = node->next; } cout << endl; } } // deque size 반환 int size(){ return dataSize; } bool isEmpty(){ return dataSize == 0; } }; int main() { Deque deque; cout << "===== addRear x3 =====" << endl; deque.addRear(1); deque.addRear(2); deque.addRear(3); cout << " size : " << deque.size() << endl; deque.display(); cout << "===== addFront x2 ======" << endl; deque.addFront(5); deque.addFront(6); cout << " size : " << deque.size() << endl; deque.display(); cout << "===== deleteRear x1 ======" << endl; cout << deque.deleteRear() << endl; cout << " size : " << deque.size() << endl; deque.display(); cout << "===== deleteFront x3 ======" << endl; cout << deque.deleteFront() << endl; cout << deque.deleteFront() << endl; cout << deque.deleteFront() << endl; cout << " size : " << deque.size() << endl; deque.display(); } 728x90 반응형

[자료구조] 덱 (Deque)

반응형

목차

덱(Deque)의 개념

덱 (Deque)은 Double-ended queue를 줄인 것으로, 양쪽에서 삽입과 삭제가 가능한 구조이며 스택과 큐의 연산을 모두 지원한다. 즉, 앞쪽 front와 뒤쪽 rear에서 모두 삽입과 삭제가 가능한 큐를 의미한다. 따라서 스택과 큐의 특성을 모두 갖는 자료구조이다.

덱이 수용할 수 있는 데이터의 크기를 넘어가는 삽입 연산을 수행할 때는 오버플로우가 (Overflow) 발생한다. 그리고 비어 있는 덱에서 삭제 연산을 수행하면 언더플로우 (Underflow)가 발생한다.

덱의 핵심 기능은 앞으로 데이터 삽입, 앞으로 데이터 제거, 뒤로 데이터 삽입, 뒤로 데이터 제거이다. 밑에서 덱의 메서드들과 사용법을 알아보겠다.

덱 (Deque) 기능 & 사용법

덱 (Deque) 선언

자바에서의 덱은 인터페이스로 구현되었다. 덱 자료구조의 여러 연산들을 정의한 Deque 인터페이스가 있고 이를 구현한 ArrayDeque, LinkedBlockingDeque, ConcurrentLinkedDeque, LinkedList 등의 클래스가 있다. 덱 또한 배열 및 연결 리스트로 구현이 가능하지만 덱의 특성상 가장 잘 어울리는 것은 양방향 연결 리스트이다.

Deque deque1 = new ArrayDeque<>(); Deque deque2 = new ConcurrentLinkedDeque<>(); Deque deque3 = new LinkedBlockingDeque<>(); Deque deque4 = new LinkedList<>();

덱 (Deque) 값 추가

메서드 설명 void addFirst() 덱의 앞쪽에 데이터 추가

단, 저장공간이 부족하면 IllegalStateExcepetion 발생 boolean offerFirst() 덱의 앞쪽에 데이터 추가

성공하면 true, 실패하면 false 반환 void addLast() 덱의 뒷쪽에 데이터 추가

단, 저장공간이 부족하면 IllegalStateExcepetion 발생 boolean add() 덱의 뒷쪽에 데이터 추가 (addLast()와 동일)

단, 저장공간이 부족하면 IllegalStateExcepetion 발생 boolean offerLast() 덱의 뒷쪽에 데이터 추가

성공하면 true, 실패하면 false 반환 boolean offer() 덱의 뒷쪽에 데이터 추가 (offerLast()와 동일)

성공하면 true, 실패하면 false 반환

Deque deque = new ConcurrentLinkedDeque<>(); deque.addFirst(“Hello”); deque.addLast(” World”); // 덱에는 “Hello World” 있음 deque.offerFirst(“Hello”); deque.offerLast(” World”);

덱 (Deque) 값 삭제

메서드 설명 Object remove() 덱의 앞쪽에 있는 데이터 삭제

단, 덱이 비어 있으면 NoSuchElementException 발생 Object removeFirst() 덱의 앞쪽에 있는 데이터 삭제

단, 덱이 비어 있으면 NoSuchElementException 발생 Object poll() 덱의 앞쪽에 있는 데이터 삭제

단, 덱이 비어 있으면 null 반환 Object pollFirst() 덱의 앞쪽에 있는 데이터 삭제

단, 덱이 비어 있으면 null 반환 Object removeLast() 덱의 뒷쪽에 있는 데이터 삭제

단, 덱이 비어 있으면 NoSuchElementException 발생 Object pollLast() 덱의 뒷쪽에 있는 데이터 삭제

단, 덱이 비어 있으면 null 반환

Deque deque = new ConcurrentLinkedDeque<>(); deque.addFirst(“Hello”); deque.addLast(” World”); deque.removeFirst(); //”Hello” 제거 deque.removeLast(); //” World” 제거 deque.remove(); //noSuchElementException 발생 deque.offerFirst(“Hello”); deque.offerLast(” World”); deque.pollFirst(); //”Hello” 제거 deque.pollLast(); //” World” 제거 deque.poll(); //null 반환

덱 (Deque) 값 출력

메서드 설명 Object getFirst() 덱의 앞쪽에 있는 데이터 가지고 옴

단, 덱이 비어 있으면 NoSuchElementException 발생 Object peek() 덱의 앞쪽에 있는 데이터 가지고 옴

단, 덱이 비어 있으면 null 반환 Object peekFirst() 덱의 앞쪽에 있는 데이터 가지고 옴

단, 덱이 비어 있으면 null 반환 Object getLast() 덱의 뒷쪽에 있는 데이터 가지고 옴

단, 덱이 비어 있으면 NoSuchElementException 발생 Object peekLast() 덱의 뒷쪽에 있는 데이터 삭제

단, 덱이 비어 있으면 null 반환

Deque deque = new ConcurrentLinkedDeque<>(); deque.addFirst(“Hello”); deque.addLast(” World”); deque.getFirst(); // “Hello” deque.getLast(); // ” World” deque.peekFirst(); // “Hello” deque.peekLast(); // ” World” deque.clear(); //덱 초기화 deque.getFirst(); //noSuchElementException 발생 deque.peekFirst(); //null 반환

반응형

[자료구조] 덱 Deque(Double-ended-queue) 큐 구현

덱 Deque(Double-ended-queue)

덱(deque)은 double-ended queue의 줄임말로써 후단(rear)으로만 데이터를 삽입했던 기존 선형 큐, 원형 큐와 달리 큐의 전단(front)와 후단(rear)에서 모두 삽입과 삭제가 가능한 큐입니다.

덱에 사용되는 Abstract Data Type

▪ create() ::= 덱을 생성한다.

▪ init(dq) ::= 덱을 초기화한다.

▪ is_empty(dq) ::= 덱이 공백상태인지를 검사한다.

▪ is_full(dq) ::= 덱이 포화상태인지를 검사한다.

▪ add_front(dq, e) ::= 덱의 앞에 요소를 추가한다.

▪ add_rear(dq, e) ::= 덱의 뒤에 요소를 추가한다.

▪ delete_front(dq) ::= 덱의 앞에 있는 요소를 반환한 다음 삭제한다

▪ delete_rear(dq) ::= 덱의 뒤에 있는 요소를 반환한 다음 삭제한다.

▪ get_front(q) ::= 덱의 앞에서 삭제하지 않고 앞에 있는 요소를 반환한다.

▪ get_rear(q) ::= 덱의 뒤에서 삭제하지 않고 뒤에 있는 요소를 반환한다.

덱의 연산에서 주의할 점은 데이터를 삽입 연산 시 front는 감소하고 rear는 증가하며 삭제 연산 시 front는 증가하고 rear는 감소하는 점입니다.

#include #include #define MAX_QUEUE_SIZE 5 typedef int element; typedef struct { // 덱 큐 타입 element data[MAX_QUEUE_SIZE]; int front, rear; } DequeType; // 오류 함수 void error(char *message) { fprintf(stderr, “%s

“, message); exit(1); } // 덱 초기화 void init_deque(DequeType *q) { q->front = q->rear = 0; } // 공백 상태 검출 함수 int is_empty(DequeType *q) { return ( q->front == q->rear ); } // 포화 상태 검출 함수 int is_full(DequeType *q) { return (( q->rear + 1) % MAX_QUEUE_SIZE == q->front); } // 덱 큐 출력 함수 void deque_print(DequeType *q) { printf(“DEQUE(front=%d rear=%d) = “, q->front, q->rear); if (!is_empty(q)) { int i = q->front; // i에 현재 q의 front값을 넣어주고 do { i = (i + 1) % (MAX_QUEUE_SIZE); // i의 자리를 1증가 printf(“%d | “, q->data[i]); // 증가한 i 자리에 해당하는 data값을 출력 } while ( i != q->rear); } printf(”

“); } // rear쪽 삽입 함수 void add_rear(DequeType *q, element item) { if (is_full(q)) error(“큐가 포화상태입니다”); q->rear = (q->rear + 1) % MAX_QUEUE_SIZE; // rear값 1 증가 q->data[ q->rear ] = item; } // rear쪽 삭제 함수 element delete_rear(DequeType *q) { int prev = q->rear; if (is_empty(q)) error(“큐가 공백상태입니다”); q->rear = (q->rear – 1 + MAX_QUEUE_SIZE) % MAX_QUEUE_SIZE; // rear값 1감소 return q->data[prev]; } // rear쪽 반환 element get_rear(DequeType *q) { if (is_empty(q)) error(“큐가 공백상태입니다”); return q->data[ q->rear ]; } // front쪽 삽입 함수 void add_front(DequeType *q, element val) { if (is_full(q)) error(“큐가 포화상태입니다”); q->data[ q->front ] = val; q->front = (q->front – 1 + MAX_QUEUE_SIZE) % MAX_QUEUE_SIZE; // front값 1감소 } // front쪽 삭제 함수 element delete_front(DequeType *q) { if (is_empty(q)) error(“큐가 공백상태입니다”); q->front = (q->front + 1) % MAX_QUEUE_SIZE ; // front값 1 증가 return q->data[ q->front ]; } // front쪽 반환 element get_front(DequeType *q) { if (is_empty(q)) error(“큐가 공백상태입니다”); return q->data[ (q->front + 1) % MAX_QUEUE_SIZE ]; } // 메인 int main(void) { DequeType queue; init_deque(&queue); for (int i = 0; i < 3; i++) { add_front(&queue, i); deque_print(&queue); } for (int i = 0; i < 3; i++) { delete_rear(&queue); deque_print(&queue); } return 0; } /* 실행결과 DEQUE(front=4 rear=0) = 0 | DEQUE(front=3 rear=0) = 1 | 0 | DEQUE(front=2 rear=0) = 2 | 1 | 0 | DEQUE(front=2 rear=4) = 2 | 1 | DEQUE(front=2 rear=3) = 2 | DEQUE(front=2 rear=2) = */ 이제 덱을 활용한 문제를 알아봅시다 Palindrome 검사 프로그램 주어진 문자열을 모두 덱에 삽입한 후, 앞과 뒤에서 뽑아 같은지 확인을 반복하여 회문 여부를 출력하시오. int palindrome_check(DequeType* q) { while (!is_empty(q)) { if (delete_front(q) != delete_rear(q)) { return 0; } else { return 1; } } return 1; } int main() { printf("단어 입력 : "); DequeType dq; char str[30]; gets_s(str, 30); init_deque(&dq); for (int i = 0; i < strlen(str); i++) { add_rear(&dq, str[i]); } if (palindrome_check(&dq)) { printf("회문입니다"); } else { printf("회문이 아닙니다"); } return 0; } 기존의 덱을 구현하는 소스코드에서 정수형이 아닌 char형 문자열의 회문을 검사해야 하므로 element를 int로 지정한 부분을 char로 수정합니다. 이외 ADT연산 함수들은 모두 동일합니다. 회문 검사 함수 : 매개변수로 덱 타입 포인터 q를 받습니다. 덱 q의 데이터가 남아있는 한 계속 반복하는 반복문 while에서 만약 q의 front에서 잘라낸 데이터와 q의 rear에서 잘라낸 데이터가 같지 않을 경우 (즉, 남아있는 문자열의 앞 뒤가 다를 경우) 거짓임을 의미하는 0을 출력합니다. 그게 아닌 모든 경우(즉, q의 front에서 잘라낸 데이터와 q의 rear에서 잘라낸 데이터가 같은 경우, 또는 잘라냈는데 문자가 1개 남은 경우)에는 참임을 의미하는 1을 출력합니다 메인 함수 : 덱 타입 dq를 선언하고 입력할 문자 배열을 담을 char배열 str을 30의 공간을 설정하여 선언합니다. gets_s() 함수로 str과 공간30을 넘겨 문자열을 입력받을 수 있도록 하고 dq를 초기화합니다. i는 0부터 str의 길이의 전 까지 1씩 증가하는 반복문 for에서 add_rear()를 통해 dq의 rear에 str 문자배열의 문자들을 하나씩 모두 삽입합니다. 이후 회문 검사 함수로 해당 덱 dq를 넣어 회문인지 아닌지를 판별합니다

[자료구조] 덱(Deque, Double-ended Queue) 설명 및 구현

1. 덱(Deque, Double-ended Queue)

덱은 큐의 양쪽 끝에서 데이터의 삽입과 삭제가 모두 가능하게 만든 큐로서, 스택과 큐의 성질을 모두 가지고 있는 자료구조입니다.

덱의 구조

2. 덱의 연산

덱은 양쪽 끝에서 데이터의 삽입과 삭제 연산을 모두 할 수 있기 때문에, 스택과 큐의 연산을 모두 구현할 수 있습니다.

· 스택 연산

front를 스택의 top으로 생각했을 때, 덱의 insertFront() 연산과 deleteFront() 연산은 push() 연산, pop() 연산과 같습니다.

rear를 스택의 top으로 생각했을 때, 덱의 insertRear() 연산과 deleteRear() 연산은 push() 연산, pop() 연산과 같습니다.

· 큐 연산

insertRear() 연산과 deleteFront() 연산은 일반 큐의 enQueue() 연산, deQueue() 연산과 같습니다.

3. 덱 구현

덱은 양쪽 끝에서 데이터의 삽입과 삭제 연산이 가능해야 하기 때문에, 왼쪽 링크 필드와 오른쪽 링크 필드를 가지는 노드를 사용하는 이중 연결 리스트를 이용하여 구현해야 합니다.

· DQNode

public class DQNode { private char data; // 데이터 필드 public DQNode llink; // 왼쪽 링크 필드 public DQNode rlink; // 오른쪽 링크 필드 public DQNode(char data) { this.data = data; this.llink = null; this.rlink = null; } public char getData() { return this.data; } }

· Deque

public class Deque { private DQNode front; private DQNode rear; // 덱 초기화 public Deque() { this.front = null; this.rear = null; } public boolean isEmpty() { return (front == null); // front가 null인 경우 공백상태 } public void insertFront(char data) { DQNode newNode = new DQNode(data); if (isEmpty()) { // 덱에 노드가 없을 경우 front = newNode; rear = newNode; } else { // 덱에 노드가 한 개 이상 존재할 경우 front.llink = newNode; newNode.rlink = front; front = newNode; } } public void insertRear(char data) { DQNode newNode = new DQNode(data); if (isEmpty()) { // 덱에 노드가 없을 경우 front = newNode; rear = newNode; } else { // 덱에 노드가 한 개 이상 존재할 경우 rear.rlink = newNode; newNode.llink = rear; rear = newNode; } } public char deleteFront() { if (isEmpty()) { // 덱에 노드가 없을 경우 System.out.println(“덱이 공백상태입니다.

“); return 0; } else { // 덱에 노드가 한 개 이상 존재할 경우 char data = front.getData(); if (front.rlink == null) { // 덱에 노드가 한 개일 경우 front = null; rear = null; } else { // 덱에 노드가 두 개 이상일 경우 front = front.rlink; front.llink = null; } return data; } } public char deleteRear() { if (isEmpty()) { // 덱에 노드가 없을 경우 System.out.println(“덱이 공백상태입니다.

“); return 0; } else { // 덱에 노드가 한 개 이상 존재할 경우 char data = rear.getData(); if (rear.llink == null) { // 덱에 노드가 한 개일 경우 front = null; rear = null; } else { // 덱에 노드가 두 개 이상일 경우 rear = rear.llink; rear.rlink = null; } return data; } } public void removeFront() { if (isEmpty()) { // 덱에 노드가 없을 경우 System.out.println(“덱이 공백상태입니다.

“); } else { // 덱에 노드가 한 개 이상 존재할 경우 if (front.rlink == null) { // 덱에 노드가 한 개일 경우 front = null; rear = null; } else { // 덱에 노드가 두 개 이상일 경우 front = front.rlink; front.llink = null; } } } public void removeRear() { if (isEmpty()) { // 덱에 노드가 없을 경우 System.out.println(“덱이 공백상태입니다.

“); } else { // 덱에 노드가 한 개 이상 존재할 경우 if (rear.llink == null) { // 덱에 노드가 한 개일 경우 front = null; rear = null; } else { // 덱에 노드가 두 개 이상일 경우 rear = rear.llink; rear.rlink = null; } } } public char peekFront() { if (isEmpty()) { // 덱에 노드가 없을 경우 System.out.println(“덱이 공백상태입니다.

“); return 0; } else { // 덱에 노드가 한 개 이상 존재할 경우 return front.getData(); } } public char peekRear() { if (isEmpty()) { // 덱에 노드가 없을 경우 System.out.println(“덱이 공백상태입니다.

“); return 0; } else { // 덱에 노드가 한 개 이상 존재할 경우 return rear.getData(); } } // 덱 출력 public void printDeque() { if (isEmpty()) { System.out.println(“덱이 공백상태입니다.

“); } else { DQNode temp = front; System.out.printf(“Deque = “); while (temp != null) { System.out.printf(“%c “, temp.getData()); temp = temp.rlink; } System.out.println(”

“); } } }

· MainForDeque

public class MainForDeque { public static void main(String[] args) { Deque dQ = new Deque(); // insertRear()와 deleteRear()를 사용하여 후입선출 구조인 스택 구현 System.out.println(“***** 덱을 후입선출 구조인 스택처럼 사용하기 *****

“); System.out.println(“1. 원소 3개 푸쉬”); for (char c = ‘A’; c <= 'C'; c++) { dQ.insertRear(c); } dQ.printDeque(); System.out.println("2. 원소 2개를 팝"); for (int i = 0; i < 2; i++) { System.out.printf("Deleted Data: %c ", dQ.deleteRear()); dQ.printDeque(); } System.out.println("3. 원소 1개 삭제"); dQ.deleteRear(); dQ.printDeque(); // insertRear()오 deleteFront()를 사용하여 선입선출 구조인 큐 구현하기 System.out.println("***** 덱을 선입선출 구조인 큐처럼 사용하기 ***** "); System.out.println("1. 원소 3개 인큐"); for (char c = 'A'; c <= 'C'; c++) { dQ.insertRear(c); } dQ.printDeque(); System.out.println("2. 원소 2개를 디큐"); for (int i = 0; i < 2; i++) { System.out.printf("Deleted Data: %c ", dQ.deleteFront()); dQ.printDeque(); } System.out.println("3. 원소 1개 삭제"); dQ.deleteFront(); dQ.printDeque(); } } · 실행 결과

언제나 되돌아보기 언제나 되돌아보기

728×90

반응형

큐를 설명하였으니, 이와 관련 있는 덱을 소개하고자 한다. 스택과 큐의 구조를 이해한 사오항에서 덱의 구조는 한줄로 설명이 가능하며, 양방향 리스트 까지 구현해본 경험이 있으면 덱의 구현을 일일히 설명할 필요는 없다.

덱의 이해와 ADT의 정의

“큐는 뒤로 넣고 앞으로 빼는 자료구조”

이러한 느낌으로 덱을 한 문장으로 설명하면 다음과 같다.

“덱은 앞으로도 뒤로도 넣을 수 있고, 앞으로도 뒤로도 뺄수 있는 자료구조”

이것으로 덱의 구조는 충분히 설명되었다고 생각한다. dequeue은 double -ended queue 를 줄여서 표현한 것으로, 양방향으로 넣고 뺄수 있다는 사실에 초점이 맞춰져서 지어진 이름이다. 어쨋든 덱은 한방향으로 넣고, 양방향으로 뺄 수 있는 자료구조이기에 스택과 큐의 특성을 모두 갖는 , 혹은 스택과 큐를 조합한 형태의 자료구조로 이해되고 있다. 따라서 덱의 ADT를 구성하는 핵심 함수 네 가지의 기능은 다음과 같다.

앞으로 넣기

뒤로 넣기

앞에서 빼기

뒤에서 빼기

그럼 이어서 위의 기능을 중심으로 한 덱의 ADT를 정의하겠다.

void Deque(Deque *pdeq);

-덱의 초기화를 진행한다.

-덱 생성 후 제일 먼저 호출되어야 하는 함수이다.

int DQIsEmpty(Deque *pdeq);

-덱이 빈 경우 TRUE(1)을 , 그렇지 않은 경우 FALSE(0) 을 반환한다.

void DQAddFirst(Deque *pdeq, Data data);

-덱의 머리에 데이터를 저장한다. data로 전달된 값을 저장한다.

void DQAddLast(Deque *pdeq, Data data);

-덱의 꼬리에 데이터를 저장한다. data로 전달된 값을 저장한다.

Data DQRemoveFirst(Deque * pdeq);

-덱의 꼬리에 위치한 데이터를 반환 및 소멸한다.

Data DQRemoveLast(Deque *pdeq);

-덱의 머리에 위치한 데이터를 소멸하지 않고 반환한다.

Data DQGetLast(Deque *pdeq);

-덱의 꼬리에 위치한 데이터를 소멸하지 않고 반환한다.

참고로 Deque ‘디큐’로 읽기 쉽다. 그럼에도 불구하고 ‘덱’으로 발음하는 이유는 ‘디큐’로 발음할 경우 큐의 dequeue연산과 그 발음이 같아져서 이 둘을 구분하기 어렵기 때문이다. 물론 ‘디큐’로 읽는 사람도 있다. 그러나 혼란을 줄 수 있으므로 가급적 ‘덱’으로 읽기 바란다.

덱의 구현

덱의 구현을 위해서 우선적으로 해야 할 일은 헤더파일의 정의이다. 그런데 헤더파일을 정의하기 위해서는 구현할 덱의 구조를 결정해야 한다. 물론 덱도 배열을 기반으로, 그리고 연결리스트를 기반으로도 구현이 가능하다. 하지만 우리는 덱의 구현에 가장 어울린다고 알려진 ‘양방향 연결 리스트’를 기반으로 덱을 구현할 것이다. 양방향 연결 리스트가 , 단방향 연결리스트보다 덱의 구현에 더 잘 어울리는 이유는 다음 함수의 구현과 관련이 있다.

Data DQRemoveLast(Deque *pdeq); //꼬리에 위치한 데이터(노드) 삭제

위의 함수는 꼬리에 위치한 노드를 삭제하는 함수인데, 노드가 양방향으로 연결되어 있지 않으면 꼬리에 위치한 노드의 삭제는 간단하지 않다. 때문에 덱의 구현에 있어서 양방향 연결 리스트는 매우 좋은 선택이라 할 수 있다.

그럼 양방향 연결 리스트 기반의 덱을 위한 헤더파일을 정의하겠다.

//Deque.h #ifndef __DEQUE_H__ #define __DEQUE_H__ #define TRUE 1 #define FALSE 0 typedef int Data; typedef struct _node { Data data; struct _node * next; struct _node * prev; }Node; typedef struct _dlDeque { Node *head; Node *tail; }DLDeque; typedef DLDeque Deque; void DequeInit(&Deque *pdeq); int DQIsEmpty(Deque *pdeq); void DQAddFirst(Deque *pdeq, Data data); //덱의 머리에 데이터 추가 void DQAddLast(Deque *pdeq, Data data); //덱의 꼬리에 데이터 추가 Data DQRemoveFirst(Deque *pdeq); //덱의 머리에서 데이터 삭제 Data DQRemoveLast(Deque *pdeq); //덱의 꼬리에서 데이터 삭제 Data DQGetFirst(Deque *pdeq); //덱의 머리에서 데이터 참조 Data DQGetLast(Deque *pdeq); //덱의 꼬리에서 데이터 참조 #endif

위의 헤더파일에 정의된 구조체 Node를 보면 양방향 연결 리스트를 기반으로 덱이 구현됨을 알 수 있고, 구조체 DLDeque을 보면 head와 tail이 각각 리스트의 머리와 꼬리를 가리키게 됨을 알 수 있다. 즉 다음 구조의 양방향 연결리스트를 구현할 생각이다.

head->2-><-4-><-6-><-8-><-10<-tail 2의 prev와 10의 next 에는 NULL이 저장되어 있음 그런데 앞서 우리는 다음과 같이, 꼬리를 가리키는 포인터 변수 tail이 없는 구조로 양방향 연결 리스트를 구현한바가 있다. head->2-><-4-><-6-><-8-><-10->NULL

2의 prev에는 NULL

이 둘의 유일한 차이점은 포인터 변수 tail을 둬서 리스트의 꼬리를 가리키게 하느냐 마느냐에 있다.

물론 tail의 유무를 제외하고 구조적으로는 그 형태가 동일하지만 ADT에 정의된 함수가 다르기 때문에 코드까지 완전히 동일하지는 않다. 하지만 이전에 구현한 내용을 참조하여 쉽게 덱을 구현할 수 있다.

//Deque.c #include #include #include “Deque.h” void DequeInit(Deque *pdeq) { pdeq->head= NULL; pdeq->tail= NULL; } int DQIsEmpty(Deque *pdeq) { if(pdeq->head == NULL0 //head가 NULL이면 비어있는 덱 return TRUE; else return FALSE; } void DQAddFirst(Deque *pdeq, Data data) { Node *newNode =(Node*)malloc(sizeof(Node)); newNode->data = data; newNode->next = pdeq->head; if(DQIsEmpty(pdeq)) pdeq->tail= newNode; else pdeq->head->prev= newNode; newNode->prev=NULL; pdeq->head = newNode; } void DQAddLast(Deque *pdeq, Data data) { Node * newNode= (Node *)malloc(sizeof(Node)); newNode->data= data; newNode->prev= pdeq->tail; if(DQIsEmpty(pdeq)) pdeq->head= newNode; else pdeq->tail->next= newNode; newNode->next= NULL; pdeq->tail= newNode; } Data DQRemoveFirst(Deque *pdeq) { Node *rnode= pdeq->head; Data rdata; if(DQIsEmpty(pdeq)) { printf(“Deque Memory Error!”); exit(-1); } rdata= pdeq->head->data; pdeq->head= pdeq->head->next; free(rnode); if(pdeq->head ==NULL) pdeq->tail = NULL; else pdeq->head->prev =NULL; return rdata; } Data DQRemoveLast(Deque * pdeq) { Node *rnode = pdeq->tail; Data rdata; if(DQIsEmpty(pdeq)) { printf(“Deque Memory Error!”); exit(-1); } rdata= pdeq->tail->data; pdeq->tail = pdeq->tail->prev; free(rnode); if(pdeq->tail == NULL) pdeq->head = NULL; else pdeq->tail->next= NULL; return rdata; } Data DQGetFirst(pdeq) { if(DQIsEmpty(pdeq)) { printf(“Deque Memory Error!”); exit(-1); } return pdeq->head->data; } Data DQGetLast(pdeq) { if(DQIsEmpty(pdeq)) { printf(“Deque Memory Error!”); exit(-1); } return pdeq->tail->data; }

//DequeMain.c #include #include “Deque.h” int main() { //Deque의 생성 및 초기화 Deque deq; DequeInit(&deq); //데이터 넣기 1차 DQAddFirst(&deq, 3); DQAddFirst(&deq, 2); DQAddFirst(&deq, 1); DQAddLast(&deq, 4); DQAddLast(&deq, 5); DQAddLast(&deq, 6); //데이터 꺼내기 1차 while(!DQIsEmpty(&deq)) printf(“%d “, DQRemoveFirst(&deq)); printf(”

“); //데이터 넣기 2차 DQAddFirst(&deq, 3); DQAddFirst(&deq, 2); DQAddFirst(&deq, 1); DQAddLast(&deq, 4); DQAddLast(&deq, 5); DQAddLast(&deq, 6); //데이터 꺼내기 2차 while(!DQIsEmpty(&deq)) printf(“%d “, DQRemoveLast(&deq)); return 0; } ==========================실행결과======================= 1 2 3 4 5 6 6 5 4 3 2 1

위의 main함수에서는 덱을 대표하는 4개의 함수를 확인하기 위해서, 데이터를 덱의 머리와 꼬리에 넣어보고, 또 이를 머리에서 그리고 꼬리에서 꺼내어 그 결과를 출력하였다.

728×90

반응형

키워드에 대한 정보 자료 구조 덱

다음은 Bing에서 자료 구조 덱 주제에 대한 검색 결과입니다. 필요한 경우 더 읽을 수 있습니다.

이 기사는 인터넷의 다양한 출처에서 편집되었습니다. 이 기사가 유용했기를 바랍니다. 이 기사가 유용하다고 생각되면 공유하십시오. 매우 감사합니다!

사람들이 주제에 대해 자주 검색하는 키워드 [바킹독의 실전 알고리즘] 0x07강 – 덱

  • 알고리즘
  • 코딩테스트
  • 기술면접
  • 프로그래밍
  • 백준
  • 프로그래머스
  • 자료구조
  • 공채
  • 개발자
  • 역량테스트
  • SW 역량테스트
  • 삼성전자 역량테스트
  • 알고리즘 시험
  • 소프트웨어 역량테스트
  • 카카오 블라인드 코딩
  • 블라인드 코딩
  • 코드포스
  • SCPC
  • ICPC
  • 알고리즘 면접
  • 기술 면접
  • deque
  • c++ deque
  • C++ 덱
  • C++ 덱 vs 벡터
  • C++ deque vs vector
  • 자료구조 덱
[바킹독의 #실전 #알고리즘] #0x07강 #- #덱


YouTube에서 자료 구조 덱 주제의 다른 동영상 보기

주제에 대한 기사를 시청해 주셔서 감사합니다 [바킹독의 실전 알고리즘] 0x07강 – 덱 | 자료 구조 덱, 이 기사가 유용하다고 생각되면 공유하십시오, 매우 감사합니다.

See also  사회 복지사 지원 동기 | 사회복지사 이력서 실제 사례 9112 투표 이 답변

Leave a Reply

Your email address will not be published. Required fields are marked *