web-dev-qa-db-ja.com

再帰関数を書く

木に関連する再帰関数を書くのに苦労しています。これらの機能は一般的ではなく、試験環境でGoogleを使用できないため、これらの機能にGoogleを使用することはできません。

再帰関数のアルゴリズム/擬似コードの記述を成功させるための「トリック」はありますか?これについて私が考えるべき/それに近づくべき特定の方法はありますか?

:与えられたバイナリツリーが有効なAVLツリーと一致する構造を持つかどうかを決定する再帰関数を記述します。

予想されるソリューション

template <typename Type>
bool is_avl (const Binary_node<Type> * tree) {
    if (tree == NULL) {
        return true;
    }
    return is_bst (tree)
      && is_avl (tree->left())
      && is_avl (tree->right())
      && std::abs(height(tree->left()) - height(tree->right())) <= 1;
}
6
rrazd

あなたは運がいい!あり(ソート)です!

あなたがよくしたいことは、2/3のケースを特定することです:

  1. ベースケース
  2. 再帰的なケース
  3. 終了ケース(オプションの場合もあります)

あれは:

  1. あなたがしたいこと
  2. 続行する必要がある場所
  3. 終わったら

例を考えてみてください(バイナリ検索ツリー上のDFS):

bool DFS(Node currentNode, T searchValue)
{
    // base case
    if (currentNode.Value == searchValue) 
        return true;

    // recursive case and exit case
    if (curentNode.Left != null && DFS(currentNode.Left, searchValue)) 
        return true;

    // recursive case and exit case
    if (curentNode.Right != null && DFS(currentNode.Right, searchValue))
        return true;

    return false;
}

だからここにあります:

  1. 基本ケース:価値を見つけたかどうか
  2. 再帰的なケース:子ノードでDFSを実行します
  3. 終了ケース:子ノードのDFSが値を見つけた場合はtrueを返します

それでは、同じツリーの順序通りのトラバースについて考えてみましょう。

  1. 基本ケース:ノードを印刷する
  2. 再帰的なケース:
    • 左の子を訪ねる
    • 適切な子供を訪問する
  3. 終了ケース:ノードは存在しますか?

体内トラバーサルの場合は次のようになります。

void InOrder (Node currentNode)
{
    // 3
    if (currentNode == null)
        return;

    // 2
    InOrder(currentNode.Left);
    // 1
    print(currentNode.Value);
    // 2
    InOrder(currentNode.Right);
}

ほとんどすべての再帰関数にはこれらの要素があります。それらを識別し、正しい順序にすることが重要です。

16
Steven Evers

アルゴリズム/再帰関数の擬似コードの作成を成功させるための「トリック」はありますか?

絶対に!再帰関数を作成するときは、特定のデータ構造で実行している帰納法を明示的に説明しています。したがって、関数を作成するときの「トリック」は2つあります。

  • データ構造が表すさまざまなフォームをすべてカバーします(IE、ツリーのリーフとノード、またはリンクリストのセルと空のリストのケース、または繰り返し発生する場合は正の数とゼロ)。
  • 包含ケース(リスト内のセル、ツリー内のノード)を処理する場合は、問題をサブ問題に減らし、必要に応じてそれらを組み合わせる方法を見つけます。

たとえば、ツリー内のすべてのノードをカウントする再帰関数は次のとおりです。

def TreeCount(Tree):
    if Tree.isLeaf: # we can't go down any further
        return 1 
    else: # break the problem into sub-problems we can solve with this function
        return 1 + TreeCount(Tree.left) + TreeCount(Tree.right) 

ご覧のように、私が見ているツリーのタイプ(リーフとノード)で関数を分割し、ノードを扱っている場合は、サブツリーの再帰の観点から処理しました。

1
mustermark