Trees Library


Tree Creation and Destruction Functions

One of the most useful features of the tree data structure is that it can grow dynamically. That is, at any point in your code, you can make a new node and add it to the tree. Because of this you do not need to know the number of nodes beforehand. As a result, our function which will provide a new tree structure will need to allocate memory. Recall that we have a tree_t data type, defined as follows:


typedef struct _tree {
	int		data;
	struct _tree	*left, *right;
} tree_t;

From this definition we can see that each node points to its left and right children. To make our node creation function mesh easily with the rest of our implementation, it should return a pointer to the memory we allocate. Here is one possible way to implementation such a function:


tree_t *new_tree(int	data)
{
	tree_t	*tree;

	if ((tree = (tree_t *) malloc (sizeof(tree_t))) == NULL) {
		return NULL;
	}
	tree->data = data;
	tree->left = NULL;
	tree->right = NULL;

	return tree;
}

Alternatively, you could write a version where the caller is allowed to specify the children.


tree_t *new_tree(int	data; tree_t *left; tree_t *right)
{
	tree_t	*tree;

	if ((tree = (tree_t *) malloc (sizeof(tree_t))) == NULL) {
		return NULL;
	}
	tree->data = data;
	tree->left = left;
	tree->right = right;

	return tree;
}

Since each node in the tree will necessarily be allocated dynamically, it must also be freed when it is no longer needed. The following function will take care of the freeing of an individual node.


void 	free_node (tree_t *tree)
{
	if (tree != NULL) {
		free(tree);
	}
}

While it is useful to have a function that destroys an individual node, it would be far more useful if we could make one function call to destroy an entire tree. We mentioned in the introduction that trees are naturally recursive. This function will take advantage of that feature. Destroying a tree essentially requires destroying the tree headed by the left child and the tree headed by the right child along with the root of the tree itself. With that algorithm in mind, we produce the following function:


void	destroy_tree (tree_t *tree)
{
	if (tree == NULL)
		return;

	destroy_tree(tree->left);
	destroy_tree(tree->right);
	free_node(tree);
}

To break down the function above, we see that there is a base case for the NULL tree, a recursive case for other trees, and finally a call to free_node to destroy the tree's root. You will find that this is a pattern that recurs frequently when writing functions to manipulate trees.

There are a few things to now consider. This implementation was based on the data in each node being an integer. It is entirely possible, however, to have each node contain some sort of dynamically allocated data. If you wanted to do this, then the new_tree function would also have to allocate space separately for the additional data. Furthermore, free_node would be need to be modified to free memory allocated to the data elements in addition to that allocated for the tree nodes.

Take a Study Break

SparkLife

Star Trek gets SEXY

Chris Pine and Zoe Saldana heat up the red carpet!

SparkLife

Are you afraid of relationships?

Auntie SparkNotes can help!

SparkLife

Wanna get JLaw's gorgeous glow?

Click here for simple, sexy makeup tricks!

SparkLife

Sexy starlet style

See every single look from the Met Gala!

SparkLife

Who'd be on your zombie-apocalypse crew?

We already dib'sed Genghis Khan.

Geek out!

The MindHut

Geeky Actors: Then and Now

Travel back in time!

The MindHut

Villains We Want These Actresses to Play

From super cute to super bad!

The MindHut

10 Movies Better Than Their Books

What do you think?

The MindHut

How To Look Like J-Law...

When you don't look like J-Law.

The MindHut

12 Scientific Inaccuracies in Into Darkness

What did Star Trek get wrong?

The Book

Cover image

Read What You Love, Anywhere You Like

Get Our FREE NOOK Reading Apps