Skip to main content

Command Palette

Search for a command to run...

자료구조 Trie

Published
3 min read

Trie란?

Trie는 문자열 탐색에 특화된 트리 기반의 자료구조로, Prefix Tree(접두사 트리) 라고도 불립니다.

문자열의 접두사(prefix)를 기준으로 구조화되어 있기 때문에, 자동완성, 사전 검색, 검색 최적화 등에서 널리 활용됩니다.

아래의 Trie에 들어있는 문자열

apple, april, bus, busy, beer, best

주요 특징

  • 각 노드는 문자열의 한 글자를 저장

  • 루트 노드는 빈 문자열을 나타냄

  • 같은 접두사를 공유하는 단어들끼리 같은 경로를 따라감 → 공간 효율이 높음

  • 노드마다 ‘isEndOfWord’ 플래그를 통해 단어의 끝인지 여부를 판단 (파란 노드)

노드 정의

public class TrieNode {

    private HashMap<Character, TrieNode> children = new HashMap<>();
    //현재 노드에서 이어질 수 있는 문자들과 그에 대응하는 하위 TrieNode들을 저장하는 map

    private boolean isEndOfWord = false;  // 어떤 단어의 마지막 글자인지를 나타내는 플래그

    public HashMap<Character, TrieNode> getChildren() {
        return children;
    }

    public boolean isEndOfWord() {
        return isEndOfWord;
    }

    public void setEndOfWord(boolean isEndOfWord) {
        this.isEndOfWord = isEndOfWord;
    }
}

기본 연산 구현

1. 삽입 (Insert)


public void insert(String word) {
    TrieNode current = root;
    for (char ch : word.toCharArray()) {
        current = current.getChildren().computeIfAbsent(ch, c -> new TrieNode());
    }
    current.setEndOfWord(true);
}
  • 한 글자씩 순회하며 존재하지 않으면 새 노드를 생성

  • 마지막 글자 노드에는 isEndOfWord를 true로 설정

  • 시간 복잡도 : O(n) (n= 문자열 길이)


public boolean search(String word){
    TrieNode current = root;
    for(char ch : word.toCharArray()){
        TrieNode node = current.getChildren().get(ch);
        if(node == null) return false;
        current = node;
    }
    return current.isEndOfWord();
}
  • 한 글자씩 트리를 따라가며 , 노드가 없으면 false

  • isEndOfWord가 true이면 해당 단어가 존재


3. 삭제 (Delete)

// Trie에서 문자열을 삭제하는 메서드 (사용자 호출용)
public void delete(String word) {
    delete(root, word, 0);
}

/**
 * Trie에서 재귀적으로 문자열을 삭제하는 내부 메서드
 *
 * @param current 현재 탐색 중인 노드
 * @param word 삭제하려는 문자열
 * @param index 현재 탐색 중인 문자 인덱스
 * @return 현재 노드를 삭제할 수 있는지 여부 (true면 상위 노드에서 이 노드를 삭제해도 됨)
 */
private boolean delete(TrieNode current, String word, int index) {
    // 문자열의 끝까지 도달한 경우
    if (index == word.length()) {
        // 현재 노드가 단어의 끝이 아니라면, Trie에 존재하지 않는 단어 → 삭제 실패
        if (!current.isEndOfWord()) {
            return false;
        }

        // 단어의 끝 표시를 제거
        current.setEndOfWord(false);

        // 자식 노드가 없다면 상위 노드에서 이 노드를 삭제할 수 있도록 true 반환
        return current.getChildren().isEmpty();
    }

    // 현재 문자 하나 가져오기
    char ch = word.charAt(index);

    // 해당 문자가 자식 노드에 없다면 → 존재하지 않는 단어 → 삭제 불가
    TrieNode node = current.getChildren().get(ch);
    if (node == null) {
        return false;
    }

    // 자식 노드에서 삭제 재귀 수행
    // 1. 자식 노드에서 단어 삭제가 완료되었고
    // 2. 그 자식 노드가 더 이상 단어의 끝이 아니면
    // → 현재 노드에서 해당 자식 노드를 삭제할 수 있음
    boolean shouldDeleteCurrentNode =
            delete(node, word, index + 1) && !node.isEndOfWord();

    // 자식 노드를 삭제해도 된다면, 현재 노드의 자식 목록에서 해당 문자 제거
    if (shouldDeleteCurrentNode) {
        current.getChildren().remove(ch);

        // 현재 노드도 더 이상 자식이 없다면 true 반환 → 상위 노드에서도 삭제 가능
        return current.getChildren().isEmpty();
    }

    // 삭제할 수 없는 경우 (예: 해당 노드가 다른 단어의 일부일 경우)
    return false;
}

