2024-03-28,   이현지

본 포스팅은 Trie 자료 구조를 구현하는 방법에 대한 글입니다.



Trie 자료구조

Retrieval Tree(탐색 트리)의 약자
문자열을 저장하고 효율적으로 탐색하기 위한 트리 기반의 자료 구조


장점 및 활용

  • 문자열 검색 시간 단축
    for문의 경우 특정 문자열을 찾기 위해 전체 문자열을 순회해야 함
    Trie 구조는 문자열 길이만큼 노드를 검사하면 됨

  • 자동 완성 검색과 사전 탐색에 유용함


단점

  • 메모리 측면에서 비효율적
    각 노드가 자식 노드들을 저장하고 있음


구조 (트리 구조와 동일)

trie 구조 예시

  • 루트 노드 : 시작 노드
  • 노드 : 각 노드는 하나의 문자를 표현. 루트노드부터 특정 노드까지의 경로 하나의 문자열을 나타냄
  • 포인터 : 부모 노드와 자식 노드 연결


구현

Map<Character, Node>

  • key : 문자
  • value : 자식 노드 객체

trie 구현 예시


소스 코드

public class Trie {

	@Data
	private class Node {
				
		/** 자식 노드 목록 맵 */
		private Map<Character, Node> childNodeMap = new HashMap<>();
        /** 터미널 노드 여부 */
        private boolean terminal;
        
	}

	
	/** 루트 노드 */
	private Node rootNode = new Node();	


	/**
	 * Trie에 문자열 저장
	 * 
	 * @param str 
	 * @throws Exception
	 */
	public void insert(String str) throws Exception {
				
		// 현재 노드 (for문에서 다음 문자로 넘어갈 때마다 현재 노드의 자식 노드로 넘어감)
		Node currNode = this.rootNode;

		// 각 문자마다 현재 노드의 자식 노드에 있는지 검사
	    for(int charIndex = 0; charIndex < str.length(); charIndex++) {
	    	
	    	// 현재 문자
	    	char currentChar = str.charAt(charIndex);
	    	
	    	// 현재 문자가 자식 노드에 있으면 해당 자식 노드를 현재 노드로 저장 
	    	// 아니면 현재 문자를 자식 노드로 새로 생성하고, 해당 노드를 현재 노드로 저장
	    	// computeIfAbsent() : Map에 특정키에 해당하는 값이 존재하는지 확인 후 있으면 해당 값 반환, 없으면 새로 만들어서 추가 후 반환
	    	currNode = currNode.childNodeMap.computeIfAbsent(currentChar, key -> new Node());
	    		    
	    }
		
        // 마지막 문자 표시
        currNode.terminal = true;
        
	}

	
	/**
	 * Trie에서 문자열 검색
	 * 
	 * @param target 검색할 문자열
	 * @return 검색 결과가 있을 경우 true, 없을 경우 false
	 * @throws Exception
	 */
	public boolean search(String target) throws Exception {
		//TODO 기준 문자열 받아서 목록 문자열과 비교

		// 현재 노드 (for문에서 다음 문자로 넘어갈 때마다 현재 노드의 자식 노드로 넘어감)
		Node currNode = this.rootNode;

		// 문자열의 각 문자마다 노드가 존재하는지 체크
		for(int charIndex = 0; charIndex < target.length(); charIndex++) {
			
			// 현재 문자
			char currChar = target.charAt(charIndex);
			// 현재 문자가 현재 노드의 자식 노드로 존재하면 해당 자식 노드를 현재 노드로 저장
            // 아니면 null
			currNode = currNode.childNodeMap.getOrDefault(currChar, null);
			
			if(currNode == null) {
				
				// 현재 노드가 null이면 일치하는 문자열 없음
				return false;
	        
			}
		
		}
		
		// target 문자열(예. ABC)의 마지막 문자(C)까지 일치하고, 
        // 현재 노드가 마지막 노드인지도 확인해야 함 (ABC != ABCD)
		return currNode.terminal;

	}
	
	
}


저장 및 검색 테스트

public static void main(String[] args) throws Exception {

    Trie trie = new Trie(); 

    // 문자열 저장
    trie.insert("car");
    trie.insert("cake");
    trie.insert("cute");
    trie.insert("key");
    trie.insert("keep");

    // 문자열 검색
    System.out.println(trie.search("car"));
    System.out.println(trie.search("carr"));
    System.out.println(trie.search("cake"));
    System.out.println(trie.search("caker"));
    System.out.println(trie.search("cute"));
    System.out.println(trie.search("cutie"));
    System.out.println(trie.search("key"));
    System.out.println(trie.search("kenya"));
    System.out.println(trie.search("keep"));
    System.out.println(trie.search("kep"));

}


이상으로 Trie 자료 구조를 구현하는 방법에 대해 알아보았습니다.



Reference

  • https://velog.io/@kimdukbae/%EC%9E%90%EB%A3%8C%EA%B5%AC%EC%A1%B0-%ED%8A%B8%EB%9D%BC%EC%9D%B4-Trie
  • https://codingnojam.tistory.com/40

업데이트: