如何在C中删除二叉树中的元素?

时间:2016-06-07 08:51:31

标签: c pointers binary-tree free

我试图了解二叉树中节点的删除。这是我从教程中找到的代码片段,它解释了相同的内容。

节点如下所示:

struct node
{
  int key_value;
  struct node *left;
  struct node *right;
};

来源:http://www.cprogramming.com/tutorial/c/lesson18.html

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

我怀疑free(leaf)部分。我的意思是,作者声称这将以递归方式从最左下角开始删除所有节点。但是不是free(leaf)只是释放叶子指针的内存吗? Aren所有节点仍然连接?清算是如何进行的?

7 个答案:

答案 0 :(得分:3)

我以图形方式向您展示树的变化:

START:

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

                  10
               /      \
              6           14
             /   \       /  \
            free free  11    18


                  10
               /       \
              free        14
             /   \       /  \
            free  free  11  18


                   10
                /       \
              free         14
             /   \       /    \
            free  free  free  18

                   10
                 /       \
              free         14
             /   \       /     \
            free  free  free  free

                     10
                 /       \
              free         free
             /   \       /     \
            free  free  free  free

                    free
                 /       \
              free         free
             /   \       /     \
            free  free  free  free

当然最终,节点没有连接,它们不再存在。我刚刚在图片中展示了它们在此算法过程中会如何变化。如果您有任何其他问题,请随时提出。

我强烈建议您,只要您无法理解树递归的工作方式,就可以在纸上写一张图片,然后像我上面写的那样通过算法。

答案 1 :(得分:2)

在您发布的链接中,作者有一个如下所示的树:

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

递归删除功能的工作方式是向左下方,然后是右侧,然后删除节点。因此,在上面将发生以下情况(从包含10的节点开始)

Node 10 -> leaf!=null -> destroy_leaf(leaf->left)
  Node 6 -> leaf!=null -> destroy_leaf(leaf->left)
    Node 5 -> leaf!=null -> destroy_leaf(leaf->left)
      null -> do nothing and return back to Node 5
    Node 5 - destroy_leaf(leaf->right)
      null -> do nothing and return back to Node 5
    free(Node 5) and return back to Node 6
  Node 6 -> destroy->leaf(leaf->right)
    Node 8 -> leaf!=null -> destroy_leaf(leaf->left)
      null -> do nothing and return back to Node 8
    Node 8 -> destroy_leaf(leaf->right)
      null -> do nothing and return back to Node 8
    free(node 8) and return back to Node 6
  free(node 6) and return back to Node 10
Node 10 -> destroy_left(leaf->right)

上面显示了该函数将如何从节点10向左递归。由于节点是free d,它们的父节点将指向已释放的内存,但这很好,因为你最终将丢弃递归展开时释放父节点并释放父节点。

答案 2 :(得分:2)

它以递归方式删除叶子和它的分支。我为你画了一个样本。圆圈中的数字表示正在释放的叶子的顺序。这些行显示了代码执行的顺序

enter image description here

答案 3 :(得分:1)

你是对的。它正在从C" Allocated Memory"中回收内存,这很可能是堆。由于您要删除整个树,因此它不能正确地重建节点,因为它们会在树上进行重新计算,因为它们也将被销毁。

此代码不会删除或更确切地说"删除"树中的一个元素,它会在给定叶节点的情况下销毁整个树。

来自网站

  

下面显示的destroy_tree实际上将释放存储在节点leaf:tree下的树中的所有节点。

答案 4 :(得分:1)

  

但是没有(叶子)只返回叶子指针的内存吗?

是。但那不是全部。看看对free的调用,你看到被叫什么?

  

Aren所有节点仍然连接?

没关系因为......

  

如何进行清算?

destroy_tree的递归调用向左和向下递减,这将反过来执行递归破坏,最后它释放,返回调用者,释放等等。最后,整棵树都被释放了。

答案 5 :(得分:1)

free(leaf)调用释放为指针leaf指向的变量分配的内存。这里,它释放了struct node类型的变量占用的所有12个字节 - 即int value的4个字节,node *left指针的4个字节和4个字节的node *right指针。

通过调用destroy_tree(left),您将删除left指向的子树。你可以把它想象成放火到树的顶部并观察它从树叶烧掉,首先是左边的树枝,然后是右边的树枝。

答案 6 :(得分:1)

让我们尝试从这段代码中理解它:

void delete(struct node* node)
{
if(node==NULL)
return;
delete(node->left);
delete(node->right);
free(node)
}

在此代码控件中将首先转到最左边的叶子,它将从那里开始删除(如同删除父级之前我们必须删除其子级) 以树为例:

     1
    / \
   2    3
  / \
 4   5

所以首先释放节点4的内存,然后释放节点5,因为free不返回任何值(内存引用被删除)所以父节点也将指向NULL,所以在5 2之后将被删除。 我希望这有帮助。