참고 자료 : https://www.baeldung.com/trie-java,https://innovation123.tistory.com/116

자료구조

Part 1 of 1

More from this blog

낙관적 락(Optimistic Lock)과 비관적 락(Pessimistic Lock)

락(Lock)의 필요성 현대 애플리케이션은 대부분 동시성(Concurrency) 문제에 직면합니다. 여러 사용자나 프로세스가 동시에 같은 데이터를 수정하거나, 은행 계좌 이체와 같은 중요한 트랙잭션을 동시에 실행하는 경우가 있습니다. 이때 동시 접근을 적절히 제어하지 않으면, 데이터 불일치, 중복 처리, 시스템 오류까지 발생할 수 있습니다. 이를 방지하기 위해 락(Lock) 개념이 도입되었습니다. 락은 여러 프로세스나 스레드가 동시에 동일한 자...

Aug 22, 20253 min read

Java 프로그램이 실행되는 흐름

자바 프로그램은 단순히 .java 파일을 실행하는 것이 아니라, 컴파일 → 로드 → 실행 이라는 여러 단계를 거쳐 최종적으로 CPU 가 이해할 수 있는 기계어로 변환됩니다. 이 과정에서 JDK, JVM, JRE가 각각 어떤 역할을 하는지 이해하는 것이 중요합니다. 1. 소스 코드 작성과 컴파일 개발자는 자바 소스 파일(.java)을 작성 JDK 에 포함된 javac (Java Compiler)가 소스 코드를 컴파일 하여 JVM이 이해할 수...

Aug 21, 20252 min read

Java Collection Framework

컬렉션 프레임워크(Collection Framework)란? 자바에서 컬렉션 프레임워크란 다수의 데이터를 쉽고 효과적으로 처리할 수 있는 표준화된 방법을 제공하는 클래스와 인터페이스 집합입니다. 즉, 데이터를 저장하는 자료구조과 데이터를 처리하는 알고리즘을 구조화하여 클래스로 구현한 것입니다. 모든 컬렉션 프레임워크는 자바의 인터페이스를 기반으로 구현됩니다. JFC(Java Collection Framework)의 도입 배경 JCF 이전에는 ...

Aug 14, 20254 min read

운영체제의 발전: 단일 프로세스에서 멀티코어까지

운영체제의 발전은 ‘CPU를 얼마나 효율적으로 활용하느냐’의 역사라고 볼 수 있습니다. 초기에는 한 번에 하나의 프로그램만 실행했지만, 점차 CPU 사용률과 사용자 경험을 높이기 위해 멀티프로그래밍, 멀티태스킹, 멀티프로세스, 멀티스레딩, 그리고 멀티코어 구조가 발전했습니다. 들어가기에 앞서 프로세스와 스레드에 대해 간단히 설명하겠습니다. 프로세스(Process) 실행 중인 프로그램으로 OS로부터 독립된 주소 공간과 자원을 할당 받음 각 ...

Aug 13, 20252 min read

Keep-Alive (HTTP Keep-Alive와 TCP Keep-Alive)

Keep-Alive는 연결(Connection)을 계속 유지하기 위한 메커니즘입니다. 네트워크에서 어떤 연결을 만들고, 요청/응답을 주고받은 후 바로 끊지 않고 일정 시간 동안 유지하면, 그 시간 안에 들어오는 추가 요청은 이미 열린 연결을 재사용할 수 있습니다. 이를 통해 매번 연결을 새로 맺는데 필요한 오버헤드(3-Way Handshake)를 줄일 수 있고, 불필요한 지연(latency)를 감소시킬 수 있습니다. 하지만 연결을 너무 오래 유...

Aug 12, 20252 min read

gaeng

22 posts