C언어로 쉽게 풀어쓴 자료구조

[C언어로 쉽게 풀어쓴 자료구조] 5장 큐

studyingalone 2024. 11. 16. 14:33
728x90

C언어로 쉽게 풀어쓴 자료구조: 5장 큐(선형, 원형),덱

큐(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)) queue_full 오류;
    else q의끝에 e를 추가한다. 
dequeue(q) = 
	if(is_empty(q)) queue_empty 오류;
    else q의 맨 앞에 있는 e를 제거하여 반환한다.
peek(q) =
	if(is_empty(q)) queue_empty 오류;
    else q의 맨 앞에 있는 e를 읽어서 반환한다.

 

 


5.2 선형큐

위에서 설명한 간단하게 생긴 큐가 선형큐이다.

#include <stdio.h>
#include <stdlib.h>
#define MAX_QUEUE_SIZE 5

typedef int element;
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)
{
	if (is_full(q)) {
		error("큐가 포화상태입니다.");
		return;
	}
	q->data[++(q->rear)] = item;
}

int dequeue(QueueType *q)
{
	if (is_empty(q)) {
		error("큐가 공백상태입니다.");
		return -1;
	}
	int item = q->data[++(q->front)];
	return item;
}

 

선형 큐는 쓰기 쉽지만 문제점이 있다.

  1. front와 rear의 값이 계속 증가만 하기 때문에 언젠가는 배열의 끝에 도달하게 된다.
  2. 배열의 앞부분이 비어 있더라도 사용하지 못한다

이를 보완하기 위해 배열의 끝네 도달하면 배열의 처음으로 데이터를 이동시키는 방법이 있다.

하지만 이보다 간단한 해결책은 원형큐를 사용하는 것이다.


5.3 원형큐

데이터 삽입, 삭제 전 front(가장 처음 들어간)와 rear(가장 최근에 들어간)을 원형으로 회전 시킨다.

front는 항상 큐의 첫 번째 요소의 하나 앞을, rear는 마지막 요소(가장 최근에 들어간 값)를 가리킨다.

원형큐의 삽입, 삭제 과정, 출처: c언어로 쉽게 풀어쓴 자료구조

 

말이 원형이지 실제로 원형이 아니다...

선을 원처럼 사용한다는 의미..

 

10 삽입

 

20 삽입

 

삭제

 

➡️ 큐의 front가 rear보다 커지면 포화상태가 되어 오류 발생

 

 

원형큐 프로그램

#include <stdio.h>
#include <stdlib.h>

// ===== 원형큐 코드 시작 ======
#define MAX_QUEUE_SIZE 5
typedef int element;
typedef struct { // 큐 타입
	element  data[MAX_QUEUE_SIZE];
	int  front, rear;
} QueueType;

// 오류 함수
void error(char *message)
{
	fprintf(stderr, "%s\n", message);
	exit(1);
}

// 공백 상태 검출 함수
void init_queue(QueueType *q)
{
	q->front = q->rear = 0;
}

// 공백 상태 검출 함수
int is_empty(QueueType *q)
{
	return (q->front == q->rear);
}

// 포화 상태 검출 함수
int is_full(QueueType *q)
{
	return ((q->rear + 1) % MAX_QUEUE_SIZE == q->front);
}

// 원형큐 출력 함수
void queue_print(QueueType *q)
{
	printf("QUEUE(front=%d rear=%d) = ", q->front, q->rear);
	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");
}

// 삽입 함수
void enqueue(QueueType *q, element item)
{
	if (is_full(q))
		error("큐가 포화상태입니다");
	q->rear = (q->rear + 1) % MAX_QUEUE_SIZE;
	q->data[q->rear] = item;
}

// 삭제 함수
element dequeue(QueueType *q)
{
	if (is_empty(q))
		error("큐가 공백상태입니다");
	q->front = (q->front + 1) % MAX_QUEUE_SIZE;
	return q->data[q->front];
}

// 삭제 함수
element peek(QueueType *q)
{
	if (is_empty(q))
		error("큐가 공백상태입니다");
	return q->data[(q->front + 1) % MAX_QUEUE_SIZE];
}
// ===== 원형큐 코드 끝 ======

int main(void)
{
	QueueType queue;
	int element;

	init_queue(&queue);
	printf("--데이터 추가 단계--\n");
	while (!is_full(&queue))
	{
		printf("정수를 입력하시오: ");
		scanf("%d", &element);
		enqueue(&queue, element);
		queue_print(&queue);
	}
	printf("큐는 포화상태입니다.\n\n");

	printf("--데이터 삭제 단계--\n");
	while (!is_empty(&queue))
	{
		element = dequeue(&queue);
		printf("꺼내진 정수: %d \n", element);
		queue_print(&queue);
	}
	printf("큐는 공백상태입니다.\n");
	return 0;
}

 


5.4 큐의 응용: 버퍼

서로 다른 속도로 실행되는 두 프로세스 간의 상호 작용을 조화시키는 버퍼 역할을 담당한다.

 


5.5 덱 

덱(deaue)이란?

큐의 전단(front)과 후단(rear)에서 모두 삽입과 삭제가 가능한 큐를 의미한다.

 

 

덱의 ADT

create(max_size) = 덱을성한다.
init(dq) = 큐를 초기화 한다.
is_empty(dq) = 덱이 공백 상태인지 검사한다.
is_full(dq) = 덱이 포화상태인지 검사한다.
add_front(dq, e) = 덱의 앞에 요소를 추가
add_rear(dq, e) = 덱의 뒤에 요소를 추가
delete_front(dq, e) = 덱의 앞에 요소를 반환한 후 삭제
delete_rear(dq, e) = 덱의 뒤에 요소를 반환한 후 삭제
get_front(dq) = 덱의 앞에 요소를 반환
get_rear(dq) = 덱의 뒤에 요소를 반환

 

 

원형 덱 프로그램

#include <stdio.h>
#include <stdlib.h>

#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\n", 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;
		do {
			i = (i + 1) % (MAX_QUEUE_SIZE);
			printf("%d | ", q->data[i]);
			if (i == q->rear)
				break;
		} while (i != q->front);
	}
	printf("\n");
}

// 삽입 함수
void add_rear(DequeType *q, element item)
{
	if (is_full(q))
		error("큐가 포화상태입니다");
	q->rear = (q->rear + 1) % MAX_QUEUE_SIZE;
	q->data[q->rear] = item;
}

// 삭제 함수
element delete_front(DequeType *q)
{
	if (is_empty(q))
		error("큐가 공백상태입니다");
	q->front = (q->front + 1) % MAX_QUEUE_SIZE;
	return q->data[q->front];
}

// 삭제 함수
element get_front(DequeType *q)
{
	if (is_empty(q))
		error("큐가 공백상태입니다");
	return q->data[(q->front + 1) % MAX_QUEUE_SIZE];
}

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;
}

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;
	return q->data[prev];
}

element get_rear(DequeType *q)
{
	if (is_empty(q))
		error("큐가 공백상태입니다");
	return q->data[q->rear];
}

 

 

 

728x90
반응형