πŸ“–CS/πŸ“™Data Structure

[자료ꡬ쑰] Chapter3. STACKS AND QUEUES(1)

goguma.dev 2024. 10. 5. 21:29

β€» 이 μΉ΄ν…Œκ³ λ¦¬μ˜ 글듀은 knu EK.Ryu κ΅μˆ˜λ‹˜μ˜ <자료ꡬ쑰> μˆ˜μ—…μ„ λ“£κ³  λ‚˜λ¦„λŒ€λ‘œ ν•„μžκ°€ μ •λ¦¬ν•œ κΈ€μž…λ‹ˆλ‹€.

β€» λΆ€μ‘±ν•œ μ„€λͺ…이 μžˆκ±°λ‚˜, 잘λͺ» μ•Œκ³  μž‘μ„±ν•œ 뢀뢄이 보인닀면 νŽΈν•˜κ²Œ λŒ“κΈ€λ‘œ μ•Œλ €μ£Όμ‹œλ©΄ 정말 κ°μ‚¬ν•˜κ² μŠ΅λ‹ˆλ‹€πŸ˜Š

3.1 Stack

μŠ€νƒμ€ 데이터λ₯Ό μ €μž₯ν•˜κ³  μ‚­μ œν•˜λŠ”λ° LIFO(Last In, First Out) λ°©μ‹μœΌλ‘œ μž‘λ™ν•˜λŠ” μžλ£Œκ΅¬μ‘°μž…λ‹ˆλ‹€. 즉, λ§ˆμ§€λ§‰μ— λ“€μ–΄μ˜¨ 데이터가 κ°€μž₯ λ¨Όμ € λ‚˜κ°€λŠ” κ΅¬μ‘°μž…λ‹ˆλ‹€.

μœ„ κ·Έλ¦Όμ—μ„œ λ³΄μ΄λŠ” κ²ƒμ²˜λŸΌ, A, B, C, D, E μˆœμ„œλ‘œ 데이터λ₯Ό λ„£κ³ , μ‚­μ œν•  λ•ŒλŠ” EλΆ€ν„° μ œκ±°λ©λ‹ˆλ‹€.

 

μŠ€νƒμ— 데이터λ₯Ό λ„£κ³ (push), λΉΌλŠ”(pop) ν•¨μˆ˜μ— λŒ€ν•΄μ„œ μ•„λž˜μ—μ„œ μ•Œμ•„λ³΄κ² μŠ΅λ‹ˆλ‹€.

void push(element item) // 데이터 μΆ”κ°€
{
    if (top >= MAX_STACK_SIZE - 1)
        stackFull();
    stack[++top] = item;
}

void stackFull() // μŠ€νƒμ΄ 꽉 찼을 λ•Œ 였λ₯˜ 좜λ ₯
{
    fprintf(stderr, "Stack is full, cannot add element");
    exit(EXIT_FAILURE);
}

element pop() // μŠ€νƒμ—μ„œ 데이터 뽑기(κ°€μž₯ μœ„μ— μžˆλŠ”!)
{
    if (top == -1)
        return stackEmpty();
    return stack[top--];
}

 

 

3.2 Stacks Using Dynamic Arrays

배열을 μ΄μš©ν•œ μŠ€νƒμ€ 데이터가 μŠ€νƒμ˜ μš©λŸ‰μ„ λ„˜μ–΄μ„œ μŒ“μΌ 수 μ—†μŠ΅λ‹ˆλ‹€.

ν•˜μ§€λ§Œ 동적 할당을 μ΄μš©ν•œλ‹€λ©΄, μŠ€νƒμ˜ 크기가 가득 μ°° λ•Œ λ™μ μœΌλ‘œ 배열을 두 λ°° 늘렀 이 문제λ₯Ό 극볡할 수 μžˆμŠ΅λ‹ˆλ‹€.

