简体   繁体   English

Java中的Trie上的DFS和BFS

[英]DFS and BFS on a Trie in Java

I have a Trie which looks like this: 我有一个Trie,看起来像这样:

      Root
     /    \
    b      c
   /      / \
  a      a   h
 /      /   / \
t      t   a   e
          /   /
         t   e
            / \
           r   s
          /     \
         s       e

I'm trying to implement a DFS, and BFS. 我正在尝试实现DFS和BFS。 The BFS works fine, using a queue: BFS使用队列可以正常工作:

public String breadthFirstSearch() {
    //FIFO Queue to hold nodes
    Queue<TrieNode> nodeQueue = new LinkedList<TrieNode>();

    //Output array
    ArrayList<Integer> out = new ArrayList<Integer>();

    //Start from root
    nodeQueue.add(this.root);

    //While queue is not empty
    while (nodeQueue.isEmpty() == false) {
        //Remove and return first queue element
        TrieNode current = nodeQueue.poll();
        //For node's children
        for (int i=0; i<26; i++) {
            //If not null
            if (current.offspring[i] != null) {
                //Add node to queue
                nodeQueue.add(current.offspring[i]);
                //Add node's index (char) to output array
                out.add(i);                    
            }
        }
    }
    //Return result
    return indexArrayToString(out);
}

Output: 输出:

b,c,a,a,h,t,t,a,e,t,e,r,s,s,e

Now, I'm trying to implement the DFS (same algorithm, but using a stack) however the output isn't correct: 现在,我正在尝试实现DFS(相同的算法,但是使用堆栈),但是输出不正确:

public String depthFirstSearch() {
    //LIFO Stack to hold nodes
    Stack<TrieNode> nodeStack = new Stack<TrieNode>();

    //Output array
    ArrayList<Integer> out = new ArrayList<Integer>();

    //Start from root
    nodeStack.push(this.root);

    //While stack is not empty
    while (nodeStack.isEmpty() == false) {
        //Remove and return first stack element
        TrieNode current = nodeStack.pop();
        //For node's children
        for (int i=0; i<26; i++) {
            //If not null
            if (current.offspring[i] != null) {
                //Add node to stack
                nodeStack.push(current.offspring[i]);
                //Add node's index (char) to output array
                out.add(i);                    
            }
        }
    }
    //Return result
    return indexArrayToString(out);
}

This gives: 这给出:

b,c,a,h,a,e,e,r,s,e,s,t,t,a,t

When I want it to give: 当我想给它:

t,a,b,t,a,t,a,s,r,e,s,e,e,h,c

I can't figure out what's going wrong. 我不知道怎么了。

I have implemented the map-based approach that I mentioned in my comment, ie without modifying the original TrieNode class: 我已经实现了我在评论中提到的基于地图的方法,即TrieNode原始TrieNode类:

  public String depthFirstSearch() {
            //LIFO Stack to hold nodes
            Stack<TrieNode> nodeStack = new Stack<TrieNode>();
            //keep set of processed nodes (processed node is a node whose children were already pushed into the stack)
            Set<TrieNode> processed = new HashSet<TrieNode>();
            //boolean for checking presence of at least one child
            boolean hasChild=false;
            //map for trienode->char
            Map<TrieNode, Integer> map = new HashMap<TrieNode, Integer>();

            //Output array
            List<Integer> out = new ArrayList<Integer>();

            //Start from root
            nodeStack.push(this.root);

            //While stack is not empty
            while (nodeStack.isEmpty() == false) {

                //Peek at the top of stack
                TrieNode topNode = nodeStack.peek();

                //if it is not processed AND if it has at least one child, push its children into the stack from right to left. otherwise pop the stack

                hasChild=false;                
                if(!processed.contains(topNode))
                {

                   for (int i=25; i>=0; i--) 
                   {
                       //If not null
                       if (topNode.offspring[i] != null) 
                       {
                         //Add node to stack and map
                         nodeStack.push(topNode.offspring[i]);
                         map.put(topNode.offspring[i], i);
                         hasChild=true;                                               
                       }     

                   }//end for

                   processed.add(topNode); //after discovering all children, put the top into set of processed nodes

                   if(!hasChild) //top node has no children so we pop it and put into the list
                       {
                          TrieNode popNode = nodeStack.pop();
                          if(map.get(popNode)!=null)
                             out.add(map.get(popNode)); 

                       }

                }
                else //the node has been processed already so we pop it and put into the list

                {               
                    TrieNode popNode = nodeStack.pop();
                    if(map.get(popNode)!=null)
                       out.add(map.get(popNode)); 
                }


            }//end while stack not empty

            //Return result
            return indexArrayToString(out);

        }//end method

To get the output that you wanted, you need to think about when a node is added to the out list. 要获得所需的输出,您需要考虑何时将节点添加到“出站”列表中。 In your code, you start at the root and iterate throught it's offspring in a kind-of recursive style while adding them directly to your output. 在您的代码中,您从根开始,以一种递归样式迭代它的后代,同时将它们直接添加到输出中。 Therefore your output has more in common with a BFS than a DFS. 因此,与DFS相比,您的输出与BFS有更多的共同点。

Although there are very simple DFS implementations like 虽然有非常简单的DFS实现,例如

DFS(TrieNode current){ 
  for(int i = 26; i >= 0; i--){
    if(current.offspring[i] != null){
      DFS(current.offspring[i]);
    }
  }
  out.add(current);
}

if you want to keep most of your code for any reason, you could create a second stack that keeps track for you where in the tree you are and when which node is supposed to be added to the output. 如果您出于某种原因想要保留大部分代码,则可以创建第二个堆栈,该堆栈可以跟踪您在树中的位置以及何时将哪个节点添加到输出中。 Explicitly, this could look something like this: 明确地,这可能看起来像这样:

public String depthFirstSearch() {
  //LIFO Stack to hold nodes
  Stack<TrieNode> nodeStack = new Stack<TrieNode>();

  //Second stack that keeps track of visited nodes
  Stack<TrieNode> helpStack = new Stack<TrieNode>();

  //Output array
  ArrayList<Integer> out = new ArrayList<Integer>();

  //Start from root
  nodeStack.push(this.root);

  //While stack is not empty
  while (nodeStack.isEmpty() == false) {
    //Remove and return first stack element
    TrieNode current = nodeStack.peek();

    //We visited this node -> push it on the second stack
    helpStack.push(current);

    //We want to add nodes to the output once we reach a leaf node, so we need a
    //helper variable
    boolean hasOffspring = false;

    //For node's children - since we want to go the left path first we push the 
    //children in right-to-left fashion on the stack. Can vary with implementation.
    for (int i=25; i>=0; i--) {
        //If not null
        if (current.offspring[i] != null) {
            //Add node to stack
            nodeStack.push(current.offspring[i]);
            //not a leaf
            hasOffspring = true;                  
        }
     }

     //if we reached a leaf node add it and all previous nodes to the output until 
     //we reach a fork where we didn't already fo the other path
     if(!hasOffspring){
       TrieNode node1 = nodeStack.peek();
       TrieNode node2 = helpStack.peek();
       while(node1.equals(node2)){
         nodeStack.pop();
         helpStack.pop();

         //Add node's index (char) to output array
         out.add(node1);  

         //we are back at the root and completed the DFS
         if(nodeStack.isEmpty() || helpStack.isEmpty()) break;
         node1 = nodeStack.peek();
         node2 = nodeStack.peek();
       }
     }
 }
  //Return result
  return indexArrayToString(out);
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM