Let x = the node to be deleted
How can I reassign the left or right pointer of x's parent to x's left or right sub tree during rotation without a parent pointer in node's struct declaration using recursion in an AVL Tree Implementation coded in C?
My Node's struct declaration:
typedef struct Node{
int key;
struct Node *left;
struct Node *right;
int height;
}node;
Currently, these are my rotation codes:
void rotateRight(node **n){
node *lChild = (*n)->left;
node *subtree = lChild->right;
// Rotate Right
lChild->right = *n;
(*n)->left = subtree;
*n = lChild;
// Update Height
lChild->right->height = max(getHeight(lChild->right->left), getHeight(lChild->right->right)) + 1;
(*n)->height = max(getHeight((*n)->left), getHeight((*n)->right)) + 1;
}
void rotateLeft(node **n){
node *rChild = (*n)->right;
node *subtree = rChild->left;
// Rotate Left
rChild->left = *n;
(*n)->right = subtree;
*n = rChild;
// Update Height
rChild->left->height = max(getHeight(rChild->left->left), getHeight(rChild->left->right)) + 1;
(*n)->height = max(getHeight((*n)->left), getHeight((*n)->right)) + 1;
}
When I execute these rotation codes, I lose some elements that should have not been deleted.
You can't. Either add a pointer to parent to your structure, or write your recursion in a way that passes node and parent on each level, so you can pass the parent as a second parameter to your rotate functions.
Related
I've just tried to sort a linked list in my own way. I tried to bubble sort it entirely with recursion. Below is my code. Sorting works fine. I just wanted to know if there are some better ways to do this. Should I have done it iteratively rather than using recursion? I'd be happy to hear some suggestions.
// Some preprocessing stuff ...
// definition of node
typedef struct node {
int num;
struct node *next;
}node;
// ... functions
int main(void)
{
node *list = create_list(n); // n is list's length
sort(list, list, NULL);
}
Sort function
void sort(const node *first_node, node *left, node *last_node)
{
node *right = left->next;
if (first_node == last_node)
return;
if (right == last_node)
{
last_node = left;
left = first_node;
}
else if (right->num < left->num)
{
swap(&left->num, &right->num);
left = right;
}
else
left = right;
sort(first_node, left, last_node);
}
I'm working on implementing a binary search tree data structure in C, but I got stuck at the part where you point to the left or right child. I understand that if the value you're inserting is smaller than the root, it goes to the left and to the right if it's larger. I'm just struggling with the double pointers part as shown in the code below. Let's take bs_tree_insert_left for example, I want pos->left_child to point to the left_child in order to place the value given there, but I'm not sure how I would write this.
For context regarding the main function, the numbers in arr[] will be randomly shuffled but I removed that part of the code to keep the post short and compact.
struct node
{
int value;
struct node *left_child;
struct node *right_child;
};
typedef struct node BSTree;
typedef struct node* BSTreePos;
BSTree *bs_tree_make(int value){
// Allocate memory for new node
struct node* origin = (struct node*)malloc(sizeof(struct node));
// Assign data to this node
origin->value = value;
// Initialize left and
// right children as NULL
origin->left_child = NULL;
origin->right_child = NULL;
return (origin);
}
BSTreePos bs_tree_insert_left(int value, BSTreePos pos){
pos->left_child = bs_tree_make(value);
return pos->left_child;
}
void insert_value(int value, BSTreePos pos)
{
if (pos == NULL) return bs_tree_make(value);
if (value < pos->value)
{
pos->left_child = bs_tree_insert_left(value, pos->left_child);
}
else if (value > pos->value)
{
pos->right_child = bs_tree_insert_right(value, pos->right_child);
}
}
int main(void)
{
// Create an array with the values 1, 2, ..., 10 and print out the content.
int n = 10;
int arr[n];
for (int i = 0 ; i < n ; i++) {
arr[i] = i + 1;
}
print_array(n, arr);
BSTree *tree = bs_tree_make(arr[0]);
for (int i = 1 ; i < n ; i++) {
BSTreePos pos = bs_tree_root(tree);
insert_value(arr[i], pos);
}
return 0;
}
You know what, I'm just going to write the correct algorithm that uses the double pointer to maximum effect.
void insert_value(int value, struct node **node)
{
if (*node == NULL) {
*node = malloc(sizeof(struct node));
node[0]->value = value;
node[0]->left_child = NULL;
node[0]->right_child = NULL;
} else if (node[0]->value < value)
insert_value(value, &node[0]->left_child);
else if (node[0]-> value > value)
insert_value(value, &node[0]->right_child);
/* else duplicate value found -- don't insert (from OP's code) */
}
BSTree *tree = NULL;
for (int i = 0 ; i < n ; i++) {
insert_value(arr[i], &tree);
}
node[0]->value is the idiomatic way of accessing a struct through a double pointer.
But let's look at how this works and how much value this gets out of the double pointer. The empty tree is stored as the NULL pointer. This makes initializing the tree and adding a node to the tree the same code. Notice how insert_value takes a double pointer to the tree; this allows it to fill out the root node when adding the first node, or any child node thereof. Thus double pointer which is pointer to pointer is used to update a pointer to a node when we make a new one.
With this algorithm, having a bs_tree_insert_left literally makes no sense. The whole idea is the code that does the insertion doesn't know where it is inserting the node.
Fun fact: the compiler will transform away the recursion for us when compiling with optimizations.
I have this code to rightRotate a sub tree :
void rightRotate(mynode **parentPtr, mynode *child)
{
// make sure the arguments are valid for a right rotation
assert(parentPtr != NULL && child != NULL && child->left != NULL);
// save the three node addresses involved in the rotation
mynode *F = child;
mynode *D = F->left;
mynode *E = D->right;
// perform the rotation
*parentPtr = D;
D->right = F;
F->left = E;
}
Tree struct is :
typedef struct tree mynode; // differences between nametag and type????
struct tree{ // tree node struct
int value;
int key;
char color;
struct tree *left;
struct tree *right;
};
My question is : How should I call this function ?
Example : I have a tree and I want to right rotate son, since the first argument is a pointer to pointer to node and the second a pointer to node how should I write the call?
//...some code...
//I have two pointers to nodes : parent and son
rightRotate ( ??? , son)// I didn't get the first argument, what I should write?
//some code...
P.S. : This code is from an other post, sorry for this little "spam" but I'm very confused about this simple function and why it works in this way. Can someone explain me a little more?
I am trying to construct a BST given a string. It is assumed that my strlen will always be in the power of 2 so that I can have a structure with the ends always leveled, like so:
I am having trouble starting this function. I've written a helper that willd construct a tree up to the final points here:
tree* build(int height)
{
int i;
tree *t = malloc(sizeof(tree));
t.tag = NODE;
t.u = node;
t.u.node->left = build(height - 1);
t.u.node->right = build(height - 1);
if(height == 1)
{
return t;
}
}
I would like to reach the end of each node and append the first two chars and so forth throughout the rest of the tree. I am lost, though.
Here are the structs:
typedef struct tagged_tree tree;
struct node {
tree *left, *right;
};
union tree_union {
struct node node;
char leaf;
};
enum tree_tag {
NODE, LEAF
};
struct tagged_tree {
enum tree_tag tag;
union tree_union u;
};
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.