Skip to content

Latest commit

 

History

History

Trie

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 
 
 
 
 

README.md

Trie (트라이, 접두사 트리) (2026-07-28)

특징

  • 문자열의 집합을 표현하는 트리 자료구조 (Prefix Tree)
  • 루트에서 노드로 내려가는 경로가 곧 문자열의 접두사가 됨
  • 접두사가 같은 문자열끼리 앞부분 노드를 공유함
  • BST에서 문자열 검색은 O(M log N)이지만, 트라이는 문자열 개수 N과 무관하게 O(M) (M = 문자열 길이, N = 집합에 든 문자열 개수)

구조

  • 배열(children[26]) 방식으로 구현 — 소문자 a~z만 대상
  • 노드는 글자를 직접 저장하지 않음 → "부모의 몇 번째 칸에 매달렸는가"로 글자를 표현
    • idx = ch - 'a' (a=0, b=1, ... z=25) → 칸 번호가 곧 글자
  • isEnd(빨간 노드) = "이 노드에서 끝나는 문자열이 있다"는 표시 → 이게 사실상 삽입의 핵심

핵심 개념

  • insert: 글자마다 자식 노드를 따라가거나 없으면 생성, 마지막에 isEnd = true
  • search: 경로 끝까지 도달 + isEnd == true 여야 true (단어 자체가 있는지)
  • startsWith: 경로만 존재하면 true (그 접두사로 시작하는 단어가 있는지)
  • search vs startsWith: "hi", "high"만 넣었을 때 search("h")는 false지만 startsWith("h")는 true
  • static 중첩 클래스: Node를 static class로 선언 → 바깥 Trie 참조(숨은 필드)를 없애 메모리 절약 (노드가 수십만 개 생기므로 노드마다 붙는 숨은 참조가 그대로 낭비가 됨)

시간 복잡도

연산 시간 복잡도
삽입 (insert) O(M)
검색 (search) O(M)
접두사 검색 (startsWith) O(M)
삭제 (delete) O(M)
  • N(문자열 개수)과 무관하게 오직 문자열 길이 M에만 비례 (BST의 log N 항이 사라짐)

장단점

  • 장점: 문자열 삽입/검색이 O(M), 접두사 기반 연산(자동완성 등)에 강함
  • 단점: 메모리 낭비가 큼 — 배열 방식은 노드마다 안 쓰는 칸까지 26개를 확보
    • 총 메모리 ≈ O(포인터 크기 × 26 × 총 노드 수)
    • 완화: 배열 대신 HashMap<Character, Node>로 실제 등장한 문자만 저장

삭제 (delete) — 재귀로 내려갔다 올라오며 처리

  • 삭제 방식은 2가지
    1. isEnd만 끄기: node.isEnd = false 한 줄. 노드는 남고 검색만 실패 (메모리 낭비)
    2. 노드까지 회수: children[idx] = null(map은 remove)로 연결을 끊음 → GC가 수거 (우리 구현)
  • 재귀 2단계
    • 내려가는 길: 글자를 따라 단어 끝까지 감 → 끝에서 isEnd = false (이게 삭제 본체)
    • 올라오는 길: 각 노드가 "나 지워도 되나?"를 아래에서부터 판단
  • 노드를 실제로 지우는 조건 (둘 다 만족)
    1. 다른 단어의 끝이 아님 (isEnd == false)
    2. 자식이 하나도 없음 (아무도 그 경로를 안 씀)
  • 반환값의 의미: delete(...)의 return 값 = "부모야, 방금 다녀온 이 노드 끊어도 돼?"
    • true → 부모가 children[idx] = null로 실제로 끊음
    • false → 남겨야 함. 여기서 연쇄가 멈춤

기타 메모

  • 트라이는 문자열을 통째로 저장하지 않음 → 글자는 칸 위치로, 단어 존재는 isEnd로 나눠 표현
  • 문자열 특화 자료구조라 제네릭(Trie)보다 String 입력으로 고정하는 게 자연스러움
  • 소문자 외 입력(대문자/공백/숫자)이 들어오면 idx가 0~25 범위를 벗어나 예외 발생 주의
  • 자바 GC: children[idx] = null로 참조를 끊으면 아무도 안 가리키는 노드는 자동 회수됨

Trie - HashMap 방식 구현 (2026-08-03)

왜 필요한가

  • 배열 방식은 노드마다 안 쓰는 칸까지 26개를 확보 → 메모리 낭비
  • HashMap 방식은 실제 등장한 문자만 저장 → 메모리 절약 + 소문자 외 문자도 자연스럽게 처리

구조

  • Node[] children (배열 26칸) → Map<Character, Node> children (HashMap) 으로 교체
  • 로직(insert/search/startsWith/delete)은 배열 버전과 100% 동일 — 자식 저장/접근 방식만 바뀜

핵심 개념

  • idx = ch - 'a' 변환이 사라짐: 배열은 "몇 번째 칸"이 글자였지만, map은 문자 ch를 그대로 key로 씀
  • isEmpty() 헬퍼 삭제: 배열은 26칸을 직접 순회했지만, map은 children.isEmpty() 한 줄로 대체
  • 범위 예외 걱정 없음: 대문자·숫자·한글도 key로 그대로 사용 가능

배열 vs HashMap 방식

항목 배열 children[26] HashMap
자식 저장 항상 26칸 확보 등장한 문자만 저장
접근 속도 O(1) (가장 빠름) 평균 O(1), TreeMap은 O(log k)
메모리 낭비 큼 절약
적합한 상황 문자 종류 적고 고정 (a~z) 문자 종류 많음(유니코드/한글), 메모리 제한

기타 메모

  • 시간 복잡도는 배열 버전과 동일 (모든 연산 O(M))