컴퓨터 과학에서 탐색 트리의 일종.
동적 집합이나 연관 배열을 저장하는데 사용되는 트리 자료 구조.
주로 문자열이 키인 경우가 많다.
이진 탐색 트리와 달리 트리의 어떤 노드도 그 노드 자체와 연관된 키는 저장하지 않는다.
대신 노드가 트리에서 차지하는 위치가 연관된 키를 정의한다.
즉, 키의 값은 자료 구조 전체에 분산된다.
노드의 모든 자손은 노드에 연관된 문자열의 공통 접두사를 공유한다.
루트는 빈 문자열에 연관된다.
일부 내부 노드가 키에 대응할 수도 있지만, 일반적으로 키는 단말에 연관되는 경향이 있다.
따라서 모든 노드가 꼭 키와 연결되지는 않는다.
메모리에 최적화 된 경우는 기수 트리가 된다.
예시에서 키는 노드에, 값은 그 아래에 있다.
완전한 단어 키마다 연관된 임의의 정수가 있는 식이다.
트라이는 트리 모양인 결정적 유한 오토마타로 볼 수도 있다.
트라이 오토마타로 생성한 각 유한 언어는 결정적 비순환 유한 상태 오토마타로 압축할 수 있다.
트라이는 문자열이 키인 경우가 흔하지만, 꼭 그래야 하는 것은 아니다.
어떻게 구성된 정렬된 리스트라도 비슷한 기능을 제공할 수 있는 동등한 알고리즘을 적용할 수만 있다면 상관 없다.
이를테면 숫자나 도형의 리스트로 구성한 순열 같은 것이 가능하다.
정수나 메모리 주소 같은 고정 길이 이진 자료를 표현하는 각각의 비트로 구성된 트라이를 특별히 비트 트라이라고 부른다.
해시테이블을 대체하여 사용 가능하며 이진 검색 트리에 비해 몇 가지 장점이 있다.
트라이는 탐색과 삽입을 지원하는 노드로 구성된 트리.
탐색 - 키 문자열과 연관된 값을 반환
삽입 - 문자열(키)과 그 값을 삽입
키의 길이가 m일 때 탐색과 삽입 모두 O(m) 시간에 수행된다.
package algorithm;
import java.util.HashMap;
import java.util.Map;
public class SelfTrie {
class NodeTrie {
Map<Character, NodeTrie> childNodes = new HashMap<>();
boolean isLastChar;
Map<Character, NodeTrie> getChildNodes() {
return this.childNodes;
}
boolean isLastChar() {
return this.isLastChar;
}
void setIsLastChar(boolean isLastChar) {
this.isLastChar = isLastChar;
}
}
NodeTrie rootNode;
SelfTrie() {
rootNode = new NodeTrie();
}
void insert(String word) {
NodeTrie curNode = this.rootNode;
for (int i = 0; i < word.length(); i++) {
curNode = curNode.getChildNodes().computeIfAbsent(word.charAt(i),
c -> new NodeTrie());
}
curNode.setIsLastChar(true);
}
boolean contains(String word) {
NodeTrie curNode = this.rootNode;
for (int i = 0; i < word.length(); i++) {
char character = word.charAt(i);
NodeTrie node = curNode.getChildNodes().get(character);
if (node == null)
return false;
curNode = node;
}
return curNode.isLastChar();
}
void delete(String word) {
delete(this.rootNode, word, 0);
}
void delete(NodeTrie curNode, String word, int index) {
char character = word.charAt(index);
if (!curNode.getChildNodes().containsKey(character))
throw new Error("There is no [" + word + "] in this Trie.");
NodeTrie childNode = curNode.getChildNodes().get(character);
index++;
if (index == word.length()) {
if (!childNode.isLastChar())
throw new Error("There is no [" + word + "] in this Trie.");
childNode.setIsLastChar(false);
if (childNode.getChildNodes().isEmpty())
curNode.getChildNodes().remove(character);
} else {
delete(childNode, word, index);
if (!childNode.isLastChar() && childNode.getChildNodes().isEmpty())
curNode.getChildNodes().remove(character);
}
}
boolean isRootEmpty() {
return this.rootNode.getChildNodes().isEmpty();
}
public static void main(String[] args) {
SelfTrie trie = new SelfTrie();
System.out.println("isRootEmpty: " + trie.isRootEmpty());
trie.insert("PI");
trie.insert("PIE");
trie.insert("POW");
trie.insert("POP");
System.out.println("isRootEmpty: " + trie.isRootEmpty());
System.out.println("does contain POW: " + trie.contains("POW"));
System.out.println("does contain PIES: " + trie.contains("PIES"));
trie.delete("POP");
System.out.println("does contain POP: " + trie.contains("POP"));
System.out.println("does contain POW: " + trie.contains("POW"));
}
}