释放AVL树的Valgrind错误

时间:2015-04-07 03:42:29

标签: c tree valgrind avl-tree

我为字符串创建了一个AVL树,树本身运行良好:插入,删除,搜索都运行良好。但是,valgrind给了我一个错误。 Valgrind说错误发生在我的stringDuplicate函数中(我已经对valgrind指出的特定行号做了评论),而且我的treeInsert函数调用了这个stringDuplicate函数(我在treeInsert调用stringDuplicate时发表了注释) 。有人能帮我找到我的valgrind错误吗?

#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);
}

编辑:只是想添加注释,以防有人想知道tree.h只是我正在使用的函数头。

1 个答案:

答案 0 :(得分:0)

您复制word中的treeDelete()并忘记释放它。那里没有必要复制。 valgrind抱怨stringDuplicate()分配的内存未被释放。

顺便提一下,此功能名称令人困惑,您应该使用treeDeleteStringtreeInsert - &gt;相同treeInsertString,以及其他一些。

修改:您还忘记在treeDelete()free(iterator);之前释放free(heir);中的字符串。我无法判断treeDelete()中的逻辑是否通过对代码的快速分析是正确的,但这些缺失的free()肯定会导致内存丢失并由valgrind报告。