I am trying to implement the deletion function for a binary search tree in C, however I am running into problems.
I have the following structs for the tree and the nodes
typedef struct {
double value;
struct Node *parent;
struct Node *right_child;
struct Node *left_child;
} Node;
typedef struct {
struct Node *root;
} Tree;
I also have an in-order traversal function
void inOrderTraversalNode(Node *n) {
if (n != NULL) {
inOrderTraversalNode(n->left_child);
printf("%f\n", n->value);
inOrderTraversalNode(n->right_child);
}
}
A subtree minimum function
Node * minimum(Node *n) {
while (n->left_child != NULL) {
n = n->left_child;
}
return n;
}
and a transplant function
void transplant(Tree *t, Node *u, Node *v) {
Node *p = u->parent;
//replace u's parent's child pointer to v
if (p == NULL) {
t->root = v;
} else if (u == p->left_child) {
p->left_child = v;
} else {
p->right_child = v;
}
//set v's parent pointer to u's parent
if (v != NULL) {
v->parent = p;
}
}
And finally I have the delete function
void delete(Tree *t, Node *z) {
//if node z has no left subtree, replace z with right subtree and vice-versa.
if (z->left_child == NULL) {
transplant(t, z, z->right_child);
} else if (z->right_child == NULL) {
transplant(t, z, z->left_child);
} else {
Node *y = minimum(z->right_child);
if (y->parent != z) {
transplant(t, y, y->right_child);
Node *y_right_child = y->right_child;
y_right_child = z->right_child;
y_right_child->parent = y;
}
transplant(t, z, y);
Node *y_left_child = y->left_child;
y_left_child = z->left_child;
y_left_child->parent = y;
}
}
However when I run the following code in main
int main(void) {
Node n1;
Node n2;
Node n3;
Node n4;
Node n5;
Node n6;
Node n7;
Node n8;
n1.value = 4;
n1.parent = NULL;
n1.left_child = &n2;
n1.right_child = &n5;
n2.value = 2;
n2.parent = &n1;
n2.left_child = &n3;
n2.right_child = &n4;
n3.value = 1;
n3.parent = &n2;
n3.left_child = NULL;
n3.right_child = NULL;
n4.value = 3;
n4.parent = &n2;
n4.left_child = NULL;
n4.right_child = NULL;
n5.value = 6;
n5.parent = &n1;
n5.left_child = &n6;
n5.right_child = &n7;
n6.value = 5;
n6.parent = &n5;
n6.left_child = NULL;
n6.right_child = NULL;
n7.value = 7;
n7.parent = &n5;
n7.left_child = NULL;
n7.right_child = NULL;
Tree t;
t.root = &n1;
printf("In order traversal\n");
inOrderTraversalNode(t.root);
printf("Delete node\n");
delete(&t,&n1);
inOrderTraversalNode(t.root);
return EXIT_SUCCESS;
}
It returns 1,2,3,4,5,6,7 for the first traversal. But it returns 1,2,3,4,7 for the second traversal after deleting n5 which is incorrect because it misses the n6 node containing 5. I do not understand why this is happening. I have inserted some print statements in the delete function and the n7 node is adding the n6 node as its left child, but for some reason it doesn't get printed during the traversal.
This code caught my attention:
Node *y_right_child = y->right_child;
y_right_child = z->right_child;
y_right_child->parent = y;
You assign a value to variable y_right_child, and then you immediately replace it with a different value. What you intend to do, it appears, is transfer node z's right child to node y. That would be this:
y->right_child = z->right_child;
y->right_child->parent = y;
You don't need to remember or modify y's original right child at that point, because that was already handled via function transplant().
There is a similar issue with the other child-transfer code:
Node *y_left_child = y->left_child;
y_left_child = z->left_child;
y_left_child->parent = y;
Again, you assign a value to the variable, and then immediately replace it. What you appear really to want is this:
y->left_child = z->left_child;
y->left_child->parent = y;
Note that because node y started out as the minimum value from its subtree, you can be certain that y->left_child is initially NULL.
As your code stands, the type struct Node is not declared or defined anywhere. The typedef at the top of your code doesn't accomplish this; it defines a different type called Node. See typedef struct vs struct definitions. This should have caused a ton of warnings in your compilation. Don't ignore them!
It also seems to have been the indirect cause of the real bug. In delete you have the code
Node *y_right_child = y->right_child;
y_right_child = z->right_child;
y_right_child->parent = y;
which is clearly not the right thing. You want to change the right child pointer of y. But when you wrote what you really want:
y->right_child = z->right_child;
y->right_child->parent = y;
you got an error because y->right_child is of the undefined type struct Node * and therefore can't be dereferenced. Rather than fix this properly, you introduced the local variable y_right_child, which at least made the code compile. But what good is code that compiles, if it doesn't work? Assigning to y_right_child just changes the value of the local variable; it doesn't change the value of the pointer y->right_child itself.
Changing the very first line to typedef struct Node { causes struct Node to be defined as what you want (and the typedef Node is defined as the same type). Then changing y_right_child to y->right_child and removing the variable y_right_child altogether, and doing the same for y->left_child, the delete works as intended.
Related
For a school project in C, I want to create a pathfinding algorithm, I decided to use A*.
After long reflexion and rewrite of many time all the code I can't find what is wrong. It must be because of the memory management but I can't figure out where it goes wrong. Even after looking for hours on forums I didn't find anything interesting.
The gdb help me a little bit more when he shows me in which function the segfault occurs.
(gdb) bt
#0 0x0000000008000917 in list_prepend ()
#1 0x0000000008000b38 in findPath ()
#2 0x0000000008001473 in main ()
I use struct to represent my Nodes and for my lists of pointers to the Nodes.
typedef struct Coord Coord;
struct Coord{
int x;
int y;
};
typedef struct Node{
bool walkable;
bool wayToGo;
Coord pos;
int gCost;
int hCost;
int fCost; // fCost = gCost + hCost
struct Node *parent;
} Node;
typedef struct NodeList{
Node * pNode;
struct NodeList * next;
struct NodeList * previous;
} NodeList;
And the function that raise the SIGSEGV :
NodeList * list_prepend(NodeList *old, Node *pNode)
{
NodeList *list = list_create(pNode);
if (list){
list->next = old;
old->previous = list;
}
return list;
}
Where :
NodeList * list_create (Node *pNode)
{
NodeList *list = malloc(sizeof(NodeList));
if (list)
{
list->pNode = pNode;
list->next = NULL;
list->previous = NULL;
}
return list;
}
I think that the problem comes from old->previous = list because it looks like old->previous gives NULL and I try to affect something to NULL. I don't know and that's why I'm asking.
If you have any idea or if you can share a good debugging technique that would be great.
If needed here is the full code I wrote to test the pathfinder :
pathFinding.c
NodeList * list_prepend(NodeList *old, Node *pNode)
{
NodeList *list = list_create(pNode);
if (list){
list->next = old;
(*old).previous = list; // Since this accesses *old, old cannot be NULL
}
return list;
}
See the comment above. It is a pre-condition of calling list_prepend that old not be NULL.
NodeList * getNeighbours(Node grid[row][column], Node * pNode)
{
int x, y;
NodeList * list = NULL;
for(x = -1; x <= 1; x++){
for(y = -1; y <= 1; y++){
if(x == y || x == -y)
continue;
int checkX = pNode->pos.x + x;
int checkY = pNode->pos.y + y;
if (checkX >= 0 && checkX < column && checkY >= 0 && checkY < row){
list = list_prepend(list, &(grid[checkY][checkX])); // Uh oh, list is NULL on first invocation
}
}
}
return list;
}
See the comment. The first call to list_prepend violates the pre-condition. It is very important to clearly document (in comments) the pre-conditions of your functions. It is also extremely helpful to test that all pre-conditions are true and report any that aren't. It makes debugging much easier.
I'm also puzzled by your thinking in a few places. For example:
NodeList * list_append(NodeList *list, Node *pNode)
{/*Rajouter le previous*/
NodeList **plist = &list;
while (*plist)
plist = &(*plist)->next;
*plist = list_create(pNode);
if (*plist)
return list;
else
return NULL;
}
Why the mess with double indirection in plist? And why don't you set the newly-created node's prev? Why not just:
NodeList * list_append(NodeList *list, Node *pNode)
{
if (list == NULL)
return list_create(pNode);
NodeList *plist = list;
while (plist->next != NULL)
plist = plist->next;
plist->next = list_create(pNode);
if (plist->next == NULL)
return NULL;
plist->next->prev = plist;
return list;
}
I am relatively new to C, and have been learning about linked lists with pointers.
I learned that
(*foo).bar is the same ad foo->bar.
foo->bar is used because it is more readable.
Therefore I do not understand why these code snippets behave differently:
1)
void appendCourse(CourseNode** pLL, Course c){
CourseNode * root = *pLL;
CourseNode* last = makeCourseNode(c);
if(root != NULL){
CourseNode node = *root;
while(node.pNext != NULL){
node = *node.pNext;
}
node.pNext = last;
} else {
*pLL = last;
}
}
and
2)
void appendCourse(CourseNode** pLL, Course c){
CourseNode * root = *pLL;
CourseNode* last = makeCourseNode(c);
if(root != NULL){
CourseNode *node = root;
while(node->pNext != NULL){
node = node->pNext;
}
node->pNext = last;
} else {
*pLL = last;
}
}
to me it looks like 1) should behave as if dereferencing first, then member access. Sort of like (*foo).bar
but 1) doesn't seem to work right at all, it can only successfully add the first element.
2) does however add all elements into the linked list.
In case this helps: my structs and other method:
typedef struct CourseNode {
struct CourseNode* pNext;
Course course;
} CourseNode;
typedef struct
{
StudentNode *pWaitlistHead; // Waitlist for this course
char szCourseId[12]; // Course Identifier
char szRoom[15]; // Room number of the course
char szDays[15]; // What days the course will meet, ex: MWF, TR, etc
char szTimes[15]; // Meeting Time, ex: 10:00-11:15am
int iAvailSeats; // Number of available seats in the course
double dFee; // Additional fees for the course
} Course;
CourseNode* makeCourseNode(Course c){
CourseNode * node = malloc(sizeof(CourseNode));
node->pNext = NULL;
node->course = c;
return node;
}
CourseNode node = *root;
while(node.pNext != NULL){
node = *node.pNext;
}
This creates a new CourseNode called node. The value of that new CourseNode is modified, but that has no affect on the linked list.
CourseNode *node = root;
while(node->pNext != NULL){
node = node->pNext;
}
Here, node points to a CourseNode that is on the linked list.
The simplest way to understand the difference is that the first code excerpt creates new CourseNodes. It's like the difference between these two:
int foo (int *i)
{
int *j = i; // j is a pointer to the same int i points to
*j = 2; // this changes the value of the int i points to
int j = *i; // this creates a new int
j = 2; // this changes the value of that new int
}
I'm performing binary tree deletion in c.I was trying out few methods interestingly this weird situation came.
void Delete(){
struct BinaryTree* ptr = root;
int element;
printf("Enter element to delete : ");
scanf("%d",&element);
while(ptr){
if(element>ptr->data)
ptr = ptr->right;
else if(element<ptr->data)
ptr = ptr->left;
else
break;
}
if(ptr->left && ptr->right){
struct BinaryTree **smallest = &(ptr);
smallest = &((*smallest)->right);
while((*smallest)->left){
smallest = &((*smallest)->left);
}
ptr->data = (*smallest)->data;
free(*smallest);
*smallest = NULL;
} else if(ptr->left){
/*rest cases*/
}
}
The above code works and it sets the the NODE to NULL.
But when i do this procedure in this way it doesn't set to NULL.
if(ptr->left && ptr->right){
struct BinaryTree *smallest = ptr;
smallest = smallest->right;
while(smallest->left){
smallest = smallest->left;
}
ptr->data = smallest->data;
struct BinaryTree **refsmall = &smallest;
free(*refsmall);
*refsmall = NULL;
}
Aren't these two methods are same? If not can someone explain me how they are different?Why the first method work and second didn't?
You should avoid using global variables in your code. If you really want to use globals the first version of delete should look like this:
void Delete(){
/* at some point you will need to change the 'real' root, not the copy of it */
struct BinaryTree **ptr = &root;
int element;
printf("Enter element to delete : ");
scanf("%d",&element);
while(*ptr){
if(element > (*ptr)->data)
ptr = &(*ptr)->right;
else if(element < (*ptr)->data)
ptr = &(*ptr)->left;
else
break;
}
if((*ptr)->left && (*ptr)->right){
struct BinaryTree **smallest = ptr;
smallest = &(*smallest)->right;
while((*smallest)->left){
smallest = &(*smallest)->left;
}
(*ptr)->data = (*smallest)->data;
free(*smallest);
*smallest = NULL;
} else if((*ptr)->left){
/*rest cases*/
}
}
In the first version you would not be able to delete the root.
struct node {
struct node *l,*r;
int data;
};
void delnode(struct node **pp, int data)
{
struct node *del, *l,*r;
// Walk the tree
while(*pp) {
if ((*pp)->data < data) {pp = &(*pp)->l; continue;}
if ((*pp)->data > data) {pp = &(*pp)->r; continue;}
break; // found it!
}
if (!*pp) return; // not found
del = *pp;
l = del->l;
r = del->r;
// If only one child it wil take del's place.
if (!r) *pp = l;
else if (!l) *pp = r;
// del has two children.
// pick one (R) child, and append the (L) other onto its (Leftmost) shoulder
else {
*pp = r;
for (pp= &del->r; *pp; pp=&(*pp)->l) {;} // find Leftmost NULL pointer in the R tree
*pp = l;
}
free(del);
}
#include<stdio.h>
struct llist {
int data;
struct llist *next;
};
typedef struct llist list;
struct graph {
int V;
list **adj;
};
typedef struct graph graph;
graph* create_graph(int V) {
list **adj = (list**)malloc(sizeof(list*)*V);
graph *a = (graph*)malloc(sizeof(graph));
a->V = V;
a->adj = adj;
return a;
}
void insert_list(list **head, int v) {
list *new_node, *temp_node, *last_node;
new_node = (list*)malloc(sizeof(list));
new_node->data = v;
new_node->next = NULL;
printf("\n hi %d", head);
/*
* head is empty, point the head to temp and return.
*/
if (*head == NULL) {
*head = new_node;
return;
}
temp_node = *head;
do{
last_node = temp_node;
temp_node = temp_node->next;
}while(temp_node);
last_node->next = new_node;
}
void addedge(graph *g, int u, int v) {
insert_list(&(g->adj[u]), v);
}
int
main() {
int V = 10;
graph *a = create_graph(V);
printf("\n graph created");
addedge(a, 1,2);
addedge(a,1,5);
addedge(a,2,1);
addedge(a,2,5);
addedge(a,2,3);
addedge(a,2,4);
addedge(a,3,2);
addedge(a,3,4);
addedge(a,4,2);
addedge(a,4,5);
addedge(a,4,3);
addedge(a,5,4);
addedge(a,5,1);
addedge(a,5,2);
return 0;
}
In this code, by printing messages, I have found is create_graph function executes properly and returns a graph. Then addedge is being called, In it, if(*head==NULL) part always returns false (Don't know why, first time it should return true). Then it goes ahead in do while loop and that keep executing till infinity and code terminates.
What I am trying to do is I have a structure called graph, with a integer variable V and array of linked list variable adj (represents adjacency list). And then create graph will initialise a graph variable and return it.
Addedge(V,u,v) will add edge v to u (means v is adjacent to u). so adj[0....V-1] is a array of linked list. so if edge 1 is adjacent to 2 and 3, then list will look like 1->2->3.
Comment If more info needed. I don't know what why *head is not null the first time and why the while loop never terminates.
Thanks a lot in advance.
By trail and error, I found the mistake.
In function create graph, after initialising the list, each individual list also must be initialised to NUll, otherwise it will have junk stuff.
Below is correct code :
graph* create_graph(int V) {
list **adj = (list**)malloc(sizeof(list*)*V);
int i;
for (i = 0; i < V; ++i) {
adj[i] = NULL;
}
graph *a = (graph*)malloc(sizeof(graph));
a->V = V;
a->adj = adj;
return a;
}
Disclaimer: This is for an assignment. I am not asking for explicit code answers, only help understanding why my code isn't working.
I am trying to implement a basic Binary Search Tree, but I am having problems with my _addNode(...) function.
Here's the problem. When I walk through my code with the debugger, I notice that leaf nodes are created infinitely on both sides (left and right) so aside from the creation of the root, there is never any point when a leaf node is NULL. The problem is that I am asking my program to create a new node whenever it finds a NULL value where a leaf would be. Therefore, if there are never any NULL values, there will never be any new leaves created, right?
The other issue I'm running into is with my compare(...) function. Stepping through it in the debugger shows it to iterate through the function several times, never actually returning a value. When it returns to the calling function, it drops back into the compare(...) function and loops infinitely. Again, I don't know why this is happening considering I have valid return statements in each if statement.
Here is all the code you'll probably need. If I left something out, let me know and I'll post it.
struct Node {
TYPE val;
struct Node *left;
struct Node *right;
};
struct BSTree {
struct Node *root;
int cnt;
};
struct data {
int number;
char *name;
};
int compare(TYPE left, TYPE right)
{
assert(left != 0);
assert(right != 0);
struct data *leftData = (struct data *) left;
struct data *rightData = (struct data *) right;
if (leftData->number < rightData->number) {
return -1;
}
if (leftData->number > rightData->number) {
return 1;
} else return 0;
}
void addBSTree(struct BSTree *tree, TYPE val)
{
tree->root = _addNode(tree->root, val);
tree->cnt++;
}
struct Node *_addNode(struct Node *cur, TYPE val)
{
assert(val != 0);
if(cur == NULL) {
struct Node * newNode = malloc(sizeof(struct Node));
newNode->val = val;
return newNode;
}
if (compare(val, cur->val) == -1) {
//(val < cur->val)
cur->left = _addNode(cur->left, val);
} else cur->right = _addNode(cur->right, val);
return cur;
}
Edit: Adding the below function(s)
int main(int argc, char *argv[])
{
struct BSTree *tree = newBSTree();
/*Create value of the type of data that you want to store*/
struct data myData1;
struct data myData2;
struct data myData3;
struct data myData4;
myData1.number = 5;
myData1.name = "rooty";
myData2.number = 1;
myData2.name = "lefty";
myData3.number = 10;
myData3.name = "righty";
myData4.number = 3;
myData4.name = "righty";
/*add the values to BST*/
addBSTree(tree, &myData1);
addBSTree(tree, &myData2);
addBSTree(tree, &myData3);
addBSTree(tree, &myData4);
/*Print the entire tree*/
printTree(tree);
/*(( 1 ( 3 ) ) 5 ( 10 ))*/
return 1;
}
Maybe you could try setting right and left to NULL right after malloc:
struct Node * newNode = malloc(sizeof(struct Node));
newNode->left = NULL;
newNode->right = NULL;
Check this line here (or the corresponding for left):
cur->right = _addNode(cur->right, val);
If cur->right == 0, it's fine. But if cur->right != 0, the node that was sitting there will be replaced by the return value of _addNode, which ultimately is not a whole branch, but just one node.
I like to explicitly 0-out values in a struct after a malloc using memset(newNode, 0, sizeof(struct Node)). Others might disagree.