前缀树

前缀树又称为字典树,接触这个数据结构是因为在 LeetCode 上面刷到这道题 14. Longest Common Prefix。然后,我去看了下官方推荐的文章以及其他人的博客,基本上是可以理解这种数据结构的吧!
下面就贴下这种数据结构的一种实现的代码吧:
节点类:

package ds;

/**
 * Created by clearbug on 2018/3/6.
 *
 * 字典树节点类
 */
public class TrieNode {

    // R links to node children
    private TrieNode[] links;

    private final int R = 26;

    private boolean isEnd;

    // number of children non null links
    private int size;

    public TrieNode() {
        links = new TrieNode[R];
    }

    public boolean containsKey(char ch) {
        return links[ch - 'a'] != null;
    }

    public TrieNode get(char ch) {
        return links[ch - 'a'];
    }

    public void put(char ch, TrieNode node) {
        links[ch - 'a'] = node;
        size++;
    }

    public int getLinks() {
        return size;
    }

    public void setEnd() {
        isEnd = true;
    }

    public boolean isEnd() {
        return isEnd;
    }

}

字典树类:

package ds;

/**
 * Created by clearbug on 2018/3/6.
 *
 * 字典树
 */
public class Trie {

    private TrieNode root;

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

    // Inserts a word into the trie.
    public void insert(String word) {
        TrieNode node = root;
        for (int i = 0; i < word.length(); i++) {
            char currentChar = word.charAt(i);
            if (!node.containsKey(currentChar)) {
                node.put(currentChar, new TrieNode());
            }
            node = node.get(currentChar);
        }
        node.setEnd();
    }

    // search a prefix or whole key in trie and returns the node where search ends
    private TrieNode searchPrefix(String word) {
        TrieNode node = root;
        for (int i = 0; i < word.length(); i++) {
            char curLetter = word.charAt(i);
            if (node.containsKey(curLetter)) {
                node = node.get(curLetter);
            } else {
                return null;
            }
        }
        return node;
    }

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

    // Returns is there is any word in the trie that starts with the given prefix.
    public boolean startsWith(String prefix) {
        TrieNode node = searchPrefix(prefix);
        return node != null;
    }

    // just for https://leetcode.com/problems/longest-common-prefix/description/
    private String searchLongestPrefix(String word) {
        TrieNode node = root;
        StringBuilder prefix = new StringBuilder();
        for (int i = 0; i < word.length(); i++) {
            char curLetter = word.charAt(i);
            if (node.containsKey(curLetter) && (node.getLinks() == 1) && (!node.isEnd())) {
                prefix.append(curLetter);
                node = node.get(curLetter);
            } else {
                return prefix.toString();
            }
        }
        return prefix.toString();
    }

}

测试一把:

import ds.Trie;

/**
 * Created by clearbug on 2018/3/6.
 */
public class Test {

    public static void main(String[] args) {
        String[] words = {"are", "you", "ok"};
        String[] words2 = {"yes", "no"};

        Trie trie = new Trie();
        for (int i = 0; i < words.length; i++) {
            trie.insert(words[i]);
        }

        for (int i = 0; i < words.length; i++) {
            System.out.println("Search \"" + words[i] + "\" result: " + trie.search(words[i]));
        }
        for (int i = 0; i < words2.length; i++) {
            System.out.println("Search \"" + words2[i] + "\" result: " + trie.search(words2[i]));
        }
    }
}

运行结果:

Search "are" result: true
Search "you" result: true
Search "ok" result: true
Search "yes" result: false
Search "no" result: false

参考

https://leetcode.com/articles/implement-trie-prefix-tree/
https://www.cnblogs.com/grandyang/p/4491665.html

posted @ 2018-03-06 11:43  optor  阅读(177)  评论(0编辑  收藏  举报