使用Java Trie时,无法识别词尾。在递归中失败

使用Java Trie时,无法识别词尾。在递归中失败,java,recursion,hashmap,trie,Java,Recursion,Hashmap,Trie,我正试图创建我自己的JavaTrie版本,以便拥有它,并获得制作它所需的知识,但这个项目让我感到困惑。我这里有一个非常基本的坏球 我在Trie中添加了3个单词(使用单词的第一个字符作为键,值是额外的三元组)。如果您注意到了,我在trinode类中有print语句,用于在程序运行时检查isWord的值。我希望单词中的最后一个字符将isWord变量设置为True。从而识别一个单词的结尾(稍后我将使用它来获取整个单词) 当我第一次输入这三个单词时,输出会打印每个单词进入Trie时的每个字母,并正确识别

我正试图创建我自己的JavaTrie版本,以便拥有它,并获得制作它所需的知识,但这个项目让我感到困惑。我这里有一个非常基本的坏球

我在Trie中添加了3个单词(使用单词的第一个字符作为键,值是额外的三元组)。如果您注意到了,我在trinode类中有print语句,用于在程序运行时检查isWord的值。我希望单词中的最后一个字符将isWord变量设置为True。从而识别一个单词的结尾(稍后我将使用它来获取整个单词)

当我第一次输入这三个单词时,输出会打印每个单词进入Trie时的每个字母,并正确识别哪些字符是单词的结尾

但是,如果在输入单词后立即遍历Trie并重新打印Trie中的所有字符及其isWord状态,“Hello”中的“e”现在突然被标识为单词结尾

我已经滔滔不绝地讲了好几个小时,但我不明白为什么会发生这种情况。以下是工作代码:

package testcode;


import java.util.*;

public class TestCode {

    public static Trie t;
    public static void main (String[] args){
        t = new Trie();
        t.addWord("hello");
        t.addWord("hi");
        t.addWord("soup");
        //at this point the output correctly identifies word endings.
        t.findWords();
        /* but when iterating through the hash map it becomes evident that
        * when entering the word 'hi' the 'e' in 'hello' had its isWord variable
        * changed to true. I followed the logic and I do not see how or why this
        * is happening.
        */
    }
}

//This Trie class handles the root trie, and Trie commands.
class Trie{
    private TrieNode root;

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

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

    public void findWords(){
        root.findWords();
    }
}

//Trie Node handles the nodes and words within the trie
class TrieNode{

    private TrieNode parent;
    private boolean isWord;
    private boolean hasChildren;
    private char character;
    private Map<Character, TrieNode> children = new HashMap<>();

    public TrieNode(){

        hasChildren = false;
        isWord = false;
    }

    public TrieNode(String word){

        this();
        addWord(word);

    }
    public void addWord(String word){

       char firstChar = word.charAt(0);


       if (children.get(firstChar) == null){

           if(word.length() > 1){

               hasChildren = true;
               children.put(firstChar, new TrieNode(word.substring(1)));
               children.get(firstChar).parent = this;
               System.out.print(firstChar + "--");
               System.out.println(isWord);
           }

           else{
               children.put(firstChar, new TrieNode());
               if(character == 'e'){
                   System.out.println("shits about to go down");
               }
               isWord = true;
               System.out.print(firstChar + "--");
               System.out.println(isWord);
           }
           children.get(firstChar).character = firstChar;
       }

       else {
           children.get(firstChar).addWord(word.substring(1));
       }
   }

    public void findWords(){
        for(Character key : children.keySet()){
            children.get(key).findWords();
            System.out.println(children.get(key).character + " -- " + isWord);     
      }
    }
}

有一系列可能的问题。。父/子混淆,在父节点处理叶案例,包括构建和打印输出等

我注意到在旧的“findWords”代码中,您打印的是子字符,但父“isWord”标志。构建trie时,“存在子节点”和“创建子节点路径”之间存在不希望出现的差异,因此“isWord”只能标记在新路径上,而不能标记在现有路径上。构建trie似乎也会在父节点而不是叶节点上设置“isWord”。

一般来说,如果案例很可能是不可靠的,那么代码就是嵌套的意大利面条。代码应该尽可能通用——将其保留在方法的主流中,除非它确实属于IF

