티스토리 뷰
목차
개발을 오래 하다 보면 특정 데이터 구조가 얼마나 중요한지 알게 됩니다. 특히 스택과 큐는 알고리즘을 구현하거나 시스템 설계를 할 때 필수적인 구조입니다. Java와 같은 언어를 다뤄왔던 입장에서, Python에서 이 구조들을 활용하는 방식이 다소 직관적이어서 초보자들이 배우기 좋다고 생각해요. 스택과 큐의 개념을 잘 이해해 두면 이후의 알고리즘 문제 풀이에서도 큰 도움이 될 것입니다. 기초를 탄탄히 다지기 위해 천천히 따라해 보시기 바랍니다.
1. 스택(Stack)과 큐(Queue)란 무엇인가?
스택과 큐는 프로그래밍에서 기본이 되는 데이터 구조입니다. 이 두 구조는 데이터를 순서대로 처리하고 관리하는 방식이 다릅니다. 각 구조의 특성과 사용법을 알아봅시다.
1.1 스택(Stack)의 개념
스택은 LIFO(Last In, First Out) 구조입니다. 즉, 가장 마지막에 추가된 데이터가 가장 먼저 나가는 구조입니다. 흔히 접시를 쌓는 것과 비교할 수 있는데, 가장 위에 있는 접시를 먼저 꺼내는 것처럼 스택도 마지막에 들어간 데이터가 먼저 제거됩니다.
스택의 기본 연산
- push: 데이터를 스택의 맨 위에 추가합니다.
- pop: 스택의 맨 위에 있는 데이터를 제거하고 반환합니다.
- peek: 스택의 맨 위에 있는 데이터를 제거하지 않고 확인합니다.
- is_empty: 스택이 비어있는지 확인합니다.
# 스택 구현 예제 (리스트 사용)
stack = []
# push 연산
stack.append(1)
stack.append(2)
stack.append(3)
# pop 연산
print(stack.pop()) # 출력: 3
print(stack.pop()) # 출력: 2
# 스택 상태
print(stack) # 출력: [1]
1.2 큐(Queue)의 개념
큐는 FIFO(First In, First Out) 구조입니다. 즉, 가장 먼저 들어온 데이터가 가장 먼저 나가는 구조입니다. 줄을 서서 차례를 기다리는 것과 비슷합니다. 처음에 들어온 데이터가 맨 앞에서 처리되고 제거됩니다.
큐의 기본 연산
- enqueue: 데이터를 큐의 맨 뒤에 추가합니다.
- dequeue: 큐의 맨 앞에 있는 데이터를 제거하고 반환합니다.
- peek: 큐의 맨 앞에 있는 데이터를 제거하지 않고 확인합니다.
- is_empty: 큐가 비어있는지 확인합니다.
# 큐 구현 예제 (리스트 사용)
from collections import deque
queue = deque()
# enqueue 연산
queue.append(1)
queue.append(2)
queue.append(3)
# dequeue 연산
print(queue.popleft()) # 출력: 1
print(queue.popleft()) # 출력: 2
# 큐 상태
print(queue) # 출력: deque([3])
2. Python에서 스택 구현하기
Python에서는 스택을 구현하기 위해 보통 리스트를 사용합니다. 리스트는 데이터를 추가하고 제거하는 연산이 편리하기 때문입니다. Python의 리스트는 동적 배열이기 때문에 크기 제한 없이 데이터를 다룰 수 있습니다.
2.1 스택 기본 연산 구현
리스트를 활용한 스택의 기본 연산을 직접 구현해 보겠습니다.
class Stack:
def __init__(self):
self.stack = []
def push(self, item):
self.stack.append(item)
def pop(self):
if not self.is_empty():
return self.stack.pop()
return "스택이 비어 있습니다."
def peek(self):
if not self.is_empty():
return self.stack[-1]
return "스택이 비어 있습니다."
def is_empty(self):
return len(self.stack) == 0
- push: 리스트의 append() 메서드를 사용해 스택의 끝에 데이터를 추가합니다.
- pop: 리스트의 pop() 메서드를 사용해 스택의 끝에서 데이터를 제거하고 반환합니다.
- peek: 스택의 마지막 요소를 반환하지만, 제거하지 않습니다.
- is_empty: 스택이 비어있는지 확인합니다.
2.2 스택 예제
# 스택 인스턴스 생성
my_stack = Stack()
# 스택에 데이터 추가
my_stack.push(10)
my_stack.push(20)
my_stack.push(30)
# 스택의 맨 위 데이터 확인
print(my_stack.peek()) # 출력: 30
# 데이터 제거
print(my_stack.pop()) # 출력: 30
print(my_stack.pop()) # 출력: 20
# 스택 상태 확인
print(my_stack.is_empty()) # 출력: False
3. Python에서 큐 구현하기
Python에서 큐는 보통 deque(Double-Ended Queue)를 사용하여 구현합니다. 이는 큐 연산에서 효율성을 높여주며, 데이터 삽입과 제거가 매우 빠르게 이루어집니다.
3.1 큐 기본 연산 구현
from collections import deque
class Queue:
def __init__(self):
self.queue = deque()
def enqueue(self, item):
self.queue.append(item)
def dequeue(self):
if not self.is_empty():
return self.queue.popleft()
return "큐가 비어 있습니다."
def peek(self):
if not self.is_empty():
return self.queue[0]
return "큐가 비어 있습니다."
def is_empty(self):
return len(self.queue) == 0
- enqueue: append() 메서드를 사용하여 큐의 끝에 데이터를 추가합니다.
- dequeue: popleft() 메서드를 사용하여 큐의 앞에서 데이터를 제거하고 반환합니다.
- peek: 큐의 맨 앞 데이터를 반환하지만, 제거하지 않습니다.
- is_empty: 큐가 비어있는지 확인합니다.
3.2 큐 예제
# 큐 인스턴스 생성
my_queue = Queue()
# 큐에 데이터 추가
my_queue.enqueue("a")
my_queue.enqueue("b")
my_queue.enqueue("c")
# 큐의 맨 앞 데이터 확인
print(my_queue.peek()) # 출력: "a"
# 데이터 제거
print(my_queue.dequeue()) # 출력: "a"
print(my_queue.dequeue()) # 출력: "b"
# 큐 상태 확인
print(my_queue.is_empty()) # 출력: False
4. 스택과 큐의 활용 예제
스택과 큐는 다양한 상황에서 유용하게 사용됩니다. 데이터 구조를 관리하거나 알고리즘 문제를 해결할 때 이들을 이해하고 활용하는 것이 중요합니다.
4.1 스택 활용 - 괄호 검증
주어진 문자열에 괄호가 올바르게 열리고 닫혔는지 확인하는 문제는 스택으로 쉽게 해결할 수 있습니다.
def check_brackets(expression):
stack = []
for char in expression:
if char == "(":
stack.append(char)
elif char == ")":
if not stack:
return False
stack.pop()
return len(stack) == 0
print(check_brackets("(())")) # 출력: True
print(check_brackets("(()")) # 출력: False
4.2 큐 활용 - 작업 스케줄링
큐는 작업을 순차적으로 처리하는 스케줄러나 BFS(너비 우선 탐색) 알고리즘에서 자주 사용됩니다.
def process_tasks(tasks):
queue = Queue()
for task in tasks:
queue.enqueue(task)
while not queue.is_empty():
current_task = queue.dequeue()
print(f"Processing {current_task}")
tasks = ["Task1", "Task2", "Task3"]
process_tasks(tasks)
# 출력:
# Processing Task1
# Processing Task2
# Processing Task3
요약 디스크립션
Python의 스택과 큐는 데이터를 순차적으로 처리하고 관리하는 데 필수적인 데이터 구조입니다. LIFO와 FIFO 구조를 이해하고, 이를 Python에서 어떻게 구현하고 활용할 수 있는지 배워보세요.