pop() ν•¨μˆ˜λŠ” κ·ΈλŒ€λ‘œμ΄κ³ , push() ν•¨μˆ˜μ™€ stackFull() ν•¨μˆ˜λŠ” μ•„λž˜μ™€ 같이 λ³€κ²½ν•˜λ©΄ λ©λ‹ˆλ‹€.

void push(element item)
{
    if (top >= capacity - 1)
        stackFull();
    stack[++top] = item;
}

void stackFull()
{
    REALLOC(stack, 2 * capacity * sizeof(*stack));
    capacity *= 2;
}

 

 

3.3 Queues

νλŠ” FIFO(First In, First Out) λ°©μ‹μœΌλ‘œ λ™μž‘ν•˜λŠ” 자료ꡬ쑰둜, λ¨Όμ € λ“€μ–΄μ˜¨ 데이터가 λ¨Όμ € λ‚˜κ°€λŠ” κ΅¬μ‘°μž…λ‹ˆλ‹€.

μ‚½μž…μ€ 큐의 λ’€μͺ½(rear)μ—μ„œ 이루어지고, μ‚­μ œλŠ” μ•žμͺ½(front)μ—μ„œ μ΄λ£¨μ–΄μ§‘λ‹ˆλ‹€.

큐λ₯Ό κ΅¬ν˜„ν•˜λŠ” λ°©λ²•μ—λŠ” 두 κ°€μ§€ 방법이 μžˆμŠ΅λ‹ˆλ‹€.

1. 1차원 배열을 μ΄μš©ν•œ 큐

2. 1차원 배열을 μ›ν˜•μœΌλ‘œ μ—°κ²°ν•˜μ—¬ μ΄μš©ν•˜λŠ” μ›ν˜• 큐

 

(1) 1차원 λ°°μ—΄ 큐

λ¨Όμ € 1차원 λ°°μ—΄ 큐λ₯Ό μ½”λ“œλ‘œ μž‘μ„±ν•΄ λ³΄κ² μŠ΅λ‹ˆλ‹€.

void addq(element item)
{
	// add an item to the queue
    if (rear == MAX_QUEUE_SIZE - 1)
        queueFull();
	queue[++rear] = item;
}

element deleteq()
{
	// remove element at the front of the queue
	if (front == rear)
		return queueEmpty();
	return queue[++front];
}

이 1차원 λ°°μ—΄ νμ—λŠ” μž‘μ—…μ„ μ§„ν–‰ν•˜λ©΄μ„œ 큐가 점점 였λ₯Έμͺ½μœΌλ‘œ μ΄λ™ν•˜κ²Œ λœλ‹€λŠ” λ¬Έμ œκ°€ μžˆμŠ΅λ‹ˆλ‹€.

이λ₯Ό ν•΄κ²°ν•˜κΈ° μœ„ν•΄μ„œλŠ” λ°°μ—΄μ˜ λͺ¨λ“  μ›μ†Œλ₯Ό μ™Όμͺ½μœΌλ‘œ μ΄λ™μ‹œν‚€λŠ” λ°°μ—΄ 이동(array shifting) μž‘μ—…μ΄ ν•„μš”ν•©λ‹ˆλ‹€. ν•˜μ§€λ§Œ 이 μž‘μ—…μ—λ„ μ‹œκ°„ λ³΅μž‘λ„κ°€ O(MAX_QUEUE_SIZE)둜 맀우 λΉ„ν˜Έμœ¨μ μ΄κΈ° λ•Œλ¬Έμ— λŒ€μ•ˆμœΌλ‘œ μ›ν˜•νλΌλŠ” 자료ꡬ쑰λ₯Ό μ‚¬μš©ν•©λ‹ˆλ‹€.

 

(2) μ›ν˜• 큐 Circular Queue

