当我从二叉树中删除一个包含两个孩子的节点" 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;
}
为什么这个祖先节点没有从内存中释放?我应该更改什么以确保它被删除?
答案 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