출시·고도화 중
Algorithm
배열·연결 리스트·스택·큐·해시 테이블의 동작 원리와 시간 복잡도를 익히고, 상황에 맞는 구조를 고르는 법을 배웁니다.
자료구조는 데이터를 메모리에 배치하는 방식과 그 배치에서 효율적으로 할 수 있는 연산을 함께 묶은 것입니다. 이 주제에서는 거의 모든 프로그램이 쓰는 다섯 가지 기본 구조, 즉 배열과 동적 배열, 연결 리스트, 스택, 큐와 덱, 해시 테이블을 다룹니다. 연속된 메모리에 나란히 두는 방식과 노드를 포인터로 잇는 방식이 어떻게 다른지, 해시 함수와 충돌, 적재율이 무엇인지도 함께 설명합니다.
어떤 자료구조를 고르느냐에 따라 같은 일이 O(1)이 되기도 하고 O(n)이 되기도 합니다. 큐를 리스트 맨 앞에서 빼는 식으로 만들거나 포함 검사를 리스트로 하면 데이터가 커질 때 프로그램이 급격히 느려집니다. Python의 list·deque·dict·set, C++의 vector·deque·unordered_map, Java의 ArrayList·ArrayDeque·HashMap, TypeScript의 Array·Map·Set이 각각 어떤 구조인지 알면 성능 문제를 미리 피할 수 있고, 코딩 테스트와 기술 면접에서도 가장 먼저 묻는 내용입니다.
먼저 각 구조를 작은 예제로 손으로 따라가며 메모리에서 무엇이 움직이는지 확인합니다. 그다음 스택, 원형 버퍼 큐, 분리 연결법 해시 맵을 직접 구현해 보고, 연산별 복잡도 표를 정리한 뒤 실제로 시간을 재 봅니다. 마지막으로 연습 문제에서 문제마다 어떤 구조가 맞는지 고르는 연습을 하면 실무에서도 바로 쓸 수 있습니다.
배열은 인덱스로 O(1) 접근과 좋은 캐시 효율을, 연결 리스트는 쥐고 있는 노드 옆에서 O(1) 삽입·삭제를 줍니다.
동적 배열은 가득 차면 용량을 배수로 늘려 복사하므로, 가끔 비싼 추가가 있어도 평균적으로는 추가 한 번이 O(1)입니다.
스택은 마지막에 넣은 것을, 큐는 먼저 넣은 것을 꺼냅니다. 덱과 원형 버퍼를 쓰면 양 끝 연산이 모두 O(1)입니다.
해시 테이블은 키를 버킷 번호로 바꿔 평균 O(1)에 찾습니다. 충돌은 분리 연결법 등으로 처리하고, 적재율이 기준을 넘으면 크기를 늘립니다.
분리 연결법으로 해시 맵을 만듭니다. 키의 해시값을 버킷 수로 나눈 나머지로 버킷을 고르고, 같은 키가 있으면 값만 바꾸며, 적재율이 0.75를 넘으면 버킷을 두 배로 늘려 모든 쌍을 다시 넣습니다. 함께 리스트를 스택으로, deque를 큐로 쓰는 법도 보여 줍니다.
data_structures.py
from collections import deque
class HashMap:
"""Separate chaining: each bucket is a list of (key, value) pairs."""
def __init__(self, capacity=8):
self.buckets = [[] for _ in range(capacity)]
self.size = 0
def _bucket(self, key):
return self.buckets[hash(key) % len(self.buckets)]
def put(self, key, value):
bucket = self._bucket(key)
for i, (k, _) in enumerate(bucket):
if k == key:
bucket[i] = (key, value)
return
bucket.append((key, value))
self.size += 1
if self.size > 0.75 * len(self.buckets): # load factor limit
old = self.buckets
self.buckets = [[] for _ in range(2 * len(old))]
for pairs in old:
for k, v in pairs:
self._bucket(k).append((k, v))
def get(self, key, default=None):
for k, v in self._bucket(key):
if k == key:
return v
return default
stack = [1, 2, 3]
stack.append(4)
print("stack pop:", stack.pop()) # 4 (LIFO)
queue = deque([1, 2, 3])
queue.append(4)
print("queue popleft:", queue.popleft()) # 1 (FIFO)
ages = HashMap()
for name, age in [("ada", 36), ("alan", 41), ("grace", 85)]:
ages.put(name, age)
ages.put("ada", 37)
print("ada:", ages.get("ada"), "size:", ages.size) # ada: 37 size: 3
설치부터 기본 자료구조 의 핵심 개념까지, 여섯 장으로 차근차근 따라 합니다.
기본 자료구조 에 관해 묻고, 경험을 나누고, 의견을 주고받는 곳입니다.
아직 토론이 없습니다. 첫 이야기를 시작해 보세요.
python data_structures.py
댓글 0개
로그인 · 로그인하면 댓글을 남길 수 있습니다.
첫 댓글을 남겨 보세요.