트라이 (Trie) 자료구조
핵심 인사이트 (3줄 요약)
문자열 검색에 특화된 트리 계열 자료구조. 공통 접두사를 공유하는 문자열들을 계층적으로 저장한다. 검색·삽입 O(m) (m=문자열 길이), 해시맵보다 접두사 검색·자동완성에 강하다.
📝 기술사 모의답안 (2.5페이지 분량)
📌 예상 문제
"트라이 (Trie) 자료구조의 원리와 동작 과정을 설명하고, 유사 알고리즘·기법과 비교하여 적합한 활용 시나리오를 기술하시오."
Ⅰ. 개요
1. 개념
트라이(Trie)는 문자열의 각 문자를 노드로 저장하는 트리 구조로, 공통 접두사(prefix)를 공유하는 문자열을 효율적으로 관리한다.
비유: "전화번호부 색인" - A→B→C 순서로 찾되, 공통 앞글자는 한 번만 저장
Ⅱ. 구성 요소 및 핵심 원리
2. 트라이 구조 시각화
저장할 단어: ["car", "card", "care", "cat", "bat", "ball"]
(root)
/ \
c b
| |
a a
/|\ |\
r t t l
| | | l
(*)(*) (*) |
| (*)
d,e
(*)(*)
실제 트리:
root
├── c
│ └── a
│ ├── r ← "car" ✓
│ │ ├── d ← "card" ✓
│ │ └── e ← "care" ✓
│ └── t ← "cat" ✓
└── b
└── a
├── t ← "bat" ✓
└── l
└── l ← "ball" ✓
(*) = 단어 끝 표시 (isEnd = True)
공통 접두사 "ca"는 한 번만 저장! → 메모리 효율
3. 핵심 연산
삽입 (Insert)
def insert(root, word):
node = root
for char in word:
if char not in node.children:
node.children[char] = TrieNode()
node = node.children[char]
node.is_end = True # 단어 끝 표시
검색 (Search)
def search(root, word):
node = root
for char in word:
if char not in node.children:
return False # 없음
node = node.children[char]
return node.is_end # 끝이어야 단어
접두사 검색 (StartsWith)
def starts_with(root, prefix):
node = root
for char in prefix:
if char not in node.children:
return False
node = node.children[char]
return True # 단어가 아니어도 OK (접두사만)
4. 완전한 구현
class TrieNode:
def __init__(self):
self.children = {} # char → TrieNode
self.is_end = False
self.count = 0 # 해당 접두사로 시작하는 단어 수
class Trie:
def __init__(self):
self.root = TrieNode()
def insert(self, word: str) -> None:
node = self.root
for char in word:
if char not in node.children:
node.children[char] = TrieNode()
node = node.children[char]
node.count += 1
node.is_end = True
def search(self, word: str) -> bool:
node = self.root
for char in word:
if char not in node.children:
return False
node = node.children[char]
return node.is_end
def starts_with(self, prefix: str) -> bool:
node = self.root
for char in prefix:
if char not in node.children:
return False
node = node.children[char]
return True
def count_prefix(self, prefix: str) -> int:
"""접두사로 시작하는 단어 수"""
node = self.root
for char in prefix:
if char not in node.children:
return 0
node = node.children[char]
return node.count
def auto_complete(self, prefix: str) -> list:
"""자동 완성 - 접두사로 시작하는 모든 단어"""
node = self.root
for char in prefix:
if char not in node.children:
return []
node = node.children[char]
results = []
self._dfs(node, prefix, results)
return results
def _dfs(self, node, current, results):
if node.is_end:
results.append(current)
for char, child in node.children.items():
self._dfs(child, current + char, results)
def delete(self, word: str) -> bool:
"""단어 삭제"""
def _delete(node, word, depth):
if depth == len(word):
if not node.is_end:
return False
node.is_end = False
return len(node.children) == 0 # 자식 없으면 삭제 가능
char = word[depth]
if char not in node.children:
return False
should_delete = _delete(node.children[char], word, depth + 1)
if should_delete:
del node.children[char]
return len(node.children) == 0 and not node.is_end
return False
return _delete(self.root, word, 0)
print("=== 트라이 자료구조 시뮬레이션 ===\n")
trie = Trie()
words = ["apple", "app", "application", "apply", "apt", "banana", "band"]
print("단어 삽입:")
for w in words:
trie.insert(w)
print(f" 삽입: {w}")
print("\n단어 검색:")
tests = ["app", "apple", "ap", "banana", "ban"]
for t in tests:
print(f" search('{t}'): {trie.search(t)}")
print("\n접두사 검색:")
prefixes = ["app", "ba", "xyz"]
for p in prefixes:
print(f" starts_with('{p}'): {trie.starts_with(p)}, 개수: {trie.count_prefix(p)}")
print("\n자동완성 (prefix='app'):")
for word in trie.auto_complete("app"):
print(f" {word}")
5. 트라이 vs 다른 자료구조 비교
| 항목 | 트라이 | 해시맵 | BST | B-Tree |
|---|---|---|---|---|
| 검색 | O(m) | O(m)* | O(m log n) | O(m log n) |
| 삽입 | O(m) | O(m)* | O(m log n) | O(m log n) |
| 접두사 검색 | O(m) ✓ | X | O(m log n) | X |
| 자동완성 | O(m+k) ✓ | X | 복잡 | X |
| 공간 효율 | 낮음 | 높음 | 중간 | 중간 |
| 정렬 | 자동 정렬 O | X | O | O |
| 충돌 | 없음 | 있음 | 없음 | 없음 |
*해시맵: 평균 O(1)이나 해시 충돌·계산 비용 있음
결론:
- 접두사 검색, 자동완성 → 트라이 압도적 우위
- 단순 키-값 조회 → 해시맵
- 정렬 + 범위 검색 → B-Tree (DB 인덱스)
6. 복잡도 분석
| 연산 | 시간복잡도 | 공간복잡도 |
|---|---|---|
| 삽입 | O(m) | O(m) |
| 검색 | O(m) | O(1) |
| 접두사 검색 | O(m) | O(1) |
| 자동완성 | O(m + k) | O(k) |
| 삭제 | O(m) | O(1) |
| 전체 공간 | - | O(ALPHABET × N × M) |
m = 단어 길이, k = 결과 단어 수, N = 단어 수
8. 압축 트라이 (Compressed Trie / Radix Tree)
일반 트라이: 압축 트라이 (단일 자식 압축):
r - o - m - a - n "roman"
├ - n - s "romans"
└ - e "rome"
↓ 압축
ro
├── man ← "roman"
│ └── s ← "romans"
└── me ← "rome"
메모리 절약, 구현 복잡
Patricia Trie, Radix Tree라고도 함
Ⅲ. 기술 비교 분석
비교표를 통해 주요 기술과 차이점을 분석한다.
Ⅳ. 실무 적용 방안
7. 활용 사례
- 검색 엔진 자동완성: Google 검색창 suggestion
- 사전 앱: 단어 검색 및 접두사 필터
- IP 라우팅: IP 주소 접두사 매칭 (CIDR)
- 컴파일러 어휘 분석: 예약어/식별자 빠른 조회
- 스펠 체커: 단어 유효성 검사
9. 실무에선? (기술사적 판단)
- 검색 자동완성: 접두사 O(m) 검색이 해시보다 훨씬 적합
- IP 라우팅 테이블: 최장 접두사 매칭 (Longest Prefix Match)
- 노출 제한: 단어 필터 (금칙어 검사)
- 기술사 포인트: 트라이 구조, 삽입·검색 O(m), 해시맵과의 비교
Ⅴ. 기대 효과 및 결론
| 효과 영역 | 내용 | 정량적 목표 |
|---|---|---|
| 알고리즘 효율 | 최적 알고리즘 적용으로 복잡도 대폭 감소 | O(n²) → O(n log n) 수준 개선 |
| 시스템 성능 | 빠른 자료구조·탐색 알고리즘으로 응답 시간 단축 | 대용량 데이터 처리 10배 향상 |
| 의사결정 품질 | 통계적 검증으로 신뢰 있는 데이터 기반 판단 제공 | 의사결정 오류율 50% 감소 |
결론
트라이 (Trie) 자료구조은(는) 알고리즘과 통계는 AI·머신러닝의 수학적 기반으로, XAI(설명 가능한 AI)·양자 알고리즘·AutoML 등을 통해 AI의 정확성과 신뢰성을 높이는 방향으로 지속 발전하고 있다.
※ 참고 표준: CLRS 'Introduction to Algorithms', NIST SP 800-90A(난수 생성), IEEE Data Engineering Bulletin
어린이를 위한 종합 설명
트라이 자료구조를 쉽게 이해해보자!
문자열 검색에 특화된 트리 계열 자료구조. 공통 접두사를 공유하는 문자열들을 계층적으로 저장한다. 검색·삽입 O(m) (m=문자열 길이), 해시맵보다 접두사 검색·자동완성에
왜 필요할까?
기존 방식의 한계를 넘기 위해
어떻게 동작하나?
복잡한 문제 → 트라이 자료구조 적용 → 더 빠르고 안전한 결과!
핵심 한 줄:
트라이 자료구조 = 똑똑하게 문제를 해결하는 방법
비유: 트라이 자료구조은 마치 요리사가 레시피를 따르는 것과 같아. 혼란스러운 재료들을 정해진 순서대로 조합하면 → 맛있는 요리(최적 결과)가 나오지! 🍳