以下是清晰正确的代码:

class TrieNode{
    private TrieNode parent;
    private boolean isWord;
    private boolean hasChildren;
    private char character;
    private Map<Character, TrieNode> children = new HashMap<>();

    public TrieNode(){
        this.hasChildren = false;
        this.isWord = false;
    }
    public TrieNode (char ch) {
        this.character = ch;
        this.hasChildren = false;
        this.isWord = false;
    }

    public void addWord (String word){
        if (word.length() == 0) {
            this.isWord = true;
            System.out.println( character + " -- " + isWord);
            return;
        }

        // represent the Child Node;
        //       --
        char firstChar = word.charAt(0);
        TrieNode child = children.get( firstChar);
        if (child == null){
            child = new TrieNode( firstChar);
            children.put( firstChar, child);
            child.parent = this;
            hasChildren = true;
        }

        // add Remaining Word;
        //      -- call for 1-length words, as 0-length at Child sets 'IsWord'!
        child.addWord( word.substring(1));

        // print building here.
        System.out.println( character + " -- " + isWord);
    }



    public void findWords(){
        for(Character key : children.keySet()){
            children.get(key).findWords();
        }
        System.out.println( character + " -- " + isWord);     
    }
}
类三节点{
私人三元家长;
私有布尔字;
私生子;
私有字符;
private-Map-children=new-HashMap();
公共三元组(){
this.hasChildren=false;
this.isWord=false;
}
公共三元组(char-ch){
this.character=ch;
this.hasChildren=false;
this.isWord=false;
}
公共无效添加字(字符串字){
if(word.length()==0){
this.isWord=true;
System.out.println(字符+“--”+isWord);
返回;
}
//表示子节点;
//       --
char firstChar=word.charAt(0);
三节点子节点=children.get(firstChar);
if(child==null){
child=新的三元组(firstChar);
children.put(firstChar,child);
child.parent=这个;
hasChildren=正确;
}
//添加剩余单词;
//--调用1长度的单词,因为子集合“IsWord”中的0长度!
child.addWord(word.substring(1));
//在这里打印大楼。
System.out.println(字符+“--”+isWord);
}
公共无效findWords(){
for(字符键:children.keySet()){
children.get(key.findWords();
}
System.out.println(字符+“--”+isWord);
}
}

对于您的回复,我感激不尽。不过,我喜欢你用一个问题来代替If语句的方法,这是因为我对亲子关系有明显的误解。中的变量与此.variable之间的区别是什么。我理解“this”关键字的作用,但在这个程序中,它们不应该在任何给定的点上是相同的吗?IE:在addWord()方法中有一个this.isWord=true,然后下一行只使用“isWord”而不是this.isWord。这两个变量是不同的,还是它们都指向同一个(当前节点)isWord?我总是用
this.
编写字段赋值,以使它们非常清晰和明确。(在我的setters中,我不会给参数加前缀,也不会将其命名为与字段不同的名称。。我只依赖于
this.
)。工作良好,阅读清晰。
class TrieNode{
    private TrieNode parent;
    private boolean isWord;
    private boolean hasChildren;
    private char character;
    private Map<Character, TrieNode> children = new HashMap<>();

    public TrieNode(){
        this.hasChildren = false;
        this.isWord = false;
    }
    public TrieNode (char ch) {
        this.character = ch;
        this.hasChildren = false;
        this.isWord = false;
    }

    public void addWord (String word){
        if (word.length() == 0) {
            this.isWord = true;
            System.out.println( character + " -- " + isWord);
            return;
        }

        // represent the Child Node;
        //       --
        char firstChar = word.charAt(0);
        TrieNode child = children.get( firstChar);
        if (child == null){
            child = new TrieNode( firstChar);
            children.put( firstChar, child);
            child.parent = this;
            hasChildren = true;
        }

        // add Remaining Word;
        //      -- call for 1-length words, as 0-length at Child sets 'IsWord'!
        child.addWord( word.substring(1));

        // print building here.
        System.out.println( character + " -- " + isWord);
    }



    public void findWords(){
        for(Character key : children.keySet()){
            children.get(key).findWords();
        }
        System.out.println( character + " -- " + isWord);     
    }
}