2011-07-06 2 views
1

スタック(プッシュとポップを使用)のおかげでツリーのバックトラッキングアルゴリズムを使用しています。 それは動作しますが、問題があります。スタックによって与えられたパスは「間違っている」。例えばツリーでバックトラッキングを使用する

bool Prefix(Node*root, stack *tas, char *search) 
{ 
    if (!isEmpty(root)) 
    { 
     if (strcmp(search,root->data) != 0) 
      push(tas, root->data, search, root); 

     if (strcmp(search,root->data) == 0) 
     { 
      return True ; 
     } 

     Prefix(root->left, tas, search); 
     Prefix(root->right, tas, search); 
    } 
    return False; 
} 

、私は木を持っている:私は、たとえばCのパスをしたい場合は、この関数はR A B(OK RとA、いないB用)を返し

 Root 
    / \  
    A  B 
/\ /\ 
C D E F  

この関数かpush()関数かどうかはわかりません。 関数にエラーが表示されない場合は、push()を貼り付けますが、かなり長いです。

編集:私は今理解しています 私は関数に追加しました:
ノードが葉の場合、pop()。 私がFを検索すると、R B Fの代わりにR A B Fが返されます。Aをスタックに入れないようにする方法は分かりません。

EDIT2:

ここ

コードです:多分 を追加し、私は良い結果を得るために横断子ノードを開くことができますどのように理解していない

bool Prefix(Node*root, stack *tas, char *search) 
{ 
    if (!isEmpty(root)) 
    { 
     if (strcmp(search,root->data) == 0) 
      return True ; 

     if (LeafOrNot(root) == True){ //it's a leaf, pop() 
      pop(tas); 

     if (Prefix(root->left, tas, search)) 
      return True; 
     if (Prefix(root->right, tas, search)) 
      return True; 
    } 
    return False; 
} 

を(RBFのではなく、RABFを返します) a else if(接頭辞(root-> left、tas、search))?誰でもアイデアはありますか?

ありがとうございました!

+0

あなたはほとんどあります。リーフノードだけでなく、子ノードを通過した後にスタックからポップすると、結果が得られます。ノードが見つかったらスタックをポップしないようにしてください。 Dを検索している場合は、ルートをプッシュし、Aを押し、Cを押し、Cをポップし、Dを押して、見つけます...コールチェーンを完全に巻き戻します。 F:ルートをプッシュし、Aを押し、Cを押し、Dを押す、Dをポップする、Aをポップする、Bを押す、Eを押す、Eをポップする、Fを押す、見つけた、巻き戻す... これが役立つことを願っています。 –

+0

私は別のポップ(タス)を持っていることを試みましたが、動作しません。私はコードの構造を変更する必要がありますか?ありがとう – lilawood

答えて

2

@マークエリオットに同意する必要がありますが、一見すると、彼の答えは混乱しているようです。停止条件が必要なので、他のノードを探索してスタックに追加しないでください。 boolを返すので、コールがあなたの探しているノードを見つけるかどうかをテストすることができます。

最後のノードをスタックのCへのパスに含める予定だった場合は、スタックに追加するときに文字列比較を削除する必要があります。

たとえば、これを行うことができます。

bool Prefix(Node*root, stack *tas, char *search) 
{ 
    if (!isEmpty(root)) 
    { 
     push(tas, root->data, search, root); 

     if (strcmp(search,root->data) == 0) 
     { 
      return True; 
     } 

     if (Prefix(root->left, tas, search)) 
      return True; 
     if (Prefix(root->right, tas, search)) 
      return True; 
    } 
    return False; 
} 
+0

ここのプッシュは過大です。スタックに格納する必要があるのはNode *だけです。これを行う効率的な方法は、プログラムスタックからノードスタック要素を割り当てて、一致するノードが見つかったときにノードスタックを処理することです。例: 'typedef struct NodeStack NodeStack; struct NodeStack {Node *ノード; NodeStack *リンク; {strcmp(search、node-> data);}; '...' boolプレフィックス(ノード*ノード、ノードスタック*リンク、char *検索){if(!isEmpty(node){NodeStack elem = {node、link} –

+0

また、tailの再帰は 'if()を変更するだけで反復することができます。 (!isEmpty ... 'を' while'に置き換え、 'if(Prefix ...'を 'node = node-> right;'( 'root'を' node'に置き換えました。 、ルートではなく、悪い名前は悪いコードになります) –

+0

良い点はありますが、私のコードサンプルは、マークの答えを指摘するためのオリジナルのわずかな変更です。 –

3

少なくとも1つの問題は、Prefixへの呼び出しの戻り値をチェックしていないため、再帰呼び出しが「終了」しているかどうかわからないことです。

これはちょうど(あなたのサンプルツリー与えられた)関数呼び出しをウォークスルーさを確認する簡単な方法:これは、呼び出しの順序を示しており、インデントは、コールスタック上のフレームにおおよそに対応

 
Prefix("Root") 
    found "C"? 
    no: Prefix("A") 
     found "C"? 
     no: Prefix("C") 
      found "C"? 
       yes: return true 
     (without check of Prefix("C")): Prefix("D") 
      found "C"? 
       no: return false 
     Prefix("B") 
     found "C"? 
      no: Prefix("E") 
      found "C"? 
       no: return false 
      Prefix("F") 
      found "C"? 
       no: return false 
     return false 
    return false 

Prefixへの呼び出しがtrueを返すかどうかをチェックすると、適切なタイミングで終了することができます。

+0

また、ポスターは両方のブランチを追加する必要がありますか? –

+0

とあなたは少なくともあなたが各ステップで得ているものを見ることができます。シンプルなprintfが役に立ちます: – hari

+0

@Mitch:アルゴリズムは両方とも子ノードを探索するにはどうしたらいいですか? –

関連する問題