queue
"매표소의 대기열"
큐의 구조
큐의 특징
FIFO (First-In First-Out)(선입선출)
큐의 용도
직접적인 응용
- 시뮬레이션의 대기열
- 통신에서의 데이터 패킷들의 모델링
- 프린터와 컴퓨터 사이의 버퍼링
간접적인 응용
- 프로그래머의 도구로써 많은 알고리즘에 사용
큐 ADT
create(max_size)
- 최대 크기가 max_size인 공백큐 생성
init(q)
- 큐 초기화
is_empty(q)
- if (size == 0) return TRUE;
else return FALSE;
is_full(q)
- if (size == max_size) return TRUE;
else return FALSE;
enqueue(q, e)
- if (is_full(q)) full로 인한 오류;
else q의 끝에 e를 추가
dequeue(q)
- if (is_empty(q)) empty로 인한 오류;
else q의 맨 앞에 있는 e를 제거하여 return
peek(q)
- if (is_empty(q)) empty로 인한 오류;
else q의 맨 앞에 있는 e를 읽어서 return
큐 동작원리
create(5)
init()
enqueue(7)
enqueue(3)
enqueue(2)
dequeue()
dequeue()
dequeue()
// front는 항상 첫번째 요소 하나 앞의 인덱스값 갖게 된다
-> 삽입이나 삭제 둘 다 유사한 연산과정을 가지게 하기 위해
// empty() - front == rear
// full() - rear == MAX_SIZE - 1
-> 어떠한 경우에도 무조껀 rear가 마지막 index 가리키면 포화상태로 간주
배열을 이용한 큐 실제 구현 - 1. 선형큐
#include <stdio.h>
#include <stdlib.h>
#define MAX_QUEUE_SIZE 5
typedef int element; // 언제든 큐 data type을 손쉽게 변경해주기 위해
typedef struct {
int front;
int rear;
element data[MAX_QUEUE_SIZE];
} QueueType;
// 오류함수
void error(char *message)
{
fprintf(stderr, "%s\n", message);
exit(1)
}
// 큐 초기화
void init_queue(QueueType *q)
{
q->rear = -1;
q->front = -1;
}
// 현재 큐 현황 출력 함수
void queue_print(QueueType *q)
{
for (int i = 0; i < MAX_QUEUE_SIZE; i++) {
if (i <= q->front || i > q->rear)
printf(" | ");
else
printf("%d | ", q->data[i]);
}
printf("\n");
}
// 큐 포화상태 확인
int is_full(QueueType *q)
{
if (q->rear == MAX_QUEUE_SIZE - 1)
return 1;
else
return 0;
}
// 큐 공백상태 확인
int is_empty(QueueType *q)
{
if (q->front == q->rear)
return 1;
else
return 0;
}
// 큐 데이터 추가
void enqueue(QueueType *q, int item)
{
// error 처리
if (is_full(q)) {
printf("큐가 포화상태 입니다.");
return;
}
q->data[++(q->rear)] = item;
// q->rear++;
// q->data[q->rear] = item;
}
// 큐 데이터 삭제
void enqueue(QueueType *q)
{
// error 처리
if (is_full(q)) {
printf("큐가 공백상태 입니다.");
return -1;
}
return q->data[++(q->front)];
}
// 메인 함수 사용자 사용
int main(void)
{
int item = 0;
QueueType q;
init_queue(&q);
enqueue(&q, 10); queue_print(&q);
//...
dequeue(&q); queue_print(&q);
//...
return 0;
}
// 현재 큐 현황 출력 함수에서 빈공간 출력 원리
선형큐의 문제점
앞 부분이 비어있게 되므로 효율적으로 사용하기 위해서
모든 요소들을 왼쪽으로 옮겨야 한다
-> 선형 큐의 단점을 보완 - 원형 큐
배열을 이용한 큐 실제 구현 - 2. 원형큐
선형큐와 다른점
- front와 rear init -> not -1 -> 0
- 포화상태 일 때 front == (rear+1) % M -> %M이 추가
- 공백상태와 포화상태를 구별하기 위해 하나의 공간은 항상 비워두며 front는 항상 제일 앞 data의 바로 앞에 있는 빈 공간을 가리킨다.
#include <stdio.h>
#include <stdlib.h>
#define MAX_QUEUE_SIZE 5
typedef int element; // 언제든 큐 data type을 손쉽게 변경해주기 위해
typedef struct {
int front;
int rear;
element data[MAX_QUEUE_SIZE];
} QueueType;
// 오류함수
void error(char *message)
{
fprintf(stderr, "%s\n", message);
exit(1)
}
// 큐 초기화
void init_queue(QueueType *q)
{
q->rear = 0; // -1 -> 0
q->front = 0; // -1 -> 0
}
// 현재 큐 현황 출력 함수
void queue_print(QueueType *q)
{
if (!is_empty(q)) { // 돌아가는건 그림 그려서 예시들어서 하면 쉬움
int i = q->front;
do {
i = (i + 1) % MAX_QUEUE_SIZE;
printf("%d | ", q->data[i]);
if (i == q->rear)
break;
} while(i != q->front);
}
printf("\n");
}
// 큐 포화상태 확인
int is_full(QueueType *q)
{
if (q->front == (q->rear+1) % MAX_QUEUE_SIZE) // 선형 큐와 다름
return 1;
else
return 0;
}
// 큐 공백상태 확인
int is_empty(QueueType *q)
{
if (q->front == q->rear)
return 1;
else
return 0;
}
// 큐 데이터 추가
void enqueue(QueueType *q, int item)
{
// error 처리
if (is_full(q)) {
printf("큐가 포화상태 입니다.");
}
q->rear = (q->rear + 1) % MAX_QUEUE_SIZE; // 추가 방법 다름
q->data[q->rear] = item;
}
// 큐 데이터 삭제
void enqueue(QueueType *q)
{
// error 처리
if (is_full(q)) {
printf("큐가 공백상태 입니다.");
return -1;
}
q->front = (q->front + 1) % MAX_QUEUE_SIZE; // 삭제 방법 다름
return q->data[q->front];
}
// 메인 함수 사용자 사용
int main(void)
{
int item = 0;
QueueType q;
init_queue(&q);
enqueue(&q, 10); queue_print(&q);
//...
dequeue(&q); queue_print(&q);
//...
return 0;
}
'CS > Data Structure & Algorithm' 카테고리의 다른 글
[String] 1. 문자 찾기 (0) | 2022.08.04 |
---|---|
List (0) | 2021.12.02 |
deque (0) | 2021.12.02 |
Stack (0) | 2021.11.23 |
Recursion (<-> Iteration) (0) | 2021.11.23 |