2 minute read

큐(Queue)란?

정의

  • 맥도날드 줄 서기 같은 것
  • 먼저 들어온 아이템이 먼저 나가는, 선입선출(First In, First Out)

기능

  • Enqueue(아이템 삽입)
  • Dequeue(아이템 빼기)

문제점 1

오늘은 좀 더 기본적인 Queue에 대해 정리하려고 한다. 큐(Queue)는 선입선출 방식의 자료구조로, 가장 베이직 한 자료구조 중 하나이다. 아이템을 선형적으로 저장하면 Linear Queue, 원형으로 저장하면 Circular Queue라고 한다. 그럼 원형큐는 왜 쓸까?

Enqueue와 Dequeue가 반복적으로 발생하는 상황을 생각해보자.

1

Queue는 front와 rear 포인터를 통해 Enqueue와 Dequeue를 수행한다. front 포인터는 데이터의 맨 앞을, rear는 새로 들어온 데이터를 가리킨다. Dequeue를 할 때, 배열 안에 있는 데이터가 사라지는 것은 아니고, 이 포인터의 이동으로만 이루어지기 때문에, front와 rear 포인터가 배열의 맨 끝에 다다르면 더이상 데이터를 추가할 수 없게 된다.

뿐만 아니라 front의 앞 배열의 공간은 그대로 할당 되어 있는데, 데이터를 추가하겠다고 일일이 배열의 크기를 늘려줄 수도 없는 노릇이다.

그렇다면 한정된 배열의 자원에서 큐라는 구조를 유지하려면?

2

답은, “원형 형태로 돌리면 된다.”

if(rear == maxQueue -1) //rear이 배열의 맨 끝에 다다르면, 
	rear = 0; //배열의 맨 앞으로 간다
else
	rear += 1; //그렇지 않으면 전진

더 쉽게 짜는 방법도 있다.

rear = (rear + 1) % maxQueue; 

문제점2

자료구조를 구현할 때, 항상 들어가는 기능 중 ‘IsFull(새로운 아이템을 추가할 수 있는가?)’과, ‘IsEmpty(아이템을 더 삭제할 수 있는가?)’가 있다. 해당 기능 없이 함부로 데이터의 삽입/삭제가 일어나면 메모리 영역을 침범하여 에러가 발생하기 십상이기 때문이다. 그럼 여기서 큐의 IsFull과 IsEmpty는 어떻게 구현할 것인가?

IsFull

3

arr[2]에 5, arr[3]에 10, arr[0]에 20이 들어있는 상황에서 arr[1]에 30이 들어왔다(원형큐라는 걸 눈치채셨길!). rear + 1 == front이므로, 더이상 데이터를 추가할 수 없다.

IsEmpty

4

이번엔 Deuque를 통해 배열의 모든 아이템을 빼냈다. 어? 그런데 rear + 1 == front로, IsFull의 상태와 동일하다!

그렇다. 해당 원형큐에서는 IsFull과 IsEmpty를 구분할 수 없는 큰 문제가 있다.

해결 방법은? 공간 하나를 버리면 된다.

front == rear일 때를 Empty 상태로 만들기 위해 배열의 한 칸을 비워둔다.

IsFull

5

이렇게. Enqueue를 한들, rear는 front에 저장된 공간을 덮어쓸 수 없다.

즉, if(IsFull()==true){rear + 1 = front)};

IsEmpty

6

초기상태와 동일하게, front와 rear가 같은 공간을 가리키고 있다면, Empty 상태가 된다.

즉, if(IsEmpty()==true){rear == front)};

구현

초기화

7

QueType(int max){
	maxQueue = max + 1;
	front = maxQueue - 1; //배열의 맨 끝에서 시작
	rear = maxQueue - 1; //배열의 맨 끝에서 시작
	items = new ItemType[maxQueue];
}

Enqueue & Dequeue

Enqueue(ItemType newItem){
	rear = (rear+1)%maxQueue;
	items[rear] = newItem;
}

Dequeue(ItemType &item){
	front = (front+1)%maxQueue;
	item = items[front];
}

전체 코드

#include "ItemType.h"

template<class ItemType>
class QueType
{
	public:
		QueType();
		QueType(int max);
		~QueType();
		bool IsEmpty();
		bool IsFull() const;
		void Enqueue(ItemType newItem);
		void Dequeue(ItemType& item); //변수 item에 Dequeue한 아이템 저장
	private:
		int front;
		int rear;
		int maxQueue;
		ItemType* items;
}

template<class ItemType>
QueType<ItemType>::QueType(int max){
	maxQue = max + 1;
	front = maxQueue - 1;
	rear = maxQueue - 1;
	items = new ItemType[maxQueue];
}

template<class ItemType>
QueType<ItemType>::~QueType(){
	delete [] items;
}

template<class ItemType>
bool QueType<ItemType>::IsEmpty(){
	return (rear == front);
}

template<class ItemType>
bool QueType<ItemType>::IsFull(){
	return ((rear+1) % maxQueue == front);
}

template<class ItemType>
void QueType<ItemType>::Enqueue(ItemType newItem){
	rear = (rear+1) % maxQueue;
	items[rear] = newItem;
}

tempalte<class ItemType>
void QueType<ItemType>::Dequeue(ItemType newItem){
	front = (front+1) % maxQueue;
	item = items[front];
}

Leave a comment