不删除有两个孩子的节点

时间:2015-05-18 22:02:21

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

当我从二叉树中删除一个包含两个孩子的节点" products"时,而不是将其替换为删除它的左子女的最右边的祖先然后删除后代,它只是用祖先值替换root的值。我打电话给#34; 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;
}

为什么这个祖先节点没有从内存中释放?我应该更改什么以确保它被删除?

1 个答案:

答案 0 :(得分: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