This section provides an alternate way to implement trees in C. As described
above, the purpose of showing this implementation is because it involves using
arrays, which are linear, meaning all the data is in a line, to implement trees,
where data is stored hierarchically.

As you can see, we will be considering only a binary tree for this example,
but the same technique could be used for a tree where all nodes had 3 children,
4 children, etc. There are a few inherent limitations to this method. The
first is that because it uses a static array, the fixed size of the array
means that there is a fixed maximum size for the tree. In general, this method
requires deciding the maximum depth of the tree beforehand. The next step is
to figure out how many nodes a complete tree of that size would require.
Consider first the case of a binary tree. There is one node of depth 0.
That one node has two children which are at depth 1. Each of those two have
two children which are at depth 2. The following table shows the progression.

DepthNumber of Nodes

0

1

1

2

2

4

3

8

etc.
We can see that the number of nodes doubles with each deeper level. In
general, at depth n, there will be 2^{n} nodes. The total number of nodes
in a tree of depth n is 2^{(}n + 1) - 1. This general sum makes sense
because the number of nodes at depth n is one more than the total of all
of the previous nodes.

Once you have determined the maximum number of nodes that there can be, you
then need to make a type which holds an array that contains that many
cells. Assume that each element in the tree is of the type data_t.

typedef data_t[MAX_NODES] tree_t;

In this example, we have stored the maximum number of nodes in a sharp
defined constant. Note that this means that we need to know this number
when we compile the program, as opposed to being able to calculate it
at run time. If MAX_NODES can only be determined at run time, then you must
allocate memory dynamically.

Now we need to figure out how we are actually going to use this array for
our tree. To start with, the root of the tree is always in the zero cell.

/* We want to store the data from the left and the right children of node n
* into the appropriate variables.
*/
data_t left_child, right_child;
left_child = tree[2 * n + 1];
right_child = tree[2 * n + 2];
/* Realize that we have only copied the data value, but if we modify left
* child * or right_child, we do not change the values in the tree. To do
* that, we would * need to make left_child and right_child pointers to those
* locations in the tree
*/

An inherent limitation to the array method is that cells will exist for
nodes even when there is no data at those locations. For this reason
you need to put some value in empty locations to indicate that they hold
no data. Thus, this implementation of the array method will only work when
the data is such that a sentinel value is available to indicate empty nodes.
For example, if the data elements were positive integers, then a -1 might
indicate empty. This could be done with a sharp define.

#define EMPTY -1

Note that this will only work when the empty value is not a possible data
value, but the data_t can hold it. If the data elements could potentially
be negative integers then -1 would not work.