읽고 나면 진짜 쉬워지는 자료 구조 - 6. 트라이와 적응형 자료 구조

이진 탐색 트리에서 문자열의 특성을 추가로 고려해 최적화한 자료 구조

🔖 6.1 문자열로 이뤄진 이진 탐색 트리

이진 탐색 트리의 한계

  • 이진 탐색 트리는 순서대로 정렬할 수 있는 것은 모두 저장할 수 있다.

  • 언뜻 보기에는 이진 탐색 트리는 문자열 데이터를 탐색하는 간단하고 효율적인 메커니즘을 제공하는 것 같다.

  • 하지만 각각 비교하는 데에 드는 비용을 주목해야 한다.

  • 최악의 경우 문자열 비교 연산 비용은 문자열 자체 길이에 비례한다.

문자열 비교의 비용과 한계

  • 이진 탐색 트리에서 문자열에 대한 순차 비교는 두 수의 비교보다 더 비싸다.

  • 많은 언어에서 문자열의 각 위치에 포함될 수 있는 문자가 많지 않다는 점도 있다.

🔖 6.2 트라이

트라이란?

  • 문자열을 접두사를 기준으로 다른 하위 트리로 분할하는 트리 기발 자료구조다.

  • 각 노드에서 데이터를 두 집합으로 분할하는 대신, 트라이는 지금까지의 접두사를 기준으로 트리의 가지를 나눈다.

  • 느린 메모리 접근 속도를 가진 컴퓨터에서 파일 탐색을 개선하기 위해 등장했다.

트라이의 특징

  • 트라이의 각 노드는 지금까지 비교한 문자열의 접두사를 나타낸다.

  • 이진 탐색 트리와 마찬가지로 트라이 또한 루트 노드에서 시작하며, 각 노드는 둘 이상의 자식을 가질 수 있다.

  • 트라이는 모든 노드에서 극적인 다중 분기를 수행한다.

  • 이진 탐색 트리와는 다르게 트라이에서는 모든 노드가 항목을 나타내진 않는다.

  • 현재 노드의 접두사 등 유용한 정보를 트라이 노드에 저장할 수 있다.

트라이 탐색하기

  • 전체 문자열을 비교하거나 접두사 앞 부분은 비교할 필요가 없어 효율적이다.

  • 코드로 구현한다면 현재 단계에서 확인해야 하는 문자의 위치를 나타내는 인덱스를 재귀 함수에 전달해 추적할 수 있다.

  • Trie wrapper를 사용하면 루트 노드에 대한 참조와 재귀 함수에 필요한 카운터를 숨겨 단순화할 수 있다.

  • 이진 탐색 트리와는 달리 성공적인 트라이 탐색의 비교 횟수는 트라이에 저장된 문자열의 갯수와 무관하다.

트라이 탐색 코드

function TrieNodeSearch(current, target, index) {
  if (index === target.length) { // ①
    if (current.isEntry) {
      return current;
    } else {
      return null;
    }
  }

  const nextLetter = target[index]; // ②
  const nextIndex = LetterToIndex(nextLetter); // ③
  const nextChild = current.children[nextIndex]; // ④

  if (nextChild === null) {
    return null;
  } else {
    return TrieNodeSearch(nextChild, target, index + 1);
  }
}

// LetterToIndex는 특정 문자(nextLetter)를 인덱스 숫자로 변환하는 함수
// current는 현재 노드를 나타내고, target은 탐색할 문자열이며, index는 현재 탐색 중인 문자열의 위치

노드 추가와 제거

  • 트라이도 이진 탐색 트리와 같이 데이터 변화를 정확하게 표현하는 동적 자료 구조다.

  • 이진 탐색 트리에서의 삽입과는 달리 한 항목을 삽입하는 동안 노드를 여러 개 추가할 수 있다.

🔖 6.3 트라이가 중요한 이유

트라이의 이점

  • 더 많은 문자열을 추가하고 공통 접두사를 가지는 문자열 수가 늘어날수록 트라이가 더 효율적이다.

  • 문자열 비교 자체가 비용이 많이 들어, 공통 접두사를 기준으로 확인하고 비교한다면 큰 이점을 얻을 수 있다.

트라이 사용 예시

  • 짧은 알파벳과 숫자로 이루어진 시리얼 번호, 모델 번호 등 구조적 레이블 추적 자료 구조

  • 수십억 개의 제품이 있더라도 시리얼 번호의 접두사를 활용하면 저장 공간을 절약할 수 있다.

  • 핵심은, 연산 비용을 최적화할 때 문자열의 구조를 더 활용할 수 있다는 점이다.

Last updated