μ›ν˜• νλŠ” λ°°μ—΄μ˜ λμ—μ„œ λ‹€μ‹œ λ°°μ—΄μ˜ 처음으둜 λŒμ•„κ°ˆ 수 μžˆλ„λ‘ κ΅¬ν˜„λ˜μ–΄, λ°°μ—΄μ˜ 끝에 λ„λ‹¬ν–ˆμ„ λ•Œ 전체λ₯Ό λ‹€μ‹œ μ΄λ™μ‹œν‚€μ§€ μ•Šκ³ λ„ 효율적으둜 큐λ₯Ό μ‚¬μš©ν•  수 있게 ν•΄ μ€λ‹ˆλ‹€.

μ•„λž˜ μ½”λ“œμ—μ„œ μ›ν˜• 큐의 μ‚½μž…, μ‚­μ œ μ½”λ“œλ₯Ό 확인해 λ΄…μ‹œλ‹€.

void addq(element item)
{
	rear = (rear + 1) % MAX_QUEUE_SIZE;
	if (front == rear)
		queueFull();
	queue[rear] = item;
}

element deleteq()
{
	if (front == rear)
		return queueEmpty();
	front = (front + 1) % MAX_QUEUE_SIZE;
	return queue[front];
}

μ½”λ“œλ₯Ό 톡해 μ›ν˜• 큐의 νŠΉμ§•μ„ ν•˜λ‚˜ μ•Œ 수 μžˆλŠ”λ°, νλŠ” 꽉 찼을 λ•Œλ„ 리슀트의 ν•œ μžλ¦¬κ°€ λΉ„μ–΄μžˆκ²Œ λ©λ‹ˆλ‹€.

μ΄λŠ” μ›ν˜• νμ—μ„œ front와 rearκ°€ 동일할 λ•Œ 큐가 λΉ„μ–΄μžˆλŠ” μƒνƒœμ™€ 가득 μ°¬ μƒνƒœλ₯Ό κ΅¬λΆ„ν•˜κΈ° μœ„ν•΄ ν•„μš”ν•©λ‹ˆλ‹€.

 

3.4 Circular Queues using Dynamic Arrays

μ›ν˜• 큐가 가득 찼을 λ•Œ 데이터λ₯Ό 더 μΆ”κ°€ν•˜κ³  μ‹Άλ‹€λ©΄ 동적할당을 μ΄μš©ν•  수 μžˆμŠ΅λ‹ˆλ‹€. 

μœ„ μ΄λ―Έμ§€λŠ” μ›ν˜• 큐가 가득 찼을 λ•Œλ₯Ό ν‘œν˜„ν•œ κ²ƒμœΌλ‘œ, μ‹€μ œλ‘œ μ›ν˜• νλŠ” 1차원 λ°°μ—΄ ν˜•νƒœμ΄κΈ° λ•Œλ¬Έμ— (b)의 ν˜•νƒœλ₯Ό κ°–κ³  μžˆμŠ΅λ‹ˆλ‹€.

(b)의 μƒνƒœμ—μ„œ realloc을 ν•˜μ—¬ μ›ν˜• 큐의 크기λ₯Ό 2λ°° λŠ˜λ¦°λ‹€λ©΄, λ¬Έμ œκ°€ λ°œμƒν•  수 μžˆμŠ΅λ‹ˆλ‹€. μ›ν˜• 큐의 νŠΉμ§•μ„ κ³ λ €ν•˜μ§€ μ•Šμ•„, (c)의 κ·Έλ¦Όμ—μ„œ 보이듯이 κ°€μš΄λ°μ— 큰 빈 곡간이 λ°œμƒν•  수 μžˆμŠ΅λ‹ˆλ‹€.

(d): 이λ₯Ό μ˜ˆλ°©ν•˜κΈ° μœ„ν•΄μ„œλŠ” 6, 7번 index에 λ“€μ–΄μžˆλŠ” 값듀을 였λ₯Έμͺ½ 끝으둜 shifting μ‹œμΌœ ν•΄κ²°ν•˜κ±°λ‚˜,

