【问题标题】:Not deleting node with two children不删除有两个孩子的节点
【发布时间】:2015-05-18 22:02:21
【问题描述】:

当从我的“产品”二叉树中删除一个具有两个子节点的节点时,而不是将要删除的根替换为它的左子最右边的祖先,然后删除该后代,它只是用祖先值替换该根的值.我在那个祖先上调用了“free()”,但这似乎不起作用。所以我剩下的是两个相同值的节点。

我的代码:

#include <stdio.h>
#include <stdlib.h>
//Structures
typedef struct Node{
    void *dataPtr;
    struct Node *left;
    struct Node *right;
}node;

typedef struct Product
{
    int ProductCode;
    char ProductName[30];
    int QuantityOnHand;
    double ProductCost;
    double ProductRetail;
    char ProductLocationCode[7];
}product;

//functions

int  compareID(void *ptr1, void *ptr2)
{
    int  temp;

    if (((product *)ptr1)->ProductCode > ((product *)ptr2)->ProductCode)
        temp = 1;
    else
        if (((product *)ptr1)->ProductCode < ((product *)ptr2)->ProductCode)
            temp = -1;
        else
            temp = 0;
    return temp;
}

void insert(node ** root, node** val, int(*f)(void*,void*)){
    if (!(*root)) {

        //initalize a temporary node
        node *temp = NULL;
        temp = (node *)malloc(sizeof(node));

        //make both right and left nodes for temp to be NULL
        temp->left = NULL;
        temp->right = NULL;


        temp->dataPtr = (*val)->dataPtr;//store value you were looking for in temp
        *root = temp;// root is now the temporary node
        return;//end of function. 
    }
    int result = f((*root)->dataPtr, (*val)->dataPtr);

    if (result == 1) {//if the value is less than the current root node, go to the left connecting node
        insert(&(*root)->left, &(*val), f);
    }
    else if (result == -1) {//if the value is more than the current root node, go to the right connecting node
        insert(&(*root)->right, &(*val), f);
    }
}

struct Node* deleteNode(struct Node *root, void *ptr, int(*cptr)(void*, void*))
{
    struct Node *temp;

    if (cptr(ptr, root->dataPtr) == 0)
    {
        if (root->left == NULL && root->right == NULL)//no children
        {
            free(root);
            return NULL;
        }
        if (root->left != NULL && root->right == NULL)//left child
        {
            temp = root->left;
            free(root);
            return temp;
        }
        if (root->left == NULL && root->right != NULL)//right child
        {
            temp = root->right;
            free(root);
            return temp;
        }
        else //two children
        {
            struct Node* pred = root->left;//go left one of the node you're trying to delete
            while (pred->right != NULL){//now get further right ancestor of that node
                pred = pred->right;
            }

            root->dataPtr = pred->dataPtr; //make the original node the value of that right ancestor
            return pred;//return that ancestor to delete it

        }
    }
    else
    {
        int val = cptr(ptr, root->dataPtr);
        if (val < 0)
        {
            root->left = deleteNode(root->left, ptr, cptr);
            return root;
        }
        else
        {
            root->right = deleteNode(root->right, ptr, cptr);
            return root;
        }
    }

}

void readData(struct Node** vptr, FILE *fp){
    product* ptr = (product *)malloc(sizeof(product));
    if (fp == stdin){
        printf("Enter Product Code: ");
        fscanf(fp, "%d", &(ptr->ProductCode));
        fflush(stdin);

        printf("Enter Name: ");
        fscanf(fp, "%30[^\n]", ptr->ProductName);
        fflush(stdin);

        printf("Enter Quantity: ");
        fscanf(fp, "%d", &(ptr->QuantityOnHand));

        printf("Enter Cost: ");
        fscanf(fp, "%lf", &(ptr->ProductCost));
        fflush(stdin);

        ptr->ProductRetail = (ptr->ProductCost / 0.7);

        printf("Enter Location: ");
        fscanf(fp, "%6[^\n]", &(ptr->ProductLocationCode));
        fflush(stdin);
    }
    else{

        fscanf(fp, "%d %29[^\n] %d %lf %6[^\n]", &(ptr->ProductCode), ptr->ProductName, &ptr->QuantityOnHand, &ptr->ProductCost, &ptr->ProductLocationCode);
        ptr->ProductRetail = (ptr->ProductCost / 0.7);
    }
    (*vptr)->dataPtr = ptr;
}


int main()
{
    int i = 0;
    struct Node *newNode, *temp;
    struct Node *root = NULL;
    int(*compPtr)(void *, void *) = compareID;
    for(i; i < 3; i++){
        newNode = (struct Node *)malloc(sizeof(struct Node));
        newNode->left = newNode->right = NULL;// missing this operation.
        readData(&newNode, stdin);   //  this function call was missing.
        insert(&root, &newNode, compPtr);
    }

    temp = (struct Node *)malloc(sizeof(struct Node));
    temp->dataPtr = malloc(sizeof(struct Product));

    printf("enter the product ID to delete : ");
    fflush(stdin);
    scanf("%d", &((struct Product *)temp->dataPtr)->ProductCode);

    deleteNode(root, temp->dataPtr, compPtr);
    free(temp->dataPtr);
    free(temp);
    return 0;
}

为什么这个祖先节点没有从内存中释放?我应该更改哪些内容才能确保将其删除?

【问题讨论】:

  • 你的调试器向你展示了什么?
  • @StarPilot 尝试将 predecor 返回到 main 时,它没有释放内存中的正确点
  • 所以您在调试器中看到了问题。您的调试器会向您显示哪些节点被选中?

标签: c data-structures binary-search-tree


【解决方案1】:

您的问题和代码起初令人困惑,因为您在表示“后代”时使用了“祖先”一词。子节点是后代。祖先是先人。

问题似乎是您返回后代而不是删除它。在所有其他情况下,您将删除根并返回新节点。在给您带来麻烦的情况下,您不会删除任何节点。相反,您将返回左孩子最右边的后代。调用deleteNode的代码将要删除的节点替换为返回的节点。

在这种情况下,您需要在删除其值替换根值的节点后返回根。但在删除该后代节点之前,您必须从该节点的父节点中删除链接。

我认为你想要的代码是:

//go left one of the node you're trying to delete
struct Node* parent = root;
struct Node* pred = root->left;

//now get further right descendant of that node
while (pred->right != NULL){
    parent = pred;
    pred = pred->right;
}

//make the original node the value of that right descendant
root->dataPtr = pred->dataPtr;

// unlink that node from its parent
if (parent == root)
    parent->left = NULL;
else
    parent->right = NULL;

free(pred);
return root; //return the root node

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-01-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-07-11
    相关资源
    最近更新 更多