【问题标题】:Why pointer is not zeroing node of BST after remove function call?为什么在删除函数调用后指针没有将 BST 的节点归零?
【发布时间】:2016-09-15 18:28:53
【问题描述】:

有一个用于 BST 的递归删除函数,它不会将指向叶节点的指针归零。

bool removeNode(Node* tree, int key)
{
    bool removed = false;

    if (tree)
    {
        if (key < tree->key)
        {
            removeNode(tree->left, key);
        }
        else if (key > tree->key)
        {
            removeNode(tree->right, key);
        }
        else // this node is the key
        {
            if (!tree->left && !tree->right) // leaf
            {
                free(tree);
                tree = 0;
            }
            else if (!tree->left)
            {
                *tree = *tree->right;
            }
            else if (!tree->right)
            {
                *tree = *tree->left;
            }
            else // this node has 2 children
            { 
                Node* paux = tree->left;

                if (paux->right)
                {
                    while (paux->right)
                    {
                        paux = paux->right;
                    }
                }

                tree->key = paux->key;
                tree->left = paux->left;
            }

            removed = true;
        }
    }

    return removed;
}

我用

Node* node = (Node*)malloc(sizeof(Node));

分配内存。我的叶子地址正确归零,但是当它返回到上一个调用时,地址仍然保持不变。如果地址被清零,为什么它会返回到以前的值?更改应该影响了指针......不应该吗?

数据结构及相关函数:

typedef struct Node
{
    int key;
    struct Node* left;
    struct Node* right;
} Node;

// init a binary tree
void init(Node** tree, int key)
{
    *tree = (Node*) malloc(sizeof(Node));

    (*tree)->key = key;
    (*tree)->left = 0;
    (*tree)->right = 0;
}

// insert at binary tree
bool insert(Node** tree, int key)
{
    bool inserted = false;

    if (!*tree)
    {
        init(&*tree, key);
    }
    else
    {
        Node* node = (Node*)malloc(sizeof(Node));
        node->key = key;
        node->left = 0;
        node->right = 0;

        Node* paux = *tree;
        Node* root = paux;

        while (paux != 0)
        {
            root = paux;

            if (key < paux->key)
            {
                paux = paux->left;
            }
            else
            {
                paux = paux->right;
            }
        }

        paux = node;
        if (key < root->key)
        {
            root->left = paux;
        }
        else
        {
            root->right = paux;
        }

        inserted = true;
    }

    return inserted;
}

void print(Node* tree)
{
    if (tree != 0)
    {
        printf("%d  ", tree->key);

        print(tree->left);
        print(tree->right);
}

【问题讨论】:

    标签: c pointers binary-search-tree


    【解决方案1】:

    您遇到的问题是因为该函数无法修改输入指针。指针本身是按值传递的。

    想象一个递增整数的函数。由于参数是“按值”传递的,因此简单的实现将不起作用。

    void inc(int x)
    {
        x++;
    }
    

    您可以通过引用(指针)传递此示例来修复此示例

    void inc(int *x)
    {
        (*x)++;
    }
    

    所以,如果您希望能够在函数内使指针无效,请将指针传递给指针:

    bool removeNode(Node **tree, int key)
    

    【讨论】:

      【解决方案2】:

      由于您希望能够在函数内部更改tree,因此您需要一个双指针。

      代替

      bool removeNode(Node* tree, int key)
      

      你需要

      bool removeNode(Node** tree, int key)
                          ^^
      

      这也意味着你需要改变你在函数内部访问tree的方式。

      另请参阅:https://stackoverflow.com/a/39436538/4386427 - 这是同样的问题

      【讨论】:

      • ...类似于void init(Node** tree, int key) 函数。 removeNode 获取指针的副本
      【解决方案3】:

      removeNode() 拥有自己的tree 副本,因此tree 本身的实际值的更改在removeNode() 之外不可见。正如其他人所建议的那样,一种选择是使tree 成为Node **。另一种选择是进行重构,以便在要释放节点的点上可以使用父指针。例如,可以将父级作为另一个参数传递给removeNode(),或者您的代码可以在处理时更深入地测试一个级别。然后你可以做free(parent-&gt;left); parent-&gt;left=0; 或类似的。

      【讨论】:

        猜你喜欢
        • 2016-12-23
        • 1970-01-01
        • 2017-03-25
        • 1970-01-01
        • 2021-01-15
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-09-07
        相关资源
        最近更新 更多