(e): 꽉 μ°¬ λ°°μ—΄μ˜ 값듀을 볡사 ν›„, malloc을 μ‚¬μš©ν•˜λŠ” 방법이 μžˆμŠ΅λ‹ˆλ‹€.

 

μ›ν˜• 큐의 크기λ₯Ό λ™μ ν• λ‹ΉμœΌλ‘œ λŠ˜λ¦¬λŠ” 두 방법을 비ꡐ해 λ΄…μ‹œλ‹€: realloc --> shifting vs malloc

λ¨Όμ €, 첫 번째 방법을 μ΄μš©ν•˜λ©΄ 배열을 2배둜 ν™•μž₯ν•˜κ³  μ›μ†Œλ₯Ό 였λ₯ΈνŽΈμœΌλ‘œ λ―ΈλŠ” 것을 λ‹€ 합쳀을 λ•Œ μ΅œλŒ€ 2 * capacity - 2의 μ›μ†Œλ₯Ό λ³΅μ‚¬ν•˜κ²Œ λ©λ‹ˆλ‹€.

 

두 번째 λ°©λ²•μ—μ„œλŠ” λ°°μ—΄ 크기λ₯Ό malloc을 μ΄μš©ν•΄μ„œ λ°°κ°€ν•  λ•Œ 값듀을 잘 λ³΅μ‚¬ν•΄μ„œ λ„£μŒμœΌλ‘œμ¨ capacity-1둜 볡사할 μ›μ†Œ 수λ₯Ό 쀄일 수 μžˆμŠ΅λ‹ˆλ‹€.

 

두 번째 λ°©λ²•μ˜ μ½”λ“œλ₯Ό ν•œ 번 μž‘μ„±ν•΄λ΄…μ‹œλ‹€.

이 μ½”λ“œμ—μ„œ ν•¨μˆ˜ copy(a, b, c)λŠ” μœ„μΉ˜ aμ—μ„œ b-1κΉŒμ§€μ˜ μ›μ†Œλ₯Ό cμ—μ„œ μ‹œμž‘ν•˜λŠ” μœ„μΉ˜λ‘œ λ³΅μ‚¬ν•˜λŠ” ν•¨μˆ˜μž…λ‹ˆλ‹€.

void addq(element item)
{
	rear = (rear + 1) % MAX_QUEUE_SIZE;
	if (front == rear)
		queueFUll();
	queue[rear] = item;
}

void queueFUll()
{
	// 이전 큐의 크기λ₯Ό 두 배둜 ν™•μž₯
	element* newQueue;
	MALLOC(newQueue, 2 * capacity * sizeof(*queue));

	// 큐의	데이터λ₯Ό μƒˆλ‘œμš΄ 큐둜 볡사
	int start = (front + 1) % capacity;
	if (start < 2)
		copy(queue + start, queue + start + capacity - 1, newQueue);
	else
	{
		copy(queue + start, queue + capacity, newQueue);
		copy(queue, queue + rear + 1, newQueue + capacity - start);
	}

	// μƒˆλ‘œμš΄ 큐의 정보λ₯Ό μ—…λ°μ΄νŠΈ
	front = 2 * capacity - 1;
	rear = capacity - 2;
	capacity *= 2;
	free(queue);
	queue = newQueue;
}

μ›ν˜• 큐가 λ¦¬μŠ€νŠΈμ—μ„œ ν•˜λ‚˜μ˜ segment일 경우

 

μ›ν˜• 큐가 λ¦¬μŠ€νŠΈμ—μ„œ 두 개의 μ„Έκ·Έλ¨ΌνŠΈλ‘œ λ‚˜λˆ μ§ˆ 경우

 

 

λ‹€μŒ μž₯μ—μ„œλŠ” μŠ€νƒκ³Ό 큐λ₯Ό μ‚¬μš©ν•˜λŠ” λ¬Έμ œλ“€μ„ κ³΅λΆ€ν•΄λ΄…μ‹œλ‹€.πŸ˜†