Implement Trie (Prefix Tree)

Implement Trie (Prefix Tree)

问题:

Implement a trie with insertsearch, and startsWith methods.

思路:

  前缀树

我的代码:

class TrieNode {
    // Initialize your data structure here.
    public TrieNode() {
    }
    public TrieNode(char c) {
        this.c = c;
    }
    char c;
    HashMap<Character, TrieNode> children = new HashMap<Character, TrieNode>();  
    boolean isWord;
}

public class Trie {
    private TrieNode root;

    public Trie() {
        root = new TrieNode();
    }

    // Inserts a word into the trie.
    public void insert(String word) {
        HashMap<Character, TrieNode> children = root.children;
        for(int i=0; i<word.length(); i++)
        {
            TrieNode node;
            char c = word.charAt(i);
            if(children.containsKey(c)) node = children.get(c);
            else
            {
                node = new TrieNode(c);
                children.put(c,node);
            }
            children = node.children;
            if(i == word.length()-1)
            {
                node.isWord = true;
            }
        }
    }

    // Returns if the word is in the trie.
    public boolean search(String word) {
        TrieNode node = searchNode(word);
        return node!=null && node.isWord;
    }

    // Returns if there is any word in the trie
    // that starts with the given prefix.
    public boolean startsWith(String prefix) {
        return searchNode(prefix) != null;
    }
    public TrieNode searchNode(String word) {
        HashMap<Character, TrieNode> children = root.children;
        TrieNode node = null;
        for(int i=0; i<word.length(); i++)
        {
            char c = word.charAt(i);
            if(children.containsKey(c)) node = children.get(c);
            else    return null;
            children = node.children;
        }
        return node;
    }
}

// Your Trie object will be instantiated and called as such:
// Trie trie = new Trie();
// trie.insert("somestring");
// trie.search("key");
View Code

他人代码:

class TrieNode {
    private final int R = 26;
    private final TrieNode[] children;
    private String item;

    public TrieNode() {
        children = new TrieNode[R];
        item = "";
    }

    public String getItem() {
        return item;
    }

    public void setItem(String item) {
        this.item = item;
    }

    public TrieNode[] getChildren() {
        return children;
    }

    public TrieNode getChild(int i) {
        if (i >= 26 || i < 0) throw new IllegalArgumentException();
        return children[i];
    }

    public void setChild(int i, TrieNode node) {
        children[i] = node;
    }
}

public class Trie {
    private TrieNode root;

    public Trie() {
        root = new TrieNode();
    }

    // Inserts a word into the trie.
    public void insert(String word) {
        TrieNode curr = root;
        for (char c : word.toCharArray()) {
            if (curr.getChild(c - 'a') == null) curr.setChild(c - 'a', new TrieNode());
            curr = curr.getChild(c - 'a');
        }
        curr.setItem(word);
    }

    // Returns if the word is in the trie.
    public boolean search(String word) {
        TrieNode curr = root;
        for (char c : word.toCharArray()) {
            if (curr.getChild(c - 'a') == null) return false;
            curr = curr.getChild(c - 'a');
        }
        return curr.getItem().equals(word);
    }

    // Returns if there is any word in the trie
    // that starts with the given prefix.
    public boolean startsWith(String prefix) {
        TrieNode curr = root;
        for (char c : prefix.toCharArray()) {
            if (curr.getChild(c - 'a') == null) return false;
            curr = curr.getChild(c - 'a');
        }
        return true;
    }
}

// Your Trie object will be instantiated and called as such:
// Trie trie = new Trie();
// trie.insert("somestring");
// trie.search("key");
View Code

学习之处:

  • 不好习惯+2
  • 他人的代码可以实现字符串排序方法,因为其实用的数组进行存储的,而我用的是HashMap进行存储的。
  • 前缀树,字典树介绍

一、什么是Trie树
Trie树,又叫字典树、前缀树(Prefix Tree)、单词查找树 或 键树,是一种多叉树结构。如下图:
二、Trie树的优缺点
Trie树的核心思想是空间换时间,利用字符串的公共前缀来减少无谓的字符串比较以达到提高查询效率的目的。
优点
(1)插入和查询的效率很高,都为O(m),其中 m 是待插入/查询的字符串的长度。
关于查询,会有人说 hash 表时间复杂度是O(1)不是更快?但是,哈希搜索的效率通常取决于 hash 函数的好坏,若一个坏的 hash 函数导致很多的冲突,效率并不一定比Trie树高。
(2)Trie树中不同的关键字不会产生冲突。
(3)Trie树只有在允许一个关键字关联多个值的情况下才有类似hash碰撞发生。
(4)Trie树不用求 hash 值,对短字符串有更快的速度。通常,求hash值也是需要遍历字符串的。
(5)Trie树可以对关键字按字典序排序。
缺点
(1)当 hash 函数很好时,Trie树的查找效率会低于哈希搜索。
(2)空间消耗比较大。
三、Trie树的应用
1、字符串检索
检索/查询功能是Trie树最原始的功能。思路就是从根节点开始一个一个字符进行比较:
如果沿路比较,发现不同的字符,则表示该字符串在集合中不存在。
如果所有的字符全部比较完并且全部相同,还需判断最后一个节点的标志位(标记该节点是否代表一个关键字)。
2、词频统计
Trie树常被搜索引擎系统用于文本词频统计 。
思路:为了实现词频统计,我们修改了节点结构,用一个整型变量count来计数。对每一个关键字执行插入操作,若已存在,计数加1,若不存在,插入后count置1。
注意:第一、第二种应用也都可以用 hash table 来做。
3、字符串排序
Trie树可以对大量字符串按字典序进行排序,思路也很简单:遍历一次所有关键字,将它们全部插入trie树,树的每个结点的所有儿子很显然地按照字母表排序,然后先序遍历输出Trie树中所有关键字即可。
4、前缀匹配
例如:找出一个字符串集合中所有以ab开头的字符串。我们只需要用所有字符串构造一个trie树,然后输出以a->b->开头的路径上的关键字即可。
trie树前缀匹配常用于搜索提示。如当输入一个网址,可以自动搜索出可能的选择。当没有完全匹配的搜索结果,可以返回前缀最相似的可能。
5、作为其他数据结构和算法的辅助结构
如后缀树,AC自动机等。

转自:http://songlee24.github.io/2015/05/09/prefix-tree/

posted on 2015-05-29 16:17  zhouzhou0615  阅读(294)  评论(0编辑  收藏  举报

导航