7

二分探索木の再帰的な削除方法がどのように機能するかを理解しようとしています。多くの場所で出くわしたコードは次のようになります。

void destroy_tree(struct node *leaf)
{
  if( leaf != 0 )
  {
      destroy_tree(leaf->left);
      destroy_tree(leaf->right);
      free( leaf );
  }
}

しかし、理解できません a) ルーチンにリターンがない場合、どのように機能しますか? b) free() が呼び出されるのはいつですか? たとえば、次のような木について考えます。

                           10
                         /    \
                        6      14
                       / \    /  \
                      5   8  11  18

したがって、私の理解では、10->6->5 をトラバースしてから、destroy_tree(5->left) を呼び出します。したがって、if 内の葉は NULL であり、if に依存するものは実行されないため、5 は削除されません。この推論のどこが間違っているのでしょうか? ここでの巻き取りと巻き戻しはどのように機能しますか? どんな助けも親切に感謝します:-)

4

2 に答える 2

12

その時点で次のようになります。

void destroy_tree(struct node *leaf_5)
{
  if( leaf_5 != 0 )  // it's not
  {
      destroy_tree(leaf_5->left); // it's NULL so the call does nothing
      destroy_tree(leaf_5->right); // it's NULL so the call does nothing
      free( leaf_5 );  // free here
  }
}

何も返す必要はありません...ステップの「履歴」はコールスタックにあり、その時点で次のようになります。

destroy_tree(leaf_10)
  destroy_tree(leaf_10->left, which is leaf_6)
    destroy_tree(leaf_6->left, which is leaf_5)

したがって、leaf_5 がなくなった後、スタックに戻り、destroy_tree(leaf_6->right, which is leaf_8)...など...

于 2013-06-18T20:21:06.187 に答える
0

これは、関数が基本的にどのように機能するかです。

void destroy_tree(struct node *leaf)
{
  if( leaf_5 != 0 )  // it's not
  {
      destroy_tree(leaf->left); 
       // Traverse the tree all the way left before any of the code below gets executed.
      destroy_tree(leaf->right); 
       // Traverse the tree all the way right from the final left node before any of 
       //the code below gets executed
      free( leaf );  // Free the final node
  }
}

以下は、再帰的な削除の完全な実装がどのように見えるかを示すコードです。

void DeleteNode(TreeNode*& tree);
void Delete(TreeNode*& tree, ItemType item);
void TreeType::DeleteItem(ItemType item)
// Calls the recursive function Delete to delete item from tree.
{
Delete(root, item);
}
void Delete(TreeNode*& tree, ItemType item)
// Deletes item from tree.
// Post: item is not in tree.
{
if (item < tree->info)
Delete(tree->left, item); // Look in left subtree.
else if (item > tree->info)
Delete(tree->right, item); // Look in right subtree.
else
DeleteNode(tree); // Node found; call DeleteNode.
}


void GetPredecessor(TreeNode* tree, ItemType& data);
void DeleteNode(TreeNode*& tree)
// Deletes the node pointed to by tree.
// Post: The user's data in the node pointed to by tree is no
// longer in the tree. If tree is a leaf node or has only one
// non-NULL child pointer, the node pointed to by tree is
// deleted; otherwise, the user's data is replaced by its
// logical predecessor and the predecessor's node is deleted.
{
ItemType data;
TreeNode* tempPtr;
tempPtr = tree;
if (tree->left == NULL)
{
tree = tree->right;
delete tempPtr;
}
else if (tree->right == NULL)
{
tree = tree->left;
delete tempPtr;
}
else
{
GetPredecessor(tree->left, data);
tree->info = data;
Delete(tree->left, data); // Delete predecessor node.
}
}

void GetPredecessor(TreeNode* tree, ItemType& data)
// Sets data to the info member of the rightmost node in tree.
{
while (tree->right != NULL)
tree = tree->right;
data = tree->info;
}
于 2013-06-18T20:28:01.513 に答える