【问题标题】:Implementing a Trie in Java在 Java 中实现 Trie
【发布时间】:2017-04-19 19:30:05
【问题描述】:

我已经在 J​​ava 中实现了 Trie 数据结构,但是在运行代码时没有得到正确的答案。我已经使用一些简单的字符串构建了 trie。然后我正在搜索单词和前缀,但结果不正确。我已经尝试过很多次调试,但仍然找不到可能出错的地方。

Trie.java:

public class Trie {

    public class Vertex {
        public int words;
        public int prefixes;
        public Vertex edges[] = new Vertex[26];

        public Vertex() {
            this.words = 0;
            this.prefixes = 0;
        }
    }

    private Vertex root;

    Trie() {
        this.root = new Vertex();
    }

    private void addWord(Vertex vertex, String word) {
        if (word.isEmpty()) {
            vertex.words++;
        } else {
            vertex.prefixes++;
            int indexOfNextChar = (int) word.charAt(0) - 97;
            vertex.edges[indexOfNextChar] = new Vertex();
            this.addWord(vertex.edges[indexOfNextChar], word.substring(1));
        }
    }

    private int countWords(Vertex vertex, String word) {
        if (!word.isEmpty()) {
            int indexOfNextChar = (int) word.charAt(0) - 97;
            if (vertex.edges[indexOfNextChar] == null) {
                return 0;
            } else {
                return this.countWords(vertex.edges[indexOfNextChar], word.substring(1));
            }
        } else {
            return vertex.words;
        }
    }

    private int countPrefixes(Vertex vertex, String word) {
        if (!word.isEmpty()) {
            int indexOfNextChar = (int) word.charAt(0) - 97;
            if (vertex.edges[indexOfNextChar] == null) {
                return 0;
            } else {
                return this.countPrefixes(vertex.edges[indexOfNextChar], word.substring(1));
            }
        } else {
            return vertex.prefixes;
        }
    }

    public void addWord(String word) {
        this.addWord(this.root, word.toLowerCase());
    }

    public int countPrefixes(String word) {
        if (word.length() != 0) {
            return this.countPrefixes(this.root, word.toLowerCase());
        }
        return -1;
    }

    public int countWords(String word) {
        if (word.length() != 0) {
            return this.countWords(this.root, word.toLowerCase());
        }
        return -1;
    }
}

TrieTester.java

public class TrieTester {
    public static void main(String[] args) {
        Trie trie = new Trie();
        trie.addWord("Ayush");
        trie.addWord("Ayur");
        trie.addWord("Ayub");
        trie.addWord("Ayan");
        trie.addWord("Bhushan");

        // Should output 0, outputs 0
        System.out.println("Count of word Ayus: " + trie.countWords("Ayus"));

        // Should output 1, outputs 0
        System.out.println("Count of word Ayush: " + trie.countWords("Ayush"));

        // Should output 4, outputs 1
        System.err.println("Count of prefix Ay: " + trie.countPrefixes("Ay"));
    }
}

我参考了Topcoder Trie tutorial 来实现这一点。

【问题讨论】:

  • 我会先测试 1 个字符的字符串,然后是 2 个字符的字符串,然后检查 trie 的完整状态。
  • 使用调试器逐步完成,并仔细观察边缘情况。当你创建一个新的顶点时尤其要小心。你需要在创建第一个顶点后重用它们。

标签: java algorithm trie


【解决方案1】:

addWord 方法中的else 子句肯定是不正确的(也可能存在其他错误):

vertex.prefixes++;
int indexOfNextChar = (int) word.charAt(0) - 97;
vertex.edges[indexOfNextChar] = new Vertex();
this.addWord(vertex.edges[indexOfNextChar], word.substring(1));

您的代码总是会创建一个新顶点。那是错误的。当且仅当给定角色还没有优势时,您才应该这样做。也就是说,应该是这样的:

if (vertex.edges[indexOfNextChar] == null) {
    vertex.edges[indexOfNextChar] = new Vertex();
}

您的实施还存在一些其他问题。例如,String.substring 方法以线性时间工作,因此将字符串添加到 trie 需要二次时间。您可以通过迭代单词的所有字符而不是对其子字符串进行递归来解决此问题。 消除递归也是一个好主意,因为对于较长的字符串,您可能会遇到堆栈溢出错误。

【讨论】:

    猜你喜欢
    • 2012-10-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-12-09
    • 2017-03-05
    相关资源
    最近更新 更多