简体   繁体   English

使用顺序遍历删除二叉树

[英]Deleting a binary tree using inorder traversal

I was learning how to delete a binary tree using Postorder traversal. 我正在学习如何使用Postorder遍历删除二叉树。 I understand that to delete a node, first we need to delete its child node and then the node itself, so Postorder traversal is the best fit to delete a binary tree. 我了解要删除一个节点,首先需要删除其子节点,然后再删除节点本身,因此Postorder遍历是删除二叉树的最佳选择。 I thought of doing the same using Inorder traversal, everything works fine but I don't understand how the below code works? 我想过使用顺序遍历做同样的事情,一切正常,但我不明白下面的代码如何工作?

#include<stdio.h>
#include<malloc.h>

struct b_tree{
    int data;
    struct b_tree *left,*right;
};

typedef struct b_tree tree;

tree* create_node(int data)
{
    struct b_tree* new_node=(tree*)malloc(sizeof(tree));
    new_node->data=data;
    new_node->left=NULL;
    new_node->right=NULL;
    return new_node;
}

void delete_tree(tree *root)
{
    if(root==NULL)
        return;
    delete_tree(root->left);
    printf("Deleting %d node.\n",root->data);
    free(root);
    delete_tree(root->right);
}

int main()
{
    tree *root=NULL;
    root=create_node(1);
    root->left=create_node(2);
    root->right=create_node(3);
    root->left->left=create_node(4);
    root->left->right=create_node(5);
    root->left->right->left=create_node(6);
    root->left->right->right=create_node(7);
    root->right->right=create_node(8);
    root->right->right->left=create_node(9);
    delete_tree(root);
    root=NULL;
    return 0;
}

树
According to Inorder traversal first node to be deleted is 4 and after that 2 , but once we freed 2 it should loose all it's data, means it should not retain the pointer to right node as well which is 5 , but even after 2 is freed its left child 5 is still traversed but it should not happen because node 2 is already freed. 根据要遍历的顺序遍历,要删除的第一个节点是4 ,然后是2 ,但是一旦释放2它就应该释放所有数据,这意味着它也不应保留指向右节点的指针5 ,即使释放了2它的左子节点5仍被遍历,但由于节点2已被释放,因此不应发生。

The output of the above code is: 上面代码的输出是:
产量

I was expecting the output to be in the following order of nodes: 4 2 1 . 我期望输出按照以下节点顺序: 4 2 1

I don't understand how all this is working. 我不明白这一切如何运作。 Please correct me if I'm wrong. 如果我错了,请纠正我。

The output it shows is correct , because in inorder it first traverse left sub-tree then root and then right sub-tree . 它显示的输出是正确的,因为首先要先遍历left sub-tree然后遍历rootright sub-tree

You won't get 4 2 1 because 4 is left sub-tree then it goes to root that is 2 and then to right sub-tree of 2 . 您不会得到4 2 1因为4是左边的子树,然后它到达root2 ,然后到右边的子树2

When it goes too right sub-tree root becomes 5 and its left sub-tree is 6 .Then 5 and then to right sub-tree of 5 that is 7 . 当它太右子树的根成为5和它的左子树为6 。然后5 ,然后到右子树57

1 is the root so without traversing left sub-tree it won't go to 1 . 1是根,因此如果不遍历左子树,它将不会变为1

To traverse a binary tree in Inorder, following operations are carried-out 要遍历Inorder中的二叉树,请执行以下操作

(i) Traverse the left most subtree starting at the left external node, 
(ii) Visit the root, and 
(iii) Traverse the right subtree starting at the left external node.

Now to delete the nodes, 现在要删除节点,

(i) Traverse the left most subtree starting at the left external node,
(ii) delete the root, and 
(iii) Traverse the right subtree starting at the left external node.
void delete_tree(tree *root)
{
    if(root==NULL)
        return;
    delete_tree(root->left);
    printf("Deleting %d node.\n",root->data);
    free(root);
    delete_tree(root->right);
}

It is an inorder traversal where pointer will first point to left most node, then root and then right most node. 这是一个有序遍历,其中指针将首先指向最左边的节点,然后是根节点,然后是最右边的节点。 Since 4 is the left most node so it has been printed then it traverse to 2 . 由于4是最左边的节点,因此已被打印,然后遍历到2。 After which the right most node which is 5. Since 5 has two nodes attached to it. 在此之后,最右边的节点是5。因为5有两个附加节点。 It will again iterate to left most node which is 6. So it printed as 4,2,6,5,7,3,9,8 它将再次迭代到最左边的节点6。因此将其打印为4,2,6,5,7,3,9,8

I originally posted this as a comment but it seems the guy asking the question was happy with my answer so I will post it in a bit more detail here. 我最初将其发布为评论,但似乎询问该问题的人对我的回答感到满意,因此我将在此处更详细地发布它。

When calling free it is important to note EXACTLY what free actually does otherwise things like this can happen. 拨打免费电话时,请务必准确说明免费电话实际上会做什么,否则可能会发生这种情况。

The C library function void free(void *ptr) deallocates the memory previously allocated by a call to calloc, malloc, or realloc. C库函数void free(void * ptr)取消分配先前由对calloc,malloc或realloc的调用分配的内存。

Note that the free function does NOT change the value of the pointer it simply gives the memory back to OS so that it can be allocated to another program. 请注意,free函数不会更改指针的值,它只是将内存返回给OS,以便可以将其分配给另一个程序。 As such it is typical for people to "clear" the pointer after calling free to avoid accessing memory that another program has changed. 因此,人们通常在调用free之后“清除”指针以避免访问另一个程序已更改的内存。

root = VOID;

The code above does not clear the root node after freeing it as such the memory is still all there. 上面的代码在释放根节点后并没有清除它,因为内存仍然在那里。 As such the C code is able to go to that memory location (which the OS has already received) and modify it. 这样,C代码便可以转到该存储位置(操作系统已经接收到)并对其进行修改。 This is EXTREMELY dangerous behaviour because the OS can give this memory to another program and then your program could change causing obviously unexpected behaviour. 这是极端危险的行为,因为OS可以将此内存分配给另一个程序,然后您的程序可能会更改,从而导致明显的意外行为。 The simple fix for this would be to remove the right node before freeing the root node. 一个简单的解决方法是在释放根节点之前删除正确的节点。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM