Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/72.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何在C中删除二进制搜索树中的一级节点?_C_Recursion_Binary Search Tree - Fatal编程技术网

如何在C中删除二进制搜索树中的一级节点?

如何在C中删除二进制搜索树中的一级节点?,c,recursion,binary-search-tree,C,Recursion,Binary Search Tree,假设我们有以下BST: 5 (level 0) 3 8 (level 1) 2 4 7 9 (level 2) 尝试删除级别0或1时,一切正常,但删除级别2时除外。我有一个分段错误 [1] 18636 segmentation fault ./a.out 这是我的代码: #include<stdio.h> #include<stdlib.h> struct node {

假设我们有以下BST:

      5           (level 0)
   3       8      (level 1)
2    4    7    9  (level 2)
尝试删除级别0或1时,一切正常,但删除级别2时除外。我有一个分段错误

[1]    18636 segmentation fault  ./a.out
这是我的代码:

#include<stdio.h>
#include<stdlib.h>

struct node
{
    int key;
    struct node *left, *right;
};

// A function to create a new BST node
struct node *newNode(int item)
{
    struct node *temp =  (struct node *)malloc(sizeof(struct node));
    temp->key = item;
    temp->left = temp->right = NULL;
    return temp;
}

// A function to insert a new node with given key in BST
struct node* insert(struct node* node, int key)
{
    // If the tree is empty, return a new node
    if (node == NULL) return newNode(key);

    // Otherwise, recur down the tree
    if (key < node->key)
        node->left  = insert(node->left, key);
    else if (key > node->key)
        node->right = insert(node->right, key);

    // return the (unchanged) node pointer
    return node;
}

// Given a non-empty binary search tree, return the node with minimum
// key value found in that tree. Note that the entire tree does not
// need to be searched.
struct node * minValueNode(struct node* node)
{
    struct node* current = node;

    // loop down to find the leftmost leaf
    while (current->left != NULL)
        current = current->left;

    return current;
}

struct node* deleteNode(struct node* root, int key)
{
    // base case
    if (root == NULL) return root;

    // If the key to be deleted is smaller than the root's key,
    // then it lies in left subtree
    if (key < root->key)
        root->left = deleteNode(root->left, key);

    // If the key to be deleted is greater than the root's key,
    // then it lies in right subtree
    else if (key > root->key)
        root->right = deleteNode(root->right, key);

    // if key is same as root's key, then This is the node
    // to be deleted
    else
    {
        // node with only one child or no child
        if (root->left == NULL)
        {
            struct node *temp = root->right;
            free(root);
            return temp;
        }
        else if (root->right == NULL)
        {
            struct node *temp = root->left;
            free(root);
            return temp;
        }

        // node with two children: Get the inorder successor (smallest
        // in the right subtree)
        struct node* temp = minValueNode(root->right);

        // Copy the inorder successor's content to this node
        root->key = temp->key;

        // Delete the inorder successor
        root->right = deleteNode(root->right, temp->key);
    }
    return root;
}

void deleteGivenLevel(struct node* root, int level)
{
    if (root == NULL)
    {
        return;
    }
    if (level == 0)
    {
        printf("\n %d will be removed!", root->key);
        root = deleteNode(root, root->key);
    }
    else if (level > 0)
    {
        deleteGivenLevel(root->left, level-1);
        deleteGivenLevel(root->right, level-1);
    }
}

// A function to do inorder traversal of BST
void inorder(struct node *root)
{
    if (root != NULL)
    {
        inorder(root->left);
        printf("\t %d", root->key);
        inorder(root->right);
    }
}

