简体   繁体   中英

Freeing tree that is NOT binary in C

I'm trying to free a tree that is not binary. It includes dozens of leaves and paths. Basicly it's a tree that starts with a root of a chess board position, and includes a lot of other positions. The structs are the following:

typedef char chessPos[2];
typedef struct _treeNodeListCell treeNodeListCell;


typedef struct _treeNode
{
    chessPos position;
    treeNodeListCell* next_possible_positions;
} treeNode;

typedef struct _treeNodeListCell
{
    treeNode* node;
    struct _treeNodeListCell* next;
} treeNodeListCell;

typedef struct _pathTree
{
    treeNode* root;
} pathTree;

Basicly I want to free a whole path tree. For example, the path tree looks the following: 在此处输入图像描述

So the root of path tree is the root with "C3" written in it. (Ignore the parts with the blue "X" on them, it just means that these tree nodes aren't in the tree in my program)

This is the way I was trying to free the tree:

void freePathTree(pathTree* ptr)
{
    freeTreeNode(ptr->root);
    free(ptr);
}

void freeTreeNodeListCell(treeNodeListCell* tmp)
{
    if (tmp->next != NULL)
    {
        freeTreeNodeListCell(tmp->next);
    }
    freeTreeNode(tmp->node);
    free(tmp);
}

void freeTreeNode(treeNode* tmp)
{
    if (tmp->next_possible_positions == NULL)
        free(tmp);
    else
    {
        freeTreeNodeListCell(tmp->next_possible_positions);
    }
}

But as always, when trying to free memory, I receive dozens of warnings.

How can I free this huge tree without getting any errors? What is wrong with my program?

Big thanks in advance!

The existing freeTreeNode function has a memory leak:

void freeTreeNode(treeNode* tmp)
{
    if (tmp->next_possible_positions == NULL)
        free(tmp);
    else
    {
        freeTreeNodeListCell(tmp->next_possible_positions);
        // Memory leak here.  `tmp` has not been freed.
    }
}

Rather than repeating the call free(tmp) , the function can be restructured as follows to be more like freeTreeNodeListCell :

void freeTreeNode(treeNode* tmp)
{
    if (tmp->next_possible_positions != NULL)
    {
        freeTreeNodeListCell(tmp->next_possible_positions);
    }
    free(tmp);
}

The freeTreeNode and freeTreeNodeListCell functions are mutually recursive. freeTreeNode could be changed to an iterative function that subsumes freeTreeNodeListCell by "flattening" the tree into a list of treeNode s and a list of treeNodeListCell s as it goes:

void freeTreeNode(treeNode* node)
{
    treeNodeListCell *cell = NULL;
    treeNodeListCell **endCell = NULL;
    while (node || cell)
    {
        if (!cell)
        {
            endCell = &cell;
        }
        if (node)
        {
            *endCell = node->next_possible_positions;
            while (*endCell)
            {
                endCell = &(*endCell)->next;
            }
            free(node);
            node = NULL;
        }
        while (!node && cell)
        {
            treeNodeListCell *tmp = cell;
            node = cell->node;
            cell = cell->next;
            free(tmp);
        }
    }
}

As a more profound change, the data structure could be simplified by merging treeNodeListCell into treeNode so that there are fewer types to worry about and to reduce the number of memory allocations required to hold the tree:

typedef struct _treeNode
{
    chessPos position;
    struct _treeNode *next_possible_positions;
    struct _treeNode *node;
} treeNode;

That turns it into a sort of binary tree turned on its side, where next_possible_positions points across to the siblings, and node points down to the children.

That would make the freeTreeNode function simpler. Recursive version:

void freeTreeNode(treeNode *node)
{
    if (node)
    {
        freeTreeNode(node->next_possible_positions);
        freeTreeNode(node->node);
        free(node);
    }
}

Iterative version:

void freeTreeNode(treeNode *node)
{
    treeNode **end = &node;
    treeNode *tmp;
    while (*end)
    {
        end = &(*end)->next_possible_positions;
    }
    while (node)
    {
        *end = node->node;
        while (*end)
        {
            end = &(*end)->next_possible_positions;
        }
        tmp = node;
        node = node->next_possible_positions;
        free(tmp);
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM