큐 자료구조의 개념과 다양한 구현 방식

큐의 기본 원리

큐는 선형 데이터 구조 중 하나로, 삽입과 삭제가 양 끝에서 이루어지는 특성을 가집니다. 한쪽 끝(후단)에서 요소를 추가하고, 다른 쪽 끝(전단)에서 요소를 제거하는 방식을 따릅니다. 이는 선입선출(First In First Out, FIFO) 원칙에 기반하며, 가장 먼저 들어온 항목이 가장 먼저 처리되는 구조입니다.

이러한 특성 덕분에 큐는 작업 스케줄링, 메시지 전달, 버퍼링 등 다양한 시스템에서 활용됩니다.

큐의 구현 방법

큐는 배열 또는 연결 리스트로 구현할 수 있습니다.

배열 기반 큐 (순차 큐)

배열을 사용하면 두 개의 인덱스 포인터를 통해 전단과 후단을 관리합니다. 후단 포인터는 다음 삽입 위치를 가리키며, 전단 포인터는 현재 첫 번째 요소를 가리킵니다. 하지만 일반적인 순차 큐는 공간 낭비 문제가 발생할 수 있으며, 용량 초과 시 재할당이 필요합니다.

원형 큐 (Circular Queue)

이 문제를 해결하기 위해 원형 큐가 도입되었습니다. 배열의 끝이 시작점과 연결되어 순환 구조를 형성하여, 전체 저장 공간을 효율적으로 활용할 수 있습니다.

연결 리스트 기반 큐 (링크드 큐)

노드 기반의 연결 리스트를 사용하면 동적 크기 조절이 가능하며, 삽입/삭제 연산의 시간 복잡도는 O(1)입니다. 전단 포인터는 헤드 노드를, 후단 포인터는 테일 노드를 유지합니다.

기본 큐 클래스 구현


class SimpleQueue:
    def __init__(self):
        self._data = []

    def enqueue(self, value):
        self._data.append(value)

    def dequeue(self):
        if self.is_empty():
            raise IndexError("큐가 비어 있습니다")
        return self._data.pop(0)

    def is_empty(self):
        return len(self._data) == 0

    def size(self):
        return len(self._data)

양방향 큐 (Deque) 구현

양방향 큐는 전단과 후단 모두에서 삽입 및 삭제가 가능한 큐입니다. 이를 통해 스택과 큐의 특성을 동시에 제공합니다.


class Deque:
    def __init__(self):
        self._items = []

    def add_front(self, item):
        self._items.insert(0, item)

    def add_rear(self, item):
        self._items.append(item)

    def remove_front(self):
        return self._items.pop(0)

    def remove_rear(self):
        return self._items.pop()

    def is_empty(self):
        return len(self._items) == 0

    def size(self):
        return len(self._items)

우선순위 큐 (Priority Queue)

우선순위 큐는 각 요소에 우선순위를 부여하여, 가장 높은 우선순위의 항목부터 처리됩니다. 동일한 우선순위인 경우 삽입 순서에 따라 처리됩니다.

이 구조는 힙(최소 힙 또는 최대 힙)으로 구현되며, 파이썬의 heapq 모듈을 활용하면 간편하게 구현할 수 있습니다.


import heapq

class PriorityQueue:
    def __init__(self):
        self._heap = []
        self._counter = 0

    def push(self, item, priority):
        heapq.heappush(self._heap, (priority, self._counter, item))
        self._counter += 1

    def pop(self):
        if not self._heap:
            raise IndexError("우선순위 큐가 비어 있습니다")
        _, _, item = heapq.heappop(self._heap)
        return item

    def is_empty(self):
        return len(self._heap) == 0

파이썬 내장 큐 모듈 사용

파이썬의 queue 모듈은 멀티스레드 환경에서도 안전하게 사용할 수 있는 다양한 큐를 제공합니다.

FIFO 큐 (순서 기반 큐)


import queue

q = queue.Queue()
q.put("task1")
q.put("task2")
q.put("task3")

print(q.get())  # task1
print(q.get())  # task2
print(q.get())  # task3

LIFO 큐 (스택처럼 동작)


import queue

stack_q = queue.LifoQueue()
stack_q.put("A")
stack_q.put("B")
stack_q.put("C")

print(stack_q.get())  # C
print(stack_q.get())  # B
print(stack_q.get())  # A

우선순위 큐 (정렬 기반)


import queue

pq = queue.PriorityQueue()
pq.put((3, "high"))
pq.put((1, "low"))
pq.put((2, "medium"))

print(pq.get())  # (1, 'low')
print(pq.get())  # (2, 'medium')
print(pq.get())  # (3, 'high')

모든 큐는 내부적으로 락을 사용해 동시성 문제를 방지하며, 다중 스레드 환경에서 신뢰성 있게 작동합니다.

태그: 우선순위 큐 양방향 큐 Heap queue module

7월 25일 09:20에 게시됨