Data Structure, Trie & JAVA구현
TrieNode.java
package org.dataStructure;
import java.util.HashMap;
import java.util.Map;
// 자식노드맵 + 현재 노드가 마지막 글자인지 여부 (한 단어가 완성되는 시점임을 알 수 있다)
public class TrieNode {
// 자식 노드 맵
private Map<Character, TrieNode> childNodes = new HashMap<>();
// 마지막 글자인지 여부
private boolean isLastChar;
Map<Character, TrieNode> getChildNodes(){
return this.childNodes;
}
boolean isLastChar() {
return this.isLastChar;
}
void setIsLastChar(boolean isLastChar) {
this.isLastChar = isLastChar;
}
}
Trie.java
package org.dataStructure;
// Trie는 기본적으로 빈 문자열을 가지는 루트노드만 가지고 있다.
// insert메서드를 통해 단어를 입력하면서 그에 맞게 자식 노드가 생성된다.
public class Trie {
// 루트 노드
private TrieNode rootNode;
Trie() {
rootNode = new TrieNode();
}
// 자식 노드 추가
void insert(String word) {
TrieNode thisNode = this.rootNode;
for (int i = 0; i < word.length(); ++i) {
thisNode = thisNode.getChildNodes().computeIfAbsent(word.charAt(i), c -> new TrieNode());
}
// 계속해서 thisNode를 갱신하기 때문에 마지막 글자가 되므로 true.
thisNode.setIsLastChar(true);
}
// 특정 단어가 Trie에 존재하는지 확인
// 1. 루트노드 부터 순서대로 알파벡이 일치하는 자식노드들이 존재 할것
// 2. 해당 단어의 마지막 글자에 해당하는 노드의 isLastChar == true 일것
boolean contains(String word) {
TrieNode thisNode = this.rootNode;
for (int i = 0; i < word.length(); ++i) {
char character = word.charAt(i);
TrieNode node = thisNode.getChildNodes().get(character);
if (node == null)
return false;
thisNode = node;
}
return thisNode.isLastChar();
}
// 삭제
// 탐색 : 부모노드 -> 자식노드
// 삭제 : 자식노드 -> 부모노드
// 1. 자식 노드를 가지고 있지 않아야 합니다.
// 삭제시, 자식노드까지 지우면 안된다.
// 2. 삭제 시작 첫 노드는 isLastChar == true여야한다.
// false이면 존재하지 않는 단어이기 때문에 삭제 불가능.
// 3. 삭제 진행 중에는 isLastChar == false 여야한다.
// true이면 다른 단어가 존재하기 때문에 삭제하면 안된다.
void delete(String word) {
delete(this.rootNode, word, 0); // 최초로 delete 시작.
}
private void delete(TrieNode thisNode, String word, int index) {
char character = word.charAt(index);
// 단어가 아예존재 하지 않는경우 , ex) ABC , DEF
if (!thisNode.getChildNodes().containsKey(character))
throw new Error("There is no [" + word + "] in this Trie.");
// 글자가 존재하는 trieNode를 가져온다
TrieNode childNode = thisNode.getChildNodes().get(character);
index++;
// 탐색완료
if (index == word.length()) {
// 삭제 조건 2번 항목
if (!childNode.isLastChar())
throw new Error("There is no [" + word + "] in this Trie.");
childNode.setIsLastChar(false);
// 삭제 조건 1번 항목
if (childNode.getChildNodes().isEmpty())
thisNode.getChildNodes().remove(childNode);
} else {
// 콜백함수
delete(childNode, word, index);
// 콜백함수로 인해서 단어 탐색이 완료된 후에 이부분이 불린다.
// 삭제 조건 1, 3번 항목
// 자식노드가 없고, 현재 노드로 끝나는 단어가 없는 경우 이 노드 삭제
if (!childNode.isLastChar() && childNode.getChildNodes().isEmpty())
thisNode.getChildNodes().remove(character);
}
}
boolean isRootEmpty() {
return this.rootNode.getChildNodes().isEmpty();
}
}
TrieTest.java
package org.dataStructure;
public class TrieTest {
public static void main(String[] args) {
Trie trie = new Trie();
trie.insert("DEV");
trie.insert("DEAR");
trie.insert("DESERVE");
trie.insert("DRIVE");
System.out.println(trie.contains("DEAR"));
System.out.println(trie.contains("DESERT"));
//trie.delete("DESERT");
//trie.delete("DE");
trie.delete("DEAR");
System.out.println(trie.contains("DEAR"));
}
}
참고