파이썬 자료구조는 처음에 서로 헷갈릴 수밖에 없습니다. 특히 코딩 테스트에서는 어떤 주머니(자료구조)에 데이터를 넣느냐에 따라 속도가 천차만별이기 때문에, 쓰임새를 확실히 구분하는 게 중요합니다.
1. 파이썬 4대 자료구조: 모양 · 특징 · 코테용 필살기
1) 리스트 [ ] (List) : “순서가 중요한 데이터 나열”
가장 기본이 되는 상자입니다. 넣는 순서대로 번호(인덱스)가 매겨집니다.
- 모양: 대괄호
[1, 2, 3] - 특징: 수정 가능, 중복 허용, 순서 있음
- 코테용 필살기:
- 데이터를 그냥 저장하고 순서대로 꺼낼 때
- 정렬(
sort())이 필요할 때
- 단점: 특정 값이 들어있는지 찾을 때(
in) 처음부터 끝까지 다 뒤져야 해서 느림 ($O(N)$)
📌 리스트 주요 메서드 예시
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
| # 추가/삭제
arr = [1, 2, 3]
arr.append(4) # [1, 2, 3, 4]
arr.pop() # [1, 2, 3] (마지막 요소 제거)
arr.pop(0) # [2, 3] (인덱스 지정 삭제)
# 확장 & 정렬
arr.extend([5, 6]) # [2, 3, 5, 6]
arr.sort() # [2, 3, 5, 6]
arr.reverse() # [6, 5, 3, 2]
# 슬라이싱/복사
sub = arr[1:3] # [5, 3]
# 멤버십 테스트 (느림)
if 5 in arr:
print("있음")
|
2) 튜플 ( ) (Tuple) : “절대 안 변하는 읽기 전용 묶음”
리스트와 비슷하지만, 한 번 만들면 내용을 절대 못 바꿉니다.
- 모양: 소괄호
(1, 2) (괄호 없이 1, 2라고만 써도 튜플이 됨) - 특징: 수정 불가, 중복 허용, 순서 있음
- 코테용 필살기:
- 좌표값 처리:
(x, y)처럼 묶어서 다닐 때 - 딕셔너리의 키: 리스트는 딕셔너리의 키가 못 되지만, 튜플은 가능
📌 튜플 주요 특징 & 예시
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| # 생성
point = (3, 4)
coord = 3, 4 # 괄호 생략 가능
# 언패킹 (함수 반환값 받기 등)
x, y = point
# 변환
lst = list(point) # [3, 4]
t = (1, 2, 3)
print(t[0]) # 1
print(t.count(2)) # 1
print(t.index(3)) # 2
|
3) 딕셔너리 { : } (Dictionary) : “이름표 붙은 데이터”
단어장에서 단어를 찾으면 뜻이 나오듯, Key를 주면 Value가 나옵니다.
- 모양: 중괄호 + 콜론
{"name": "Gemini", "age": 1} - 특징:
Key는 중복 불가, 순서 없음(최신 파이썬은 순서 유지하지만 없다고 생각하는 게 안전) - 코테용 필살기:
- 빈도수 세기:
{"A": 3, "B": 5}처럼 개수 셀 때 최고 - 데이터 검색: 아무리 데이터가 많아도
Key만 알면 즉시($O(1)$) 찾음
📌 딕셔너리 주요 메서드 예시
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
| # 기본 구조
scores = {"A": 90, "B": 80}
# get: 없으면 기본값
print(scores.get("C", 0)) # 0
# setdefault: 없으면 추가, 있으면 그대로
scores.setdefault("C", 70)
# pop: 값 반환 후 삭제
b_score = scores.pop("B") # 80
# popitem: 마지막 추가된 (키, 값) 튜플 반환 후 삭제
k, v = scores.popitem()
# update: 여러 개 추가/업데이트
scores.update({"A": 95, "D": 60})
# defaultdict: 기본값 자동 생성
from collections import defaultdict
cnt = defaultdict(int)
cnt["x"] += 1
|
4) 셋 { } (Set) : “중복 없는 집합”
딕셔너리에서 Key만 모아놓은 형태라고 볼 수 있습니다.
- 모양: 중괄호
{1, 2, 3} (주의: 빈 셋은 set()으로 선언) - 특징: 중복 절대 불가, 순서 없음
- 코테용 필살기:
- 중복 제거:
list(set(nums)) 한 줄이면 중복 끝 - 기록 확인: “나 이거 본 적 있나?” 체크할 때 리스트보다 압도적으로 빠름 ($O(1)$)
📌 셋 주요 메서드 예시
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
| s = {1, 2, 3}
# 추가/삭제
s.add(4)
s.remove(3) # 없으면 KeyError
s.discard(5) # 없어도 에러 없음
s.pop() # 임의의 요소 하나 제거 (반환)
# 집합 연산
s1 = {1, 2, 3}
s2 = {2, 3, 4}
print(s1 | s2) # 합집합 {1,2,3,4}
print(s1 & s2) # 교집합 {2,3}
print(s1 - s2) # 차집합 {1}
# 중복 제거
unique = list(set([1, 2, 2, 3]))
|
2. 💡 한눈에 보는 핵심 비교표
| 구분 | 리스트 [] | 튜플 () | 딕셔너리 { : } | 셋 { } |
|---|
| 수정 가능 | O | X | O | O |
| 중복 허용 | O | O | (Key는 X) | X |
| 검색 속도 | 느림 ($O(N)$) | 느림 ($O(N)$) | 매우 빠름 ($O(1)$) | 매우 빠름 ($O(1)$) |
| 주요 용도 | 데이터 보관/정렬 | 좌표/불변 데이터 | 개수 세기/ID 검색 | 중복 제거/방문 체크 |
3. 시간 복잡도 비교 & 코테 추천 시나리오
3.1. 주요 연산별 시간 복잡도
| 연산 | 리스트 | 튜플 | 딕셔너리 | 셋 |
|---|
| 인덱스 접근 / 키 조회 | $O(1)$ | $O(1)$ | $O(1)$ | $O(1)$ |
순차 탐색 / 멤버십 (in) | $O(N)$ | $O(N)$ | $O(1)$ | $O(1)$ |
| 삽입 (끝) | $O(1)$ 평균 | - | $O(1)$ | $O(1)$ |
| 삽입 (중간) | $O(N)$ | - | $O(1)$ | $O(1)$ |
| 삭제 (끝) | $O(1)$ | - | $O(1)$ | $O(1)$ |
| 삭제 (중간/키) | $O(N)$ | - | $O(1)$ | $O(1)$ |
✅ 코테에서 가장 자주 쓰는 패턴: 멤버십 체크 + 중복 제거 → dict / set으로 해결하세요.
3.2. 실전 사용 추천 시나리오
- 정렬된 순서 유지하면서 데이터를 쌓고 싶을 때 →
list + append / sort - 순서를 바꾸면 안 되는 고정된 값(좌표, 쌍) 관리 →
tuple - 빈도수 세기 / ID → 정보 매핑 →
dict (Counter로 더 쉽게) - 중복 제거 / 방문 여부 검사 →
set (in이 $O(1)$이기 때문에 리스트보다 훨씬 빠름) - 입력 순서 유지하면서 키-값 저장 →
OrderedDict (파이썬 3.7 이상은 기본 dict도 유지됨) - 기본값이 있는 딕셔너리를 자주 쓸 때 →
defaultdict
4. 고급 자료구조 / 유용한 표준 라이브러리
4.1. defaultdict (기본값 자동 생성)
collections.defaultdict는 키가 없을 때 자동으로 기본값을 만들어줍니다.
1
2
3
4
5
6
7
| from collections import defaultdict
cnt = defaultdict(int) # 기본값 0
cnt["a"] += 1
lst = defaultdict(list)
lst["a"].append(1)
|
4.2. Counter (빈도수 세기 최적화)
collections.Counter는 데이터를 넣고 바로 개수를 셀 때 유용합니다.
1
2
3
4
5
6
| from collections import Counter
words = ["a", "b", "a", "c", "b"]
count = Counter(words)
print(count) # Counter({'a': 2, 'b': 2, 'c': 1})
print(count.most_common(2)) # [('a', 2), ('b', 2)]
|
4.3. OrderedDict (순서가 중요할 때)
파이썬 3.7+에서는 기본 dict도 입력 순서를 유지하지만, OrderedDict는 추가 기능(이동, 마지막 삭제 등)을 제공합니다.
1
2
3
4
5
6
| from collections import OrderedDict
o = OrderedDict()
o["a"] = 1
o["b"] = 2
o.move_to_end("a") # 'a'를 맨 뒤로 이동
|
4.4. dataclasses (값 객체 정의)
dataclasses.dataclass는 간단한 데이터 구조를 선언할 때 매우 편리합니다.
1
2
3
4
5
6
7
8
9
| from dataclasses import dataclass
@dataclass
class Point:
x: int
y: int
p = Point(1, 2)
print(p) # Point(x=1, y=2)
|
5. {}의 정체: 딕셔너리 vs 셋
파이썬에서 중괄호 {}를 볼 때 헷갈리기 쉬운 곳입니다.
a = {} : 빈 딕셔너리 생성 (파이썬의 약속)b = set() : 빈 셋 생성c = {1, 2} : 값이 하나씩 있으면 셋d = {1: "A"} : Key: Value 쌍이 있으면 딕셔너리
✅ {} 안에 :이 있으면 딕셔너리, 없으면 셋이라고 생각하면 쉽습니다.
4. 파이썬 자료구조 잘 쓰는 법 (코딩 테스트 필살기)
4.1. + vs .append() vs .add(): 언제 쓰나?
| 연산 | 대상 | 원본 변경 | 설명 |
|---|
+ | 리스트/튜플/문자열 | X | 두 덩어리를 붙여 새 객체 생성 |
.append(x) | 리스트 | O | 리스트 맨 뒤에 요소 추가 |
.add(x) | 셋 | O | 셋에 요소 추가 (중복이면 무시) |
dict[k] = v | 딕셔너리 | O | 키로 값 저장/업데이트 |
4.2. 실전 선택 가이드
- 순서가 중요하고, 정렬/정렬 검사가 필요하다 →
list = [] + append - 중복 체크/멤버십 테스트가 자주 필요하다 →
seen = set() + add (멤버십은 $O(1)$) - 좌표나 복합 키로 방문 체크하고 싶다 →
(x, y) 튜플 + 딕셔너리 키 - 값의 빈도수를 빠르게 구하고 싶다 →
counts = {} + counts[val] = counts.get(val, 0) + 1
5. Set (집합) 상세 정리
5.1. 핵심 개념: “중복 없음, 순서 없음”
- Unique: 동일한 값을 두 번 넣어도 하나만 남음 (중복 자동 제거)
- Unordered: 순서를 보장하지 않음 (인덱스로 접근 불가)
- Hashable: 내부적으로 해시 테이블을 사용해 검색 속도가 압도적으로 빠름
5.2. 선언 및 기본 조작
1
2
3
4
5
6
7
8
9
| # 선언
s = {1, 2, 3, 3, 3} # s는 {1, 2, 3}
empty_set = set() # 빈 셋 ({}는 빈 딕셔너리)
# 추가 및 삭제
s.add(4) # 요소 하나 추가
s.update([5, 6]) # 여러 요소 한꺼번에 추가
s.remove(1) # 요소 삭제 (없으면 에러)
s.discard(10) # 요소 삭제 (없어도 에러 안 남)
|
5.3. 집합 연산 (수학적 활용)
| 연산 | 기호 | 메서드 | 설명 |
|---|
| 합집합 | a | b | a.union(b) | 두 집합의 모든 원소 (중복 제외) |
| 교집합 | a & b | a.intersection(b) | 공통된 원소만 |
| 차집합 | a - b | a.difference(b) | a에는 있고 b에는 없는 것 |
| 대칭 차집합 | a ^ b | a.symmetric_difference(b) | 둘 중 한 곳에만 있는 것 |
5.4. 코딩 테스트 필살기
① 중복 제거
1
2
| nums = [1, 2, 2, 3, 4, 4, 4, 5]
unique_nums = list(set(nums)) # [1, 2, 3, 4, 5]
|
② 멤버십 테스트 (검색 최적화)
- List: 처음부터 끝까지 확인 ($O(N)$)
- Set: 해시로 즉시 확인 ($O(1)$)
주의: 셋에 넣는 원소는 값이 변하지 않는(Immutable) 녀석이어야 합니다. 그래서 (r, c, num)처럼 튜플을 넣는 것이 안전합니다.
6. 요약: 어떤 자료구조를 선택할까?
| 자료구조 | 모양 | 수정 가능 | 중복 | 검색 속도 | 주요 용도 |
|---|
| List | [ ] | O | O | $O(N)$ | 데이터 나열, 정렬, 스택/큐 |
| Tuple | ( ) | X | O | $O(N)$ | 좌표, 딕셔너리 키, 불변 데이터 |
| Dict | { : } | O | (Key는 X) | $O(1)$ | 빈도수 계산, 매핑 |
| Set | { } | O | X | $O(1)$ | 중복 제거, 방문 체크 |
7. 한 줄 꿀팁
- 빈 셋은
s = set() ( {}는 빈 딕셔너리 ) - 수정하고 싶으면
[], 불변이면 ( ) - 빠른 검색이 필요하면 리스트 대신
{ } (셋/딕셔너리) - 리스트는
append, 셋은 add, 딕셔너리는 dict[key] = value
이제 파이썬 자료구조를 보고 “어떤 주머니에 넣으면 좋을까”를 빠르게 판단할 수 있을 거예요. 이 내용을 TIL로 잘 보관해 두면, 코딩 테스트 중에도 머리가 덜 복잡해질 거예요! ✨