I've made an AVL Tree for strings, and the tree itself works well: Insertion, Deletion, Search are all working well. However, valgrind is giving me an error. Valgrind says the error is in my stringDuplicate function (I have made a comment on the specific line number where valgrind points it out) and it is when this stringDuplicate function is called by my treeInsert function (I have made a comment where treeInsert calls stringDuplicate). Can someone help me find my valgrind error?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include "tree.h"
//NODES OF TREE
struct node{
char *word;
int balance;
struct node *children[2];
};
//STRUCT TREE WHICH CONTAINS A POINTER TO THE ROOT AND NUMBER OF ELEMENTS
struct tree{
struct node *root;
size_t numElements;
};
//MALLOC SPACE FOR TREE
struct tree *treeCreate(void){
struct tree *s = malloc(sizeof(struct tree));
s->root = NULL;
s->numElements = 0;
return s;
}
//CREATE A DUPLICATE OF THE STRINGS TO BE INSERTED/DELETED
char *stringDuplicate (const char *s) {
char *d = malloc (strlen (s) + 1); //VALGRIND POINTS TO THIS LINE FOR ERROR
if (d == NULL) return NULL;
strcpy (d,s);
return d;
}
//RETURN THE SIZE OF THE TREE
size_t treeSize(const struct tree *s){
return s->numElements;
}
//CREATE A NEW NODE OF THE TREE
struct node *make_node(char *word){
struct node *temp = malloc(sizeof(struct node));
if(temp != NULL){
temp->word = word;
temp->children[0] = temp->children[1] = NULL;
temp->balance = 0;
}
return temp;
}
//CHANGE THE BALANCE OF NODE/NODES IN THE TREE
void adjustBalance(struct node *root, int direction, int temp_bal){
struct node *temp1 = root->children[direction];
struct node *temp2 = temp1->children[!direction];
if(temp2->balance == 0){
root->balance = temp1->balance = 0;
}else if(temp2->balance == temp_bal){
root->balance = -temp_bal;
temp1->balance = 0;
}else{
root->balance = 0;
temp1->balance = temp_bal;
}
temp2->balance = 0;
}
//SINGLE ROTATION OF TREE
struct node *singleRotation(struct node *root, int direction){
struct node *temp = root->children[!direction];
root->children[!direction] = temp->children[direction];
temp->children[direction] = root;
return temp;
}
//DOUBLE ROTATION OF TREE
struct node *doubleRotation(struct node *root, int direction){
struct node *temp = root->children[!direction]->children[direction];
root->children[!direction]->children[direction] = temp->children[!direction];
temp->children[!direction] = root->children[!direction];
root->children[!direction] = temp;
temp = root->children[!direction];
root->children[!direction] = temp->children[direction];
temp->children[direction] = root;
return temp;
}
//CHANGE THE BALANCE OF NODES WHEN INSERTING
struct node *insertBalance(struct node *root, int direction){
struct node *temp = root->children[direction];
int temp_bal;
if(direction == 0){
temp_bal = -1;
}else{
temp_bal = 1;
}
if(temp->balance == temp_bal){
root->balance = temp->balance = 0;
root = singleRotation(root, !direction);
}else{
adjustBalance(root, direction, temp_bal);
root = doubleRotation(root, !direction);
}
return root;
}
//INSERT INTO TREE RECURSIVELY
struct node *insertRecursive(struct node *root, char *word, int *flag){
if(root == NULL){
root = make_node(word);
}
else{
//IF word < root->word, WE NEED TO GO LEFT AND direction < 0
//IF word > root->word, WE NEED TO GO RIGHT AND direction > 0
int direction = strcmp(word, root->word);
if(direction > 0){
direction = 1;
}else if(direction < 0){
direction = 0;
}
root->children[direction] = insertRecursive(root->children[direction], word, flag);
if(!*flag){
if(direction == 0){
root->balance += -1;
}else{
root->balance += 1;
}
if(root->balance == 0){
*flag = 1;
}else if(abs(root->balance) > 1){
root = insertBalance(root, direction);
*flag = 1;
}
}
}
return root;
}
//SEARCH FOR A STRING IN TREE: 1 IF IN TREE, 0 IF NOT
int searchTree(struct node *root, char *word){
int flag = 0;
struct node *current = root;
while(!flag){
if(current){
int direction = strcmp(word, current->word);
if(direction == 0){
flag = 1;
break;
}else if(direction > 0){
direction = 1;
}else{
direction = 0;
}
current = current->children[direction];
}else{
break;
}
}
return flag;
}
//INSERT NEW ELEMENT INTO TREE
void treeInsert(struct tree *tree, const char *word){
char *newWord = stringDuplicate(word);
int flag = searchTree(tree->root, newWord);
int temp = 0;
if(flag == 0){
tree->root = insertRecursive(tree->root, newWord, &temp);
tree->numElements = tree->numElements + 1;
}
}
//CHANGE THE BALANCE OF NODES WHEN DELETING FROM TREE
struct node *deleteBalance(struct node *root, int direction, int *flag){
struct node *temp = root->children[!direction];
int temp_bal;
if(direction == 0){
temp_bal = -1;
}else{
temp_bal = 1;
}
if(temp->balance == -temp_bal){
root->balance = temp->balance = 0;
root = singleRotation(root, direction);
}else if(temp->balance == temp_bal){
adjustBalance(root, !direction, -temp_bal);
root = doubleRotation(root, direction);
}else{
root->balance = -temp_bal;
temp->balance = temp_bal;
root = singleRotation(root, direction);
*flag = 1;
}
return root;
}
//DELETE A STRING FROM TREE ITERATIVELY
void treeDelete(struct tree *tree, const char *word){
if(tree->root != NULL){
char *newWord = stringDuplicate(word);
struct node *iterator, *ancestor_array[32];
int ancestor_direction[32];
int current_index = 0;
int flag = 0;
iterator = tree->root;
for(;;){
if(iterator == NULL){
return;
}else if(strcmp(newWord, iterator->word) == 0){
tree->numElements = tree->numElements - 1;
break;
}
int direction = strcmp(word, iterator->word);
if(direction > 0){
direction = 1;
}else if(direction < 0){
direction = 0;
}
ancestor_direction[current_index] = direction;
ancestor_array[current_index++] = iterator;
iterator = iterator->children[ancestor_direction[current_index - 1]];
}
if(iterator->children[0] == NULL || iterator->children[1] == NULL){
int dir = iterator->children[0] == NULL;
if(current_index != 0){
ancestor_array[current_index - 1]->children[ancestor_direction[current_index - 1]] = iterator->children[dir];
}else{
tree->root = iterator->children[dir];
}
free(iterator);
}else{
struct node *heir = iterator->children[1];
ancestor_direction[current_index] = 1;
ancestor_array[current_index++] = iterator;
while(heir->children[0] != NULL){
ancestor_direction[current_index] = 0;
ancestor_array[current_index++] = heir;
heir = heir->children[0];
}
iterator->word = heir->word;
ancestor_array[current_index - 1]->children[ancestor_array[current_index - 1] == iterator] = heir->children[1];
free(heir);
}
while(--current_index >= 0 && !flag){
ancestor_array[current_index]->balance += ancestor_direction[current_index] != 0 ? -1 : 1;
if(abs(ancestor_array[current_index]->balance) == 1){
break;
}else if(abs(ancestor_array[current_index]->balance) > 1){
ancestor_array[current_index] = deleteBalance(ancestor_array[current_index], ancestor_direction[current_index], &flag);
if(current_index != 0){
ancestor_array[current_index - 1]->children[ancestor_direction[current_index - 1]] = ancestor_array[current_index];
}else{
tree->root = ancestor_array[0];
}
}
}
}
return;
}
//FREE TREE
void treeDestroyHelper(struct node *root){
if(root == NULL){
return;
}
if(root->children[0] == NULL && root->children[1] == NULL){
free(root->word);
free(root);
}else if(root->children[0] == NULL && root->children[1] != NULL){
treeDestroyHelper(root->children[1]);
free(root->word);
free(root);
}else if(root->children[0] != NULL && root->children[1] == NULL){
treeDestroyHelper(root->children[0]);
free(root->word);
free(root);
}else{
treeDestroyHelper(root->children[0]);
treeDestroyHelper(root->children[1]);
free(root->word);
free(root);
}
}
//FREE TREE
void treeDestroy(struct tree *s){
treeDestroyHelper(s->root);
free(s);
}
edit: Just wanted to add the comment in case anyone was wondering that tree.h is simply the function headers I am using.
You duplicate the word in treeDelete() and forget to free it. Duplicating is unnecessary there. valgrind complains that memory allocated by stringDuplicate() is not freed.
Incidentally, this function name is confusing, you should use treeDeleteString. Same for treeInsert -> treeInsertString, and some other ones.
Edit: you also forget to free the string in treeDelete() before free(iterator); and free(heir);. I cannot tell if the logic in treeDelete() is correct from a quick analysis of your code, but these missing free() are definitely causing memory to be lost and reported as such by valgrind.
Related
I got problem with Singly Linked List problem.
When i inserted something in front of head. head is always have 0 of data.
I think init_list() function is something wrong. I think head of 0 is from randomly initialized data.
anything is fine without head 0 problem.
I'm sure that initializing method is wrong. But I don't know how to solve it..
Here is my I/0 and Desired Output
Input
2
insert 0 1
size
Output I got
1->0->NULL
2
1->0->NULL
Desired Output
1->NULL
1
1->NULL
Here is My Code
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef int Element;
typedef struct LinkedNode {
Element data;
struct LinkedNode* link;
} Node;
Node* head;
void init_list() {
head = (Node*)malloc(sizeof(Node));
head->link = NULL;
}
int is_empty() {
if (head == NULL) return 1;
else return 0;
}
Node* get_entry(int pos)
{
Node* p = head;
int i;
for (i = 0; i < pos; i++, p=p->link){
if (p == NULL) return NULL;
}
return p;
}
int size()
{
Node* p;
int count = 0;
for (p = head; p != NULL; p = p->link)
count++;
return count;
}
void replace(int pos, Element val)
{
Node* node = get_entry(pos);
if (node != NULL)
node->data = val; // replace
}
Node* search_list(Element val)
{
Node* p;
for (p = head; p != NULL; p = p->link)
if (p->data == val) return p;
return NULL;
}
void insert_next(Node * before, Node * node)
{
if (node != NULL) {
node->link = before->link;
before->link = node;
}
}
void insert(int pos, Element val)
{
Node* new_node, * prev;
new_node = (Node*)malloc(sizeof(Node));
new_node->data = val;
if (pos == 0) {
new_node->link = head;
head = new_node;
}
else {
prev = get_entry(pos-1);
if (prev != NULL)
insert_next(prev, new_node);
else free(new_node);
}
}
Node * remove_next(Node * prev)
{
Node* removed = prev->link;
if (removed != NULL) {
prev->link = removed->link;
}
return removed;
}
void delete(int pos)
{
Node* prev, * removed;
if (pos == 0 && is_empty() == 0) {
removed = get_entry(pos);
head = head->link;
free(removed);
}
else {
prev = get_entry(pos-1);
if (prev != NULL) {
remove_next(prev);
free(removed);
}
}
}
void clear_list()
{
while (is_empty() == 0)
delete(0);
}
void print_list()
{
Node* p;
for (p = head; p != NULL; p = p->link)
printf("%d->", p->data);
printf("NULL\n");
}
Node * concat_list(Node * new_node)
{
if(is_empty()) return new_node;
else if(new_node == NULL) return new_node;
else{
Node* p;
p = head;
while (p->link != NULL) {
p = p->link;
}
p->link = new_node;
return head;
}
}
int main(void)
{
Element num;
int pos;
int n, i, j, len;
char c[15];
Node* tmp_head= NULL;
Node* new_head= NULL;
init_list();
scanf("%d", &n);
for (i = 0; i < n; i++)
{
scanf("%s", c);
if (strcmp(c, "insert") == 0) { scanf("%d %d\n",&pos, &num); insert(pos,num); print_list();}
else if (strcmp(c, "delete") == 0) { scanf("%d\n", &pos); delete(pos); print_list();}
else if (strcmp(c, "size") == 0) {printf("%d\n", size()); print_list();}
else if (strcmp(c, "empty") == 0) {printf("%d\n", is_empty()); print_list();}
else if (strcmp(c, "getEntry") == 0) { scanf("%d\n", &pos); printf("%d\n", get_entry(pos)->data); print_list();}
else if (strcmp(c, "search_list") == 0) { scanf("%d\n", &num); printf("%d\n", search_list(num)->data); print_list();}
else if (strcmp(c, "replace") == 0) { scanf("%d %d\n", &pos, &num); replace(pos,num); print_list();}
else if (strcmp(c, "concat_list") == 0) {
tmp_head = head;
init_list();
scanf("%d", &len);
for (j = 0; j < len; j++)
{
scanf("%d %d\n",&pos, &num); insert(pos,num);
}
printf("new_node: ");
print_list();
new_head = head;
head = tmp_head;
head = concat_list(new_head);
print_list();
}
else printf("error\n");
}
return 0;
}
The basic problem is that within init_list, the code only initializes link but not data. I'd suggest instead that you initialize head to NULL and simply use insert to create nodes.
Creating a dictionary comparison program utilizing avl_tree, but getting a segfault when reading in a large file 200,000+ unique words. Smaller files seem to work fine.
A couple of my thoughts might be my word_compre function which may interfere with the rotation. Or likely I have implemented the rotation incorrectly.
// String compare based on alphabetical order
int word_compare(char *word, struct tree_node *root)
{
return strcasecmp(word, root->word);
}
// Get the maximum of two integers
int get_max(int int_a, int int_b)
{
if (int_a > int_b)
return int_a;
else
return int_b;
}
// Get the height of the tree
int get_height(struct tree_node *root)
{
if (root == NULL)
return 0;
else
return root->height;
}
// Determine if the tree or subtree is unbalanced by comparing the max height
// of the left and right branches
int get_balance(struct tree_node *root)
{
if (root == NULL)
return 0;
else
return get_height(root->left) - get_height(root->right);
}
// Rotate left subtree rooted with right child node
struct tree_node *left_rotate(struct tree_node* root)
{
// Store the right child node to rotate
struct tree_node *right_child = root->right;
// Store the left of the right child node to rotate
struct tree_node *subtree = right_child->left;
// Perform rotation
right_child->left = root;
root->right = subtree;
// Update heights
root->height = get_max(get_height(root->left),
get_height(root->right)) + 1;
right_child->height = get_max(get_height(right_child->left),
get_height(right_child->right)) + 1;
return right_child;
}
// Rotate right subtree rooted with left child node
struct tree_node *right_rotate(struct tree_node *root)
{
// Store the left child node to rotate
struct tree_node *left_child = root->left;
// Store the right of the left child node to rotate
struct tree_node *subtree = left_child->right;
// Perform rotation
left_child->right = root;
root->left = subtree;
// Update heights
root->height = get_max(get_height(root->left),
get_height(root->right)) + 1;
left_child->height = get_max(get_height(left_child->left),
get_height(left_child->right)) + 1;
return left_child;
}
// Insert new node into a tree
struct tree_node *insert_node(struct tree_node *root, char *word, int fp_num)
{
// Viable spot found, insert a new node
if (root == NULL) {
#ifdef DEBUG
printf("INSERTED NODE\n");
printf("WORD: %s\n", word);
#endif
if (fp_num == 1) {
// Allocate a new node
root = (struct tree_node *)malloc(sizeof(struct tree_node));
// Fail to allocate a new node
if (root == NULL) {
printf("\nFailed to allocate a node\n");
return NULL;
}
// Initialize the new node
else {
root->word = strdup(word);
root->count = 1;
root->left = NULL;
root->right = NULL;
root->height = 1;
return root;
}
}
else {
return root;
}
}
int exist = word_compare(word, root);
if (exist < 0) {
root->left = insert_node(root->left, word, fp_num);
}
else if (exist > 0) {
root->right = insert_node(root->right, word, fp_num);
}
else {
if (fp_num != 1 && root->count == fp_num - 1) {
root->count = fp_num;
}
}
// Check the balance of the tree
int balance = get_balance(root);
// If the tree is imbalanced, fixed them with one of the following cases
// Left-Left-Case
if (balance > 1 && (word_compare(word, root->left) < 0))
return right_rotate(root);
// Right-Right-Case
if (balance < -1 && (word_compare(word, root->right) > 0))
return left_rotate(root);
// Left-Right-Case
if (balance > 1 && (word_compare(word, root->left) > 0)) {
root->left = left_rotate(root->left);
return right_rotate(root);
}
// Right-Left-Case
if (balance < -1 && (word_compare(word, root->right) < 0)) {
root->right = right_rotate(root->right);
return left_rotate(root);
}
return root;
}
// Perform in-order traversal sort of the tree and display results
void in_order(struct tree_node *root, int fp_num)
{
if (root == NULL)
return;
// Recur until the left most node
if (root->left)
in_order(root->left, fp_num);
// Find the amount of dollars from the cents and puts the
// remainder after a decimal point
if (fp_num != 1 && root->count == fp_num)
printf("%s\n", root->word);
// Recur until the right most node
if (root->right)
in_order(root->right, fp_num);
}
// Delete tree
void free_tree(struct tree_node *root)
{
if (root != NULL)
{
free_tree(root->left);
free(root->word);
free_tree(root->right);
free(root);
}
}
Fixed it. Did not update current node/root height in the insertion function.
// Insert new node into a tree
struct tree_node *insert_node(struct tree_node *root, char *word, int fp_num)
{
// Viable spot found, insert a new node
if (root == NULL) {
#ifdef DEBUG
printf("INSERTED NODE\n");
printf("WORD: %s\n", word);
#endif
if (fp_num == 1) {
// Allocate a new node
root = (struct tree_node *)malloc(sizeof(struct tree_node));
// Fail to allocate a new node
if (root == NULL) {
printf("\nFailed to allocate a node\n");
return NULL;
}
// Initialize the new node
else {
root->word = strdup(word);
root->count = 1;
root->left = NULL;
root->right = NULL;
root->height = 1;
return root;
}
}
else {
return root;
}
}
int word_exist = word_compare(word, root);
if (word_exist < 0) {
root->left = insert_node(root->left, word, fp_num);
}
else if (word_exist > 0) {
root->right = insert_node(root->right, word, fp_num);
}
else {
if (fp_num != 1 && root->count == fp_num - 1) {
root->count = fp_num;
}
}
// Update height of current node
root->height = 1 + get_max(get_height(root->left), get_height(root->right));
// Check the balance of the tree
int balance = get_balance(root);
// If the tree is imbalanced, fixed them with one of the following cases
// Left-Left-Case
if (balance > 1 && (word_compare(word, root->left) < 0))
return right_rotate(root);
// Right-Right-Case
if (balance < -1 && (word_compare(word, root->right) > 0))
return left_rotate(root);
// Left-Right-Case
if (balance > 1 && (word_compare(word, root->left) > 0)) {
root->left = left_rotate(root->left);
return right_rotate(root);
}
// Right-Left-Case
if (balance < -1 && (word_compare(word, root->right) < 0)) {
root->right = right_rotate(root->right);
return left_rotate(root);
}
return root;
}
I tried a basic dequeue program in c using linked implementation. But it shows some error with the function that is used to insert element to the dequeue. Also i want to display the element in the dequeue. Below is the code i tried. The CLI doesn't show any output when running the code. Due to the error in the Insert function i'm not sure whether the delete functions are also correct or incorrect.
#include<stdio.h>
#include<stdlib.h>
typedef int DeQueueElement;
typedef enum{FALSE,TRUE} Boolean;
typedef struct node{
DeQueueElement entry;
struct node *next, *prev;
}Node;
typedef struct dequeue{
int count;
Boolean full;
Node *front;
Node *rear;
}DeQueue;
void CreateDeQueue(DeQueue *dq){
dq->count = 0;
dq->full = FALSE;
dq->front = dq->rear = -1;
}
Boolean IsEmpty(DeQueue *dq){
return (dq->front == NULL && dq->rear == NULL);
}
Boolean IsFull(DeQueue *dq){
return(dq->full);
}
void InsertRear(DeQueueElement x, DeQueue *dq){
Node *np;
np = (Node* )malloc(sizeof(Node));
if(np == NULL){
printf("Not enough space\n");
}
else{
if(dq->rear == NULL)
dq->front = dq->rear = np;
else{
np->prev = dq->rear;
dq->rear->next = np;
dq->rear = NULL;
np->next = np;
np->entry = x;
}
}
}
void InsertFront(DeQueueElement x, DeQueue *dq){
Node *np;
np = (Node* )malloc(sizeof(Node));
if(np == NULL)
printf("Not enough space\n");
else{
if(dq->front == NULL)
dq->rear = dq->front = np;
else{
np->next = dq->front;
dq->front->prev = np;
dq->front = np;
np->prev = NULL;
np->entry = x;
}
}
}
void DeleteFront(DeQueue *dq){
if(dq->front == NULL)
printf("Underflow\n");
else{
Node *temp;
temp = dq->front;
dq->front = dq->front->next;
if(dq->front == NULL)
dq->rear = NULL;
else
dq->front->prev = NULL;
free(temp);
}
}
void DeleteRear(DeQueue *dq){
if(dq->front == NULL)
printf("Underflow\n");
else{
Node *temp;
temp = dq->rear;
dq->rear = dq->rear->prev;
if(dq->rear == NULL)
dq->front == NULL;
else
dq->rear->next = NULL;
free(temp);
}
}
void display(DeQueue *dq) {
Node *temp;
if (dq->front->next == dq->rear) {
printf("Queue is empty\n");
return;
}
temp = dq->front->next;
while (temp != dq->rear) {
printf("%d", temp->entry);
temp = temp->next;
}
printf("\n");
}
int main(){
DeQueue dq;
CreateDeQueue(&dq);
InsertFront(21,&dq);
InsertFront(1,&dq);
InsertFront(221,&dq);
InsertRear(23,&dq);
InsertRear(36,&dq);
display(&dq);
}
The code has some errors and I try to correct them and comment where I made the changes.
The problems are in CreateDeQueue, InsertFront, InsertRear and display functions.
void CreateDeQueue(DeQueue *dq){
dq->count = 0;
dq->full = FALSE;
// dq->front = dq->rear = -1;
// Change 0: It should be NULL or 0 not -1
dq->front = NULL;
dq->rear = NULL;
}
void InsertRear(DeQueueElement x, DeQueue *dq){
Node *np;
np = (Node* )malloc(sizeof(Node));
if(np == NULL){
printf("Malloc failed\n");
}
else{
np->entry = x;
np->next = NULL;
np->prev = NULL;
if(dq->rear == NULL)
dq->front = dq->rear = np;
else{
np->prev = dq->rear;
dq->rear->next = np;
//dq->rear = NULL;
//Change 1: Why dq->rear to NULL it should point to valid mem location
dq->rear = np;
}
dq->count++;
}
}
void InsertFront(DeQueueElement x, DeQueue *dq){
Node *np;
np = (Node* )malloc(sizeof(Node));
if(np == NULL)
printf("Malloc failed. \n");
else{
//Change 3: Initialize the newly created struct Node, np
np->entry = x;
np->next = NULL;
np->prev = NULL;
if(dq->front == NULL)
dq->rear = dq->front = np;
else{
np->next = dq->front;
dq->front->prev = np;
dq->front = np;
}
dq->count++;
}
}
void display(DeQueue *dq) {
Node *temp;
if (dq->front->next == dq->rear) {
printf("Queue is empty\n");
return;
}
temp = dq->front;
// Change 4: Checking temp against dq->rear is not logical i guess
// temp should not be NULL. Printing from the front
while (temp!=dq->rear->next) {
printf("%d ", temp->entry);
printf("\n");
temp = temp->next;
}
}
I have a question about my Code. "delete_single_node" does not work as it should. My procedure (to delete a node) is to find the node in the "head" tree, save the child nodes temporary, delete the node and all child nodes (in "head" tree) and merge the "head" tree with the temporary saved child nodes to a new correct binary tree.
I would like to stay with this procedure but I can't find my mistake.
#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
struct tnode {
int content;
struct tnode *left;
struct tnode *right;
};
struct tnode* head;
void *malloc(size_t size);
struct tnode *talloc(void)
{
return(struct tnode*)malloc(sizeof(struct tnode));
}
/* delete a node with all child nodes*/
int deletenode(struct tnode *p)
{
if (p == NULL) return 0;
else
{
deletenode(p->left);
deletenode(p->right);
p->left = NULL;
p->right = NULL;
free(p);
return 0;
}
}
/* insert new node*/
struct tnode *addelement(struct tnode *p, int i) {
int cond;
if (p == NULL) {
p = talloc();
p->content = i;
p->left = p->right = NULL;
}
else if (p->content == i) {
return p;
}
else if (i < p->content)
p->left = addelement(p->left, i);
else
p->right = addelement(p->right, i);
return p;
}
/*merges two binary trees into one*/
struct tnode *addtree(struct tnode *top, struct tnode *p) {
if (p == NULL)
return top;
else
return addtree(addtree(addelement(top, p->content), p->right), p->left);
}
/*prints out tree*/
void showtree(struct tnode* nd)
{
if (nd == NULL)
return;
printf("ZZ %d", nd->content);
if (nd->left != NULL)
{
printf("left:%d", nd->left->content);
}
if (nd->right != NULL)
{
printf("right:%d\n", nd->right->content);
}
printf("\n");
showtree(nd->left);
showtree(nd->right);
}
/*removes connection to a node*/
void removeconnection(struct tnode *head, struct tnode *p) {
if (p->content > head->content) {
if (head->right == p)
{
head->right = NULL;
}
else
{
removeconnection(head->right, p);
}
}
if (p->content < head->content) {
if (head->left == p)
{
head->left = NULL;
}
else
{
removeconnection(head->left, p);
}
}
}
/*delete single node*/
struct tnode *delete_single_node(struct tnode *p, int content) {
struct tnode* temp2 = NULL;
struct tnode temp1;
struct tnode* temp4 = NULL;
struct tnode temp3;
if (p == NULL)
return NULL;
if (content > p->content)
{
p->right = delete_single_node(p->right, content);
}
else if (content < p->content)
{
p->left = delete_single_node(p->left, content);
}
else if (content == p->content)
{
if (p->left == NULL && p->right != NULL)
{
temp1.content = p->right->content;
temp1.right = p->right->right;
temp1.left = p->right->left;
temp2 = &temp1;
removeconnection(head, p);
deletenode(p);
head = addtree(head, temp2);
showtree(head);
}
else if (p->right == NULL && p->left != NULL)
{
temp1.content = p->left->content;
temp1.right = p->left->right;
temp1.left = p->left->left;
temp2 = &temp1;
removeconnection(head, p);
deletenode(p);
head = addtree(head, temp2);
showtree(head);
}
else if (p->right == NULL && p->left == NULL)
{
removeconnection(head, p);
deletenode(p);
showtree(head);
}
else
{
temp1.content = p->left->content;
temp1.right = p->left->right;
temp1.left = p->left->left;
temp2 = &temp1;
temp3.content = p->right->content;
temp3.right = p->right->right;
temp3.left = p->right->left;
temp4 = &temp3;
removeconnection(head, p);
deletenode(p);
head = addtree(head, temp2);
head = addtree(head, temp4);
showtree(head);
}
}
}
int main()
{
struct tnode* start = NULL;
int temp_int;
start = addelement(start, 5);
start = addelement(start, 6);
start = addelement(start, 2);
start = addelement(start, 9);
start = addelement(start, 3);
start = addelement(start, 2);
start = addelement(start, 1);
start = addelement(start, 7);
start = addelement(start, 8);
showtree(start);
printf("Which node to delete?\n");
scanf_s("%d", &temp_int);
head = start;
delete_single_node(start, temp_int);
return 0;
}
I seem to be get a strange segmentation fault when I am attempting to delete in my implementation of an AVL Tree holding strings. The problem comes in the fact that I seem to only get segmentation fault when I am deleting a leaf node. Here is the code for deletion, is there anywhere that could create a problem? According to GDB the error is the function deleteBalance.
struct node{
char *word;
int balance;
struct node *children[2];
};
struct tree{
struct node *root;
int numElements;
};
struct tree *treeCreate(void){
struct tree *s = malloc(sizeof(struct tree));
s->root = NULL;
s->numElements = 0;
return s;
}
char *stringDuplicate (const char *s) {
char *d = malloc (strlen (s) + 1);
if (d == NULL) return NULL;
strcpy (d,s);
return d;
}
size_t treeSize(const struct tree *s){
return s->numElements;
}
struct node *make_node(char *word){
struct node *temp = malloc(sizeof(*temp));
if(temp != NULL){
temp->word = word;
temp->children[0] = temp->children[1] = NULL;
temp->balance = 0;
}
return temp;
}
void adjustBalance(struct node *root, int direction, int temp_bal){
struct node *temp1 = root->children[direction];
struct node *temp2 = temp1->children[!direction];
if(temp2->balance == 0){
root->balance = temp1->balance = 0;
}else if(temp2->balance == temp_bal){
root->balance = -temp_bal;
temp1->balance = 0;
}else{
root->balance = 0;
temp1->balance = temp_bal;
}
temp2->balance = 0;
}
struct node *singleRotation(struct node *root, int direction){
struct node *temp = root->children[!direction];
root->children[!direction] = temp->children[direction];
temp->children[direction] = root;
return temp;
}
struct node *doubleRotation(struct node *root, int direction){
struct node *temp = root->children[!direction]->children[direction];
root->children[!direction]->children[direction] = temp->children[!direction];
temp->children[!direction] = root->children[!direction];
root->children[!direction] = temp;
temp = root->children[!direction];
root->children[!direction] = temp->children[direction];
temp->children[direction] = root;
return temp;
}
struct node *insertBalance(struct node *root, int direction){
struct node *temp = root->children[direction];
int temp_bal;
if(direction == 0){
temp_bal = -1;
}else{
temp_bal = 1;
}
if(temp->balance == temp_bal){
root->balance = temp->balance = 0;
root = singleRotation(root, !direction);
}else{
adjustBalance(root, direction, temp_bal);
root = doubleRotation(root, !direction);
}
return root;
}
struct node *insertRecursive(struct node *root, char *word, int *done){
if(root == NULL){
root = make_node(word);
}
else{
int direction = strcmp(word, root->word);
if(direction > 0){
direction = 1;
}else if(direction < 0){
direction = 0;
}
root->children[direction] = insertRecursive(root->children[direction], word, done);
if(!*done){
if(direction == 0){
root->balance += -1;
}else{
root->balance += 1;
}
if(root->balance == 0){
*done = 1;
}else if(abs(root->balance) > 1){
root = insertBalance(root, direction);
*done = 1;
}
}
}
return root;
}
void treeInsert(struct tree *tree, const char *word){
int done = 0;
char *newWord = stringDuplicate(word);
tree->root = insertRecursive(tree->root, newWord, &done);
}
struct node *deleteBalance(struct node *root, int direction, int *done){
struct node *temp = root->children[!direction];
int temp_bal;
if(direction == 0){
temp_bal = -1;
}else{
temp_bal = 1;
}
if(temp->balance == -temp_bal){ //ERROR OCCURRING HERE
root->balance = temp->balance = 0;
root = singleRotation(root, direction);
}else if(temp->balance == temp_bal){
adjustBalance(root, !direction, -temp_bal);
root = doubleRotation(root, direction);
}else{
root->balance = -temp_bal;
temp->balance = temp_bal;
root = singleRotation(root, direction);
*done = 1;
}
return root;
}
struct node *deleteRecursion(struct node *root, char *word, int *done){
if(root != NULL){
int direction;
if(strcmp(word, root->word) == 0){
if(root->children[0] == NULL || root->children[1] == NULL){
struct node *temp;
if(root->children[0] == NULL){
direction = 1;
}else{
direction = 0;
}
temp = root->children[direction];
free(root);
return temp;
}
else{
struct node *heir = root->children[0];
while(heir->children[1] != NULL){
heir = heir->children[1];
}
root->word = heir->word;
word = heir->word;
}
}
direction = strcmp(word, root->word);
if(direction > 0){
direction = 1;
}else if(direction < 0){
direction = 0;
}
root->children[direction] = deleteRecursion(root->children[direction], word, done);
if(!*done){
if(direction == 0){
root->balance += -1;
}else{
root->balance += 1;
}
if(abs(root->balance) == 1){
*done = 1;
}else if(abs(root->balance) > 1){
root = deleteBalance(root, direction, done);
}
}
}
return root;
}
void treeDelete(struct tree *tree, const char *word){
int done = 0;
char *newWord = stringDuplicate(word);
tree->root = deleteRecursion(tree->root, newWord, &done);
}
Edit: I have added all the functions I use, both insert and delete.