큐 (Queue)
큐 (Queue)
큐(Queue)란?
선입선출(FIFO, First In First Out) 구조를 따르는 선형 자료구조
즉, 가장 먼저 삽입된 데이터가 가장 먼저 삭제되는 방식으로 동작하며, 줄 서기나 버퍼와 같은 형태
넓이 우선 탐색(BFS), 프린터 대기열 관리, CPU 작업 스케줄링 등 순서가 중요한 작업에 자주 사용
주요 연산
- enqueue: 큐의 뒤에 새로운 요소를 추가
- dequeue: 큐의 앞에 있는 요소를 제거하고 반환
- peek 또는 front: 큐의 앞에 있는 요소를 반환 (제거하지 않음)
- isEmpty: 큐가 비어 있는지 확인
- size: 큐에 있는 요소의 개수를 반환
특징
- 선입선출 (FIFO): 가장 먼저 삽입된 요소가 가장 먼저 제거됩니다.
- 양쪽 접근 제한: 삽입과 삭제가 큐의 양 끝에서만 이루어짐
- 연산의 단순성: 삽입과 삭제 연산 시간 복잡도가 O(1)
장점
- 순서 보장: 큐는 데이터의 순서를 유지하며, 순차적으로 처리
- 효율적 데이터 흐름 관리: 데이터가 들어오는 순서대로 처리할 때 효율적
단점
- 중간 접근 불가: 큐의 중간에 있는 요소를 접근하거나 수정할 수 없음
- 제한된 탐색 기능: 큐는 순차 접근만 가능하므로, 특정 요소를 검색하는 데 비효율적
구현 예시
배열을 이용한 구현
큐의 front와 rear를 사용하여 요소를 관리
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
#include <iostream>
using namespace std;
#define MAX 5 // 큐의 최대 크기
class Queue {
int front, rear;
int arr[MAX];
public:
Queue() {
front = -1;
rear = -1; // 초기화
}
// 큐가 비어있는지 확인
bool isEmpty() {
return front == -1;
}
// 큐가 가득 찼는지 확인
bool isFull() {
return rear == MAX - 1;
}
// 큐에 요소 추가
void enqueue(int value) {
if (isFull()) {
cout << "Queue is Full\n";
return;
}
if (front == -1) front = 0; // 첫 번째 요소 삽입 시 front 초기화
arr[++rear] = value; // rear를 증가시키고 요소 추가
cout << value << " enqueued to queue\n";
}
// 큐에서 요소 제거
void dequeue() {
if (isEmpty()) {
cout << "Queue is Empty\n";
return;
}
cout << arr[front] << " dequeued from queue\n";
front++;
if (front > rear) { // 큐가 비면 초기화
front = rear = -1;
}
}
// 큐의 맨 앞 요소 반환
int peek() {
if (isEmpty()) {
cout << "Queue is Empty\n";
return -1;
}
return arr[front];
}
// 큐 출력
void printQueue() {
if (isEmpty()) {
cout << "Queue is Empty\n";
return;
}
cout << "Queue: ";
for (int i = front; i <= rear; i++) {
cout << arr[i] << " ";
}
cout << endl;
}
};
int main() {
Queue q;
q.enqueue(10);
q.enqueue(20);
q.enqueue(30);
q.printQueue(); // Queue: 10 20 30
q.dequeue();
q.printQueue(); // Queue: 20 30
return 0;
}
라이브러리
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <iostream>
#include <queue>
using namespace std;
int main() {
queue<int> q;
// 요소 삽입
q.push(10);
q.push(20);
q.push(30);
cout << "큐의 맨 앞 요소: " << q.front() << endl; // 10
cout << "큐의 맨 뒤 요소: " << q.back() << endl; // 30
// 요소 제거
q.pop(); // 10 제거
cout << "큐의 맨 앞 요소 (제거 후): " << q.front() << endl; // 20
return 0;
}
원형 큐(Circular Queue)란?
고정된 크기의 배열을 사용하여, 큐의 앞과 뒤가 연결된 순환 구조
일반 큐는 사용하지 않는 공간이 발생할 수 있지만, 원형 큐는 메모리 낭비가 발생하지 않음
특징
- 순환 구조: 배열의 끝에 도달하면 다시 처음으로 이동하여 빈 공간을 채움
- 메모리 효율: 원형 큐는 모든 공간을 활용하여 메모리 낭비를 줄임
- Front와 Rear의 순환 갱신: rear와 front의 인덱스가 배열의 끝에 도달하면, 다시 0으로 갱신되어 계속해서 삽입 및 삭제 가능
선형 큐의 front와 rear값이 계속 증가하기만 한다는 문제점을 극복한 구조
사용 예시
- 네트워크 패킷 버퍼: 고정된 크기의 버퍼에서 패킷을 관리하여 메모리 효율성을 높임
- 데이터 스트림 처리 (Data Stream Handling): 데이터 스트림을 관리할 때 데이터가 순환적으로 처리되도록 하는 데 사용
실시간 데이터가 계속 입력되고, 일정 시간 후 오래된 데이터가 삭제되는 경우에 유용 (센서, 로그 등) - 캐시 구현 (Circular Buffer Cache): 브라우저 캐시, 최근 사용한 파일 목록 관리 등에서 새 항목이 들어오면 가장 오래된 항목이 제거되도록 함
데이터가 순환해야 하거나, 제한된 메모리에서 큐를 효율적으로 사용할 때 유리
구현 예시
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
#include <iostream>
using namespace std;
#define SIZE 5
class CircularQueue {
int front, rear;
int arr[SIZE];
public:
CircularQueue() {
front = rear = -1;
}
// 큐가 비어있는지 확인
bool isEmpty() {
return front == -1;
}
// 큐가 가득 찼는지 확인
bool isFull() {
return (rear + 1) % SIZE == front;
}
// 요소 추가 (enqueue)
void enqueue(int value) {
if (isFull()) {
cout << "Queue is Full\n";
return;
}
if (front == -1) front = 0;
rear = (rear + 1) % SIZE;
arr[rear] = value;
cout << value << " enqueued to queue\n";
}
// 요소 제거 (dequeue)
void dequeue() {
if (isEmpty()) {
cout << "Queue is Empty\n";
return;
}
cout << arr[front] << " dequeued from queue\n";
if (front == rear) front = rear = -1;
else front = (front + 1) % SIZE;
}
// 큐의 맨 앞 요소 반환
int peek() {
if (isEmpty()) return -1;
return arr[front];
}
};
int main() {
CircularQueue q;
q.enqueue(10);
q.enqueue(20);
q.enqueue(30);
q.dequeue(); // 10 dequeued
q.enqueue(40);
q.enqueue(50);
q.dequeue(); // 20 dequeued
q.enqueue(60); // 원형 큐에서 메모리 재활용
return 0;
}
std::deque라이브러리를 사용하면 원형 큐와 유사한 기능을 손쉽게 구현 가능
This post is licensed under CC BY 4.0 by the author.