web-dev-qa-db-ja.com

JavaまたはC ++での再帰的幅優先移動関数?

これが幅優先探索のJavaコードです:

void breadthFirstNonRecursive(){
    Queue<Node> queue = new Java.util.LinkedList<Node>();
    queue.offer(root);
    while(!queue.isEmpty()){
        Node node = queue.poll();
        visit(node);
        if (node.left != null)
            queue.offer(node.left);
        if (node.right != null)
            queue.offer(node.right);
    }
}

同じことをする再帰関数を書くことは可能ですか?

最初は、これは簡単だと思ったので、次のように思いました。

void breadthFirstRecursive(){
    Queue<Node> q = new LinkedList<Node>();
    breadthFirst(root, q);
}

void breadthFirst(Node node, Queue<Node> q){
    if (node == null) return;
    q.offer(node);
    Node n = q.poll();
    visit(n);
    if (n.left != null)
        breadthFirst(n.left, q);
    if (n.right != null)
        breadthFirst(n.right, q);   
}

それから私はそれが機能しないことに気づきました。それは実際にはこれと同じことをします:

void preOrder(Node node) {
    if (node == null) return;
    visit(node);
    preOrder(node.left);
    preOrder(node.right);
}

これについて誰かが以前に考えたことがありますか?

12
joejax

私は想像できませんなぜあなたが完全に良い反復解法を持っているとき、あなたが望むでしょう、しかしここにあなたは行き​​ます;)

void breadth_first(Node root):
  Queue q;
  q.Push(root);
  breadth_first_recursive(q)

void breadth_first_recursive(Queue q):
  if q.empty() return;

  Node n = q.pop()
  print "Node: ", n
  if (n.left) q.Push(n.left)
  if (n.right) q.Push(n.right)
  breadth_first_recursive(q)

ツリーのノードを本当に再帰的にトラバースしたい場合は、levelパラメーターを使用してDFSを実行し、ノードをlevelでのみ出力してから、再帰的に実行できることを追加する必要があります。しかし、それはただのクレイジーな話です。なぜなら、ノードを何度も再訪するからです... BFSが反復アルゴリズムであることを受け入れてください。 :)

18
Stephen

BFSアルゴリズムは(DFSとは対照的に)再帰的アルゴリズムではありません。

1つcouldアルゴリズムをエミュレートする再帰関数を書いてみてください。しかし、それはかなり奇妙な結果になります。これを行うことのポイントは何でしょうか?

11
ob1

反復深化深さ優先探索 を使用できます。これは、事実上、再帰を使用する幅優先アルゴリズムです。分岐係数が高い場合は、メモリをあまり使用しないため、BFSよりも優れています。

6
gustafc

単純なBFSおよびDFS再帰:スタック/キュー内のツリーのルートノードをプッシュ/提供し、これらの関数を呼び出すだけです!

public void breadthFirstSearch(Queue queue) {
if (queue.isEmpty()) 
  return;

Node node = (Node) queue.poll();

System.out.println(node + " ");

if (node.right != null) 
  queue.offer(node.right);

if (node.left != null) 
  queue.offer(node.left);

breadthFirstSearch(queue);

}

public void depthFirstSearch(Stack stack) {
if (stack.isEmpty()) 
  return;

Node node = (Node) stack.pop();

System.out.println(node + " ");

if (node.right != null) 
  stack.Push(node.right);

if (node.left != null) 
  stack.Push(node.left);

depthFirstSearch(stack);

}

1
ThePatelGuy

これはすべての人を満足させるものではありません-私は確信しています。みんなに敬意を表して。何がポイントなのかと聞く人に?重要なのは、すべての反復アルゴリズムには(簡単な?)再帰的ソリューションもあると信じているということです。これがstackoverflowからの「sisis」による解決策です。

BFS(Q)

{

  if (|Q| > 0) 

     v < - Dequeue(Q)

     Traverse(v)
     foreach w in children(v)
        Enqueue(Q, w)    

     BFS(Q)
}

ある程度おかしなことがありますが、再帰的なルールに違反していることは明らかではありません。再帰的なルールに違反していない場合は、受け入れる必要があります。私見では。

0
jim