데이터 구조 시리즈 - 트 리

트 리, 즉 사전 트 리, 단어 찾기 트 리 나 키 트 리 라 고도 부 르 며 트 리 구조 로 해시 트 리 의 변종 이다.전형 적 인 응용 은 대량의 문자열 을 통계 하고 정렬 하 는 데 사용 되 기 때문에 검색엔진 시스템 에서 텍스트 주파수 통계 에 자주 사용 된다.불필요 한 문자열 비 교 를 최대한 줄 이 고 해시 표 보다 조회 효율 이 높다 는 것 이 장점 이다.
트 리 구조
Trie 의 핵심 사상 은 공간 교환 시간 이다. 문자열 의 공공 접 두 사 를 이용 하여 조회 시간의 비용 을 낮 추어 효율 을 높이 는 목적 을 달성 하 는 것 이다.
예 를 들 어 tea, ten, to, in, inn, int 라 는 단 어 를 하나의 Trie 나무 로 구축 하고 구체 적 인 Tried 나무의 구 조 를 살 펴 보 자.
그림: 트 리 구조
그림 에서 트 리 의 일부 특성 을 볼 수 있다.
  • 뿌리 노드 는 문 자 를 포함 하지 않 고 뿌리 노드 를 제외 한 모든 노드 는 하나의 문자 만 포함 합 니 다.
  • 뿌리 노드 에서 특정한 노드 까지 경로 에 있 는 문 자 를 연결 하여 이 노드 에 대응 하 는 문자열 입 니 다.
  • 각 노드 의 모든 하위 노드 에 포 함 된 문 자 는 같 지 않다.

  • 트 리 구현
    Trie 트 리 의 삽입, 삭제, 찾기 동작 은 모두 같 습 니 다. 트 리 를 간단하게 한 번 옮 겨 다 니 면 됩 니 다. 시간 복잡 도: O (n) (n 은 문자열 의 길이).Tried 트 리 의 실현 은 배열 과 링크 두 가지 방식 을 사용 할 수 있 습 니 다.
  • 배열: 우 리 는 Tried 트 리 노드 의 하위 노드 의 수량 이 26 개 로 고정 되 어 있다 는 것 을 알 기 때문에 노드 의 하위 노드 를 고정 적 으로 저장 할 수 있다.
  • 장점: 하위 노드 를 찾 을 때 속도 가 빠르다
  • 단점: 공간 을 낭비 하고 관 이 없 는 노드 가 몇 개 있 으 며 항상 26 개의 공간
  • 을 분배 해 야 한다.
  • 링크: 링크 를 사용 하면 우 리 는 모든 하위 노드 에 형제 노드 의 링크 를 저장 해 야 한다. 우리 가 한 노드 의 하위 노드 에서 문자 가 존재 하 는 지 찾 을 때 먼저 하위 노드 를 찾 은 다음 에 하위 노드 의 링크 를 따라 왼쪽 에서 오른쪽으로 옮 겨 다 녀 야 한다.
  • 장점: 공간 을 절약 하고 키 노드 가 있 는 만큼 공간 을 차지 하 며 공간 낭 비 를 초래 하지 않 는 다
  • 단점: 서브 노드 를 찾 는 것 이 상대 적 으로 느 리 고 링크 를 옮 겨 다 니 며 실현 하 는 것 도 배열 보다 번거롭다
  • .

    다음은 가장 간단 한 트 리 트 리 의 실현 으로 배열 방식 을 사용한다.
    /**
     * 

    * Trie , Trie , *

    * * @author Vicky * @email [email protected] * @2015 11 23 * */
    public class Trie { protected TrieNode root = new TrieNode('a');// TrieTree /** * * * @param word */ public void insertWord(String word) { TrieNode index = this.root; for (char c : word.toLowerCase().toCharArray()) { index = index.addChild(c); } return; } /** * TrieTree */ private class TrieNode { /** */ private final char nodeChar;// /** TrieTree */ private TrieNode[] childNodes = null; public TrieNode(char nodeChar) { super(); this.nodeChar = nodeChar; } public TrieNode addChild(char ch) { int index = ch - 'a'; if (null == childNodes) { this.childNodes = new TrieNode[26]; } if (null == childNodes[index]) { childNodes[index] = new TrieNode(ch); } return childNodes[index]; } @Override public String toString() { return "TrieNode [nodeChar=" + nodeChar + "]"; } } public static void main(String[] args) { Trie trie = new Trie(); trie.insertWord("Vicky"); } }

    Trie 트 리 응용
    Trie 트 리 의 응용 은 주로 문자열 처리 에 집중 되 어 있 습 니 다.(1) 문자열 검색
  • 정확 한 찾기: 문자열 을 지정 하여 어떤 문자열 이 있 었 는 지 찾 습 니 다
  • 접두사 일치: 문자열 을 지정 하고 특정한 문자열 을 접두사 로 하 는 문자열 집합 을 찾 습 니 다

  • (2) 최 장 공공 접두사
  • 문자열 의 가장 긴 공공 접 두 사 를 찾 으 려 면 이 문자열 을 Trie 트 리 로 구축 한 다음 에 노드 부터 옮 겨 다 니 며 여러 노드 가 나타 날 때 까지 (즉, 갈 라 짐)
  • (3) 정렬
  • 문자열 을 사전 순서에 따라 정렬 하고 트 리 로 구축 한 다음 에 선착순 으로 옮 겨 다 니 면 됩 니 다
  • 。。。
    다음은 트 리 트 리 의 응용 에 대해 상대 적 으로 간단 하고 대표 적 인 사례 를 선택 하 겠 습 니 다. 한 단어 에서 'vi' 로 시작 하 는 모든 문자열 을 찾 고 'Vicky' 가 나 타 났 는 지 확인 하 겠 습 니 다.(우 리 는 26 글자 만 저장 하기 때문에 대소 문 자 를 구분 하지 않 고 단어 가 아 닌 문 자 를 지원 하지 않 습 니 다.)
    인터넷 에서 다음 단어 표를 다운로드 하고 단어 표 에 따라 트 리 트 리 를 구축 하고 찾 을 수 있 습 니 다. 단어 표 는https://github.com/dwyl/english-words다운 로드 를 진행 하 다.
    package com.vicky.datastructure.tree.trie;
    
    /**
     * 

    * Trie *

    * * @author Vicky * @email [email protected] * @2015 11 23 * */
    public class PrefixTrie { private TrieNode root = new TrieNode('a');// TrieTree /** * * * @param word */ public void insertWord(String word) { TrieNode index = this.root; for (char c : word.toLowerCase().toCharArray()) { index = index.addChild(c); index.addPrefixCount(); } index.addCount(); return; } /** * * * @param word * @return */ public boolean selectWord(String word) { TrieNode index = this.root; for (char c : word.toLowerCase().toCharArray()) { index = index.getChild(c); if (null == index) { return false; } } return index.getCount() > 0; } /** * * * @param prefix * @return */ public int selectPrefixCount(String prefix) { TrieNode index = this.root; for (char c : prefix.toLowerCase().toCharArray()) { index = index.getChild(c); if (null == index) { return 0; } } return index.getPrefixCount(); } /** * TrieTree */ private class TrieNode { /** */ private final char nodeChar;// /** TrieTree */ private TrieNode[] childNodes = null; private int count = 0;// , private int prefixCount = 0;// , public TrieNode(char nodeChar) { super(); this.nodeChar = nodeChar; } public TrieNode addChild(char ch) { int index = ch - 'a'; if (null == childNodes) { this.childNodes = new TrieNode[26]; } if (null == childNodes[index]) { childNodes[index] = new TrieNode(ch); } return childNodes[index]; } public TrieNode getChild(char ch) { int index = ch - 'a'; if (null == childNodes || null == childNodes[index]) { return null; } return childNodes[index]; } public void addCount() { this.count++; } public int getCount() { return this.count; } public void addPrefixCount() { this.prefixCount++; } public int getPrefixCount() { return this.prefixCount; } @Override public String toString() { return "TrieNode [nodeChar=" + nodeChar + "]"; } } } package com.vicky.datastructure.tree.trie; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.util.regex.Pattern; import org.junit.Before; import org.junit.Test; public class TrieUsedTest { private PrefixTrie trie; @Before public void before() throws IOException { Pattern pattern = Pattern.compile("[a-zA-Z]+"); // , TriedTree InputStreamReader read = new InputStreamReader(this.getClass().getResourceAsStream("words.txt")); BufferedReader reader = new BufferedReader(read); trie = new PrefixTrie(); String line = null; while (null != (line = reader.readLine())) { line = line.trim(); if (!pattern.matcher(line).matches()) {// , “-” continue; } trie.insertWord(line); } } /** * TriedTree */ @Test public void searchPrefixWords() { String prefix = "vi"; System.out.println(trie.selectPrefixCount(prefix)); System.out.println(trie.selectWord("Vicky")); } }

    코드 에서 정확 한 검색 과 접 두 사 를 찾 는 두 가지 방식 을 지원 하기 위해 저 희 는 TrieNode 를 수정 하여 private int count = 0;private int prefixCount = 0; 두 개의 변 수 를 추 가 했 습 니 다. 각각 단어 가 나타 나 는 횟수 와 접두사 가 나타 나 는 횟수 를 저장 하 는 데 사 용 됩 니 다.테스트 결 과 는 텍스트 편집 기 를 사용 하여 대 비 를 찾 을 수 있 습 니 다.
    트 리 트 리 의 응용 장면 에 대해 서 는 참고 글 1 을 읽 을 수 있 습 니 다.
    참고 문장
    데이터 구조의 트 리 트 리 는 트 리 (사전 트 리) 에서 접미사 트 리 (10.28 수정) 까지 6 일 동안 트 리 구 조 를 통식 합 니 다. 5 일 째 트 리 입 니 다.
    저의 개인 블 로그 에 오신 것 을 환영 합 니 다. 더 많은 즐거움 을 찾 으 세 요 ~

    좋은 웹페이지 즐겨찾기