happy coding

[lecture] 큐 본문

lecture/data structure

[lecture] 큐

yeoonii 2023. 1. 9. 13:28

큐란 스택과 마찬가지로 삽입과 삭제의 위치가 제한되어 있는 유한 순서 리스트이다. 큐의 뒤에서는 삽입만 하고, 앞에서는 삭제만 할 수 있는 구조이다. > 삽입한 순서대로 원소가 나열되어 가장 먼저 삽입한 원소는 맨 앞에 있다가 가장 먼저 삭제된다. > 선입선출구조

선형 큐

스택이 연탄이면, 큐는 한줄서기 > push. pop : enQueue. deQueue

모든 자료구조는 array(seq structure)와 linked list 로 이루어져 있다.

초기상태(공백 큐)는 front = rear = -1 이다. 삽입된 상태(enQueue(Q,A))에서는 rear가 A를 가리키고, enQueue(Q,B)에서는 rear가 B를 가리키는 상태가 된다. 원소를 삭제할 때(deQueue(Q))는 front를 A에 위치시킨다음 그 A를 삭제시킨다. 다시말해 front index = 1st element - 1 이 되고, rear index = last element index 가 된다. 그 상태에서 C를 삽입하려면 그 위치로 rear index를 하나 증가시킨 후 그 위치에 C를 삽입시킨다. 뺄 때는 index를 하나 증가시키고 거기 있는 것을 삭제하면 된다. 그렇다면 front는 빈 곳을 가리키게 된다. 이 상태를 overhead 라고 하며 불편한 상황이라고 본다.

위에서 말한 1차원 배열을 이용한 큐를 선형 큐라고 한다. 큐의 크기는 배열의 크기와 같고, 변수의 front는 저장된 첫 번째 원소의 인덱스를 저장하며, 변수 rear는 저장된 마지막 원소의 인덱스를 저장한다. 이 상태를 표현할 때, 초기 상태는 front = rear = -1, 공백 상태는 front = rear 그리고 포화 상태는 rear = 배열의 크기 - 1 = 배열의 마지막 인덱스 라고 한다.

#define MAX_QUEUE_SIZE 100
typedef struct{
	int key;
    /* other fields */
} element;
element queue[MAX_QUEUE_SIZE];
int rear = -1;
int front = -1;
//IsEmptyQ(queue)
return (front == rear)
//IsFullQ(queue)
return rear == (MAX_QUEUE_SIZE - 1)
//add to a queue
void addq(int *prear, element item){
	if(*prear == MAX_QUEUE_SIZE - 1){
    	queue_full();
        return;
    }
    queue[++*prear] = item;
}
//delete from a queue
element deleteq(int *pfront, int rear){	//empty check를 위해서
	if(*pfront == rear)
    	return queue_empty();
    return queue[++*front];
}

(실제로는 queue full은 없다, 인덱스를 앞으로 땡기면 해결되기 때문이다. 하지만 이러한 이동 작업은 연산이 복잡해 효율성이 떨어진다.)

//초기 상태 큐 생성 알고리즘
/* 크기가 n인 1차원 배열을 생성, front와 rear를 -1로 초기화한다.*/
createQueue()
	Q[n];
    front <- -1;
    rear <- -1;
end createQueue()

선형 큐의 잘못된 포화 상태 인식을 해결하기 위한 방법 1. 원형 큐 2. 연결 큐(?)

원형 큐

원형 큐(Circular Queue)란 1차원 배열을 사용하면서 논리적으로 배열의 처음과 끝이 연결되어 있다고 가정하고 사용한다. 원형 큐에서 0 <= front, rear <= n-1 이기 때문에 초기 공백 상태는 front = rear = 0, front와 rear의 위치가 배열의 마지막 인덱스 n-1에서 논리적인 다음 자리인 인덱스 0 번으로 이동하기 위해서 나머지 연산자 mod를 사용한다.(front = (front + 1) % n) 공백 상태와 포화 상태 구분을 쉽게 하기 위해서 front가 있는 자리는 사용하지 않고 항상 빈자리로 둔다.  >> array로 queue를 만들려면 circular queue를 이용해야 한다.