int main()
{
    int input, level;
    struct node *root = NULL;

    printf("\nEnter a number to go into the BST: ");
    scanf("%d",&input);
    root = insert(root, input);

    while(1)
    {
        printf("\nEnter another number (0 to stop): ");
        scanf("%d",&input);
        if (input==0)
        {
            break;
        }
        insert(root, input);
    }

    // print inoder traversal of the BST
    printf("\nBefore Deletion:");
    inorder(root);

    printf("\nWhich level would you like to delete? ");
    scanf("%d",&level);
    deleteGivenLevel(root, level);

    // print inoder traversal of the BST
    printf("\nAfter Deletion:");
    inorder(root);
    return 0;
}
#包括
#包括
结构节点
{
int键;
结构节点*左、*右;
};
//用于创建新BST节点的函数
结构节点*新节点(int项)
{
结构节点*temp=(结构节点*)malloc(sizeof(结构节点));
temp->key=项目;
临时->左=临时->右=空;
返回温度;
}
//在BST中插入具有给定密钥的新节点的函数
结构节点*插入(结构节点*节点,int键)
{
//如果树为空,则返回一个新节点
如果(node==NULL)返回newNode(key);
//否则,将从树上再次出现
如果(键<节点->键)
节点->左=插入(节点->左,键);
否则如果(键>节点->键)
节点->右侧=插入(节点->右侧,键);
//返回(未更改的)节点指针
返回节点;
}
//给定一个非空的二叉搜索树,返回具有最小值的节点
//在该树中找到键值。请注意,整棵树没有
//需要搜索。
结构节点*最小值节点(结构节点*节点)
{
结构节点*当前=节点;
//向下循环找到最左边的叶子
while(当前->左!=NULL)
当前=当前->左侧;
回流;
}
结构节点*删除节点(结构节点*根,int键)
{
//基本情况
if(root==NULL)返回root;
//如果要删除的键小于根的键,
//然后它位于左子树中
如果(键<根->键)
根->左=删除节点(根->左,键);
//如果要删除的键大于根的键,
//然后它位于右子树中
否则如果(键>根->键)
根->右=删除节点(根->右,键);
//如果键与根的键相同,则这是节点
//删除
其他的
{
//只有一个子节点或没有子节点的节点
如果(根->左==NULL)
{
结构节点*temp=root->right;
自由根;
返回温度;
}
else if(root->right==NULL)
{
结构节点*temp=root->left;
自由根;
返回温度;
}
//具有两个子节点的节点:获取顺序后继节点(最小)
//在右子树中)
结构节点*temp=minValueNode(根->右);
//将顺序继承者的内容复制到此节点
根->键=临时->键;
//删除顺序继承项
根->右=删除节点(根->右,临时->键);
}
返回根;
}
void deleteGivenLevel(结构节点*根,整数级)
{
if(root==NULL)
{
返回;
}
如果(级别==0)
{
printf(“\n%d将被删除!”,根->键);
根=删除节点(根,根->键);
}
否则,如果(级别>0)
{
deleteGivenLevel(根->左,级别1);
deleteGivenLevel(根->右侧,级别1);
}
}
//按顺序遍历BST的函数
无效索引顺序(结构节点*根)
{
if(root!=NULL)
{
顺序(根->左);
printf(“\t%d”,根->键);
顺序(根->右);
}
}
int main()
{
int输入,电平;
结构节点*root=NULL;
printf(“\n输入一个数字进入BST:”);
scanf(“%d”,输入(&I));
根=插入(根,输入);
而(1)
{
printf(“\n输入另一个数字(0停止):”;
scanf(“%d”,输入(&I));
如果(输入==0)
{
打破
}
插入(根,输入);
}
//按BST的遍历顺序打印
printf(“\n删除前:”);
顺序(根);
printf(“\n要删除哪个级别?”);
扫描频率(“%d”级和级别);
deleteGivenLevel(根,级别);
//按BST的遍历顺序打印
printf(“\n删除后:”);
顺序(根);
返回0;
}

我还注意到,它只在我尝试删除级别0或1时起作用。除此之外,它不起作用。如果我添加更多节点并尝试删除。在这种情况下,它根本不会删除任何内容。

问题在于
deleteNode

使用叶调用
deleteNode
时(其
子节点 如果
NULL
)作为参数,则执行此块:

if (root->left == NULL)
{
    struct node *temp = root->right;
    free(root);
    return temp;
}
else if (root->right == NULL)
{
    struct node *temp = root->left;
    free(root);
    return temp;
}
这里的问题是,您正在释放叶,但父对象是 指向叶不会被更新,因此它会一直指向已更新的叶 释放内存,当您再次遍历树时,访问无效 记忆。这会产生未定义的行为,并以segfault结束

如果您逐步执行
deleteGivenLevel
函数,最终
root
将是键==3的节点。那你呢

deleteGivenLevel(root->left, level-1);
其中
root->left
是带有
key==2
的叶,而
level-1
是0。这意味着 在下一个电话里,这就是

if (level == 0)
{
    printf("\n %d will be removed!", root->key);
    root = deleteNode(root, root->key);
}
执行时,
root
是键==2的叶。问题是, 该节点将被删除,但由于它是一个leave,因此具有
key==3
的节点
left
元素指向叶,不会得到更新

快速修复方法是将父节点传递给
deleteNode
,然后
deleteGivenLevel
,以便正确更新父节点。但是你 你应该重新考虑一下你的删除策略

struct node* deleteNode(struct node* root, int key, struct node *parent)
{
    // base case
    if (root == NULL) return root;

    // If the key to be deleted is smaller than the root's key,
    // then it lies in left subtree
    if (key < root->key)
        root->left = deleteNode(root->left, key, NULL); // you could also call
                                                        // with root as the
                                                        // 3rd argument, but
                                                        // you update the parent in this line
                                                        // anyway


    // If the key to be deleted is greater than the root's key,
    // then it lies in right subtree
    else if (key > root->key)
        root->right = deleteNode(root->right, key, NULL); // same as above

    // if key is same as root's key, then This is the node
    // to be deleted
    else
    {
        // node with only one child or no child
        if (root->left == NULL)
        {
            struct node *temp = root->right;

            // update only if parent is present
            if(parent)
            {
                if(root->key < parent->key)
                    parent->left = temp;
                else
                    parent->right = temp;
            }

            free(root);
            return temp;
        }
        else if (root->right == NULL)
        {

            struct node *temp = root->left;

            // update only if parent is present
            if(parent)
            {
                if(root->key < parent->key)
                    parent->left = temp;
                else
                    parent->right = temp;
            }

            free(root);
            return temp;
        }

        // node with two children: Get the inorder successor (smallest
        // in the right subtree)
        struct node* temp = minValueNode(root->right);

        // Copy the inorder successor's content to this node
        root->key = temp->key;

        // Delete the inorder successor
        root->right = deleteNode(root->right, temp->key, root);
    }
    return root;
}

void deleteGivenLevel(struct node* root, int level, struct node *parent)
{
    if (root == NULL)
    {
        return;
    }
    if (level == 0)
    {
        printf("\n %d will be removed!", root->key);
        root = deleteNode(root, root->key, parent);
    }
    else if (level > 0)
    {
        deleteGivenLevel(root->left, level-1, root);
        deleteGivenLevel(root->right, level-1, root);
    }
}

void free_tree(struct node *root)
{
    if(root == NULL)
        return;

    free_tree(root->left);
    free_tree(root->right);
    free(root);
}
这就是结果:

$valgrind./a
==24038==Memcheck,内存错误检测器
==24038==2002-2017年版权(C)和GNU GPL'd,朱利安·苏厄德等人。
==24038==使用Valgrind-3.13.0和LibVEX;使用-h重新运行以获取版权信息
==24038==命令:./a
==24038== 
删除前:2 3 4 5 7 8 9
2将被删除!
4将被删除!
7将被删除!
9将被删除!
删除后:3 5 8
==24038== 
==24038==堆摘要:
==24038==在出口处使用:0个块中有0个字节
==24038==总hea
int main()
{
    int level;
    struct node *root = NULL;

    int vals[] = { 5, 3, 8, 2, 4, 7, 9 };

    for(size_t i = 0; i < sizeof vals / sizeof *vals; ++i)
        root = insert(root, vals[i]);

    // print inoder traversal of the BST
    printf("\nBefore Deletion:");
    inorder(root);
    puts("");

    level = 2;
    deleteGivenLevel(root, level, NULL);

    // print inoder traversal of the BST
    printf("\nAfter Deletion:");
    inorder(root);
    puts("");

    free_tree(root);
    return 0;
}