• Trie (prefix tree) 实现 (Java)


     转载 http://blog.csdn.net/beiyetengqing/article/details/7856113

    关注Trie 这种结构已经很久,Trie有一个很有趣的用途,那就是自动提示。而且,前不久在一次面试里,也需要用Trie来解答。所以,在此对这个数据结构进行总结。

    Trie,又称单词查找树键树,是一种形结构。典型应用是用于统计和排序大量的字符串(但不仅限于字符串),所以经常被搜索引擎系统用于文本词频统计。它的优点是:最大限度地减少无谓的字符串比较,查询效率比哈希表高。

    它有3个基本性质:

    1. 根节点不包含字符,除根节点外每一个节点都只包含一个字符
    2. 根节点到某一节点路径上经过的字符连接起来,为该节点对应的字符串
    3. 每个节点的所有子节点包含的字符都不相同。
    下面这个图就是Trie的表示,每一条边表示一个字符,如果结束,就用星号表示。在这个Trie结构里,我们有下面字符串,比如do, dork, dorm等,但是Trie里没有ba, 也没有sen,因为在a, 和n结尾,没有结束符号(星号)。

    有了这样一种数据结构,我们可以用它来保存一个字典,要查询改字典里是否有相应的词,是否非常的方便呢?我们也可以做智能提示,我们把用户已经搜索的词存在Trie里,每当用户输入一个词的时候,我们可以自动提示,比如当用户输入 ba, 我们会自动提示 bat 和 baii.

    现在来讨论Trie的实现。

    首先,我们定义一个Abstract Trie,Trie 里存放的是一个Node。这个类里有两个操作,一个是插入,另一个是查询。具体实现放在后面。

    Node 类的实现

    1. class Node {  
    2.     char content; // the character in the node  
    3.     boolean isEnd; // whether the end of the words  
    4.     int count;  // the number of words sharing this character  
    5.     LinkedList<Node> childList; // the child list  
    6.     
    7.     public Node(char c){  
    8.         childList = new LinkedList<Node>();  
    9.         isEnd = false;  
    10.         content = c;  
    11.         count = 0;  
    12.     }  
    13.     
    14.     public Node subNode(char c){  
    15.         if(childList != null){  
    16.             for(Node eachChild : childList){  
    17.                 if(eachChild.content == c){  
    18.                      return eachChild;  
    19.                 }  
    20.             }  
    21.         }  
    22.         return null;  
    23.    }  
    24. }  

    现在我们来看这个Trie类的具体实现。

    1. public class Trie{  
    2.     private Node root;  
    3.    
    4.     public Trie(){  
    5.         root = new Node(' ');   
    6.     }  
    7.    
    8.     public void insert(String word){  
    9.         if(search(word) == true) return;  
    10.           
    11.         Node current = root;   
    12.         for(int i = 0; i < word.length(); i++){  
    13.             Node child = current.subNode(word.charAt(i));  
    14.             if(child != null){   
    15.                 current = child;  
    16.             } else {  
    17.                  current.childList.add(new Node(word.charAt(i)));  
    18.                  current = current.subNode(word.charAt(i));  
    19.             }  
    20.             current.count++;  
    21.         }   
    22.         // Set isEnd to indicate end of the word  
    23.         current.isEnd = true;  
    24.     }  
    25.     public boolean search(String word){  
    26.         Node current = root;  
    27.           
    28.         for(int i = 0; i < word.length(); i++){      
    29.             if(current.subNode(word.charAt(i)) == null)  
    30.                 return false;  
    31.             else  
    32.                 current = current.subNode(word.charAt(i));  
    33.         }  
    34.         /*  
    35.         * This means that a string exists, but make sure its 
    36.         * a word by checking its 'isEnd' flag 
    37.         */  
    38.         if (current.isEnd == true) return true;  
    39.         else return false;  
    40.     }  
    41.       
    42.     public void deleteWord(String word){  
    43.         if(search(word) == false) return;  
    44.       
    45.         Node current = root;  
    46.         for(char c : word.toCharArray()) {   
    47.             Node child = current.subNode(c);  
    48.             if(child.count == 1) {  
    49.                 current.childList.remove(child);  
    50.                 return;  
    51.             } else {  
    52.                 child.count--;  
    53.                 current = child;  
    54.             }  
    55.         }  
    56.         current.isEnd = false;  
    57.     }  
    58.       
    59.     public static void main(String[] args) {  
    60.         Trie trie = new Trie();  
    61.         trie.insert("ball");  
    62.         trie.insert("balls");  
    63.         trie.insert("sense");  
    64.       
    65.         // testing deletion  
    66.         System.out.println(trie.search("balls"));  
    67.         System.out.println(trie.search("ba"));  
    68.         trie.deleteWord("balls");  
    69.         System.out.println(trie.search("balls"));  
    70.         System.out.println(trie.search("ball"));  
    71.     }  
    72. }  


    时间复杂度分析:

    对于insert, 如果被插入的String长度是 k, 每对一个字符进行查询,我们最多在child linkedlist里面查询26次(最多26个字母),所以,复杂度为O(26*k) = O(k). 对于 search, 复杂度是一样的。

    本文代码来自:http://www.technicalypto.com/2010/04/trie-in-java.html

  • 相关阅读:
    几种不同风格的Toast
    [置顶] 如何访问web文件夹之外的文件
    30天自制操作系统笔记(九十)
    tomcat install on Linux
    共享内存使用的基本思路和接口
    30天自制操作系统笔记(九十)——源码
    storm单机版安装配置
    新安装XAMPP,phpMyAdmin错误:#1045
    TI-Davinci开发系列之二使用CCS5.2TI Simulator模拟环境调试DSP程序
    ffmpeg的logo, delogo滤镜参数设置
  • 原文地址:https://www.cnblogs.com/chenying99/p/2700432.html
Copyright © 2020-2023  润新知