원형 큐의 특징 : full queue와 empty queue 검사는 동일하지만 구분하기 위해서는, 1. 최대 원소 개수는 MAX_QUEUE_SIZE - 1 해야 한다. (둘 사이를 구분하기 위해) 2. 다 채우고 싶다면 둘을 구분해줄 변수 하나를 추가해줘야 한다.

full이 아닌데 full로 인식하는 오류 있을 때 앞으로 땡기는 오버 헤드가 컸던 선형 큐와 다르게, 원형 큐는 그러한 오버헤드는 없다. (O(n) > O(1)) >> 시간 복잡도 감소

createQueue(); 에서 front 와 rear 값은 0으로 되어 있다.

enQueue(cQ,A); 로 새로운 원소 A를 삽입하는 경우 항상 rear에 집어 넣는다. 집어 넣기 전에 인덱스 값을 증가시켜주고, (rear인덱스의 초기값은 0인데,이것을 1로 증가시켜주고) A를 삽입시켜준다. 이 상태에서 front는 첫번째 원소 그 앞의 인덱스이다.(여기서 첫번째 인덱스는 A > 따라서 이 앞의 인덱스는 [0]) 여기서 1st element = last element이다.  > rear <= (0+1) mod 4; cQ[1] <- A;

front index는  시계반대 방향으로 가리켜야 한다.

이 큐에 몇 개 들어있는지 확인하는 식 : (rear - front) mod n 여기서 n은 배열의 크기 > n이기 때문에 범위가 0부터 n-1까지이다.

6번 이후 enqueue(cQ,E)를 한다면, [1]에 E가 들어가야 할 상황인데, rear를 [1]로 이동시켜둔다면 rear = front 상황이 발생하여 full인데, entity 인지 분간이 어렵다. 여기서 circular Queue에서 full인 상황일 때는 원소의 개수가 n-1일 때를 말한다. 따라서 이 상황은 full 이기 때문에 원소를 집어 넣을 수 없다. 

//add to a circular queue
void addq(int front, int *prear, element item){
	*prear = (*prear + 1) % MAX_QUEUE_SIZE;
    if (front == *prear){
    	queue_full(prear);
        	/* reset rear and print error >> *prear = (*prear - 1) % MAX_QUEUE_SIZE */
        return;
    }
    queue[*prear] = item;
}
//delete from a circular queue
element deleteq(int *pfront, int rear){
	element item;
    if(*pfront == rear)
    	return queue_empty();
        	/* queue_empty returns an error key */
    *pfront = (*pfront + 1) % MAX_QUEUE_SIZE;
    return queue[*pfront];    
}

연결 큐

연결 큐(linked Queue)는 단순 연결 리스트를 이용한 큐이다. 큐의 원소는 단순 연결 리스트의 노드이고, 큐의 원소의 순서는 노드의 링크 포인터로 연결하며, 변수 front 는 첫 번째 노드를 가리키는 포인터 변수이고 변수 rear는 마지막 노드를 가리키는 포인터 변수를 의미한다. 초기 상태와 공백 상태는 front = rear = null 이다. 다시말해 front는 header 역할을 겸용하며 rear는 tail의 역할을 겸용한다. 

큐의 응용

운영체제의 작업 큐는 예를 들어 수강신청, 기차표 예매이다. 

 

 

 

'lecture > data structure' 카테고리의 다른 글

[lecture] 그래프  (0) 2023.01.09
[lecture] 트리  (0) 2023.01.09
[lecture] 스택  (0) 2023.01.01
[lecture] 연결 자료구조  (0) 2022.12.30
[lecture] C언어복습.연결리스트  (0) 2022.12.29
Comments