CS-211 Fall 2015 Lab 9 Trees


This week, we extend last weeks lab, which used a structure to dynamically create a linked list of nodes. This week, we are going to do something very similar, but this time, we will put the nodes into a tree structure rather than a linked list. We have already seen a tree structure in project 2, where we turned a boolean expression into an expression tree. In this lab, we will again use a tree, where every node of the tree may have a left and right sub-tree. We keep track of the entire tree by keeping a pointer to the root of the tree (just like we kept track of linked lists by keeping a pointer to the head of the list.) As in linked lists, we can use dynamic allocation (malloc) to create a new instance of a tree node, and that node can be inserted anywhere in the tree by manipulating the "left" and "right" pointers in the tree.

For this lab, we will be creating an ordered binary tree. The payload part of each node in that tree, like last week, will consist of two integers - the first is the "value" of the node, just some arbitrary number; and the second is a "count", which counts the number of occurences of the value.

We are also going to impose a new rule on our tree... namely that the values in all nodes in the left sub-tree of a node will be less than the value in that node, and the values in all the node in the right sub-tree of a node will be greater than the value in that node.

Our tree list will be created from an arbitrary, unsorted list of integers read in from standard input.

After we have created our tree, we will print out the values in the tree in numericcal order, along with the counts.

Getting Started

Download the code that has been started for you in lab9.tar.gz. Use the command tar -xvzf lab9.tar.gz. This will unpack the tar file and make a new lab9 subdirectory. The lab9 directory will have a Makefile, and the C code to start from in file tree.c

The tree.c File

The tree.c file starts of with the standard includes for standard library functions, a definition of the tnode structure, a typedef for a tree data type, and prototypes for the eight lower level functions in the file.

What follows is just the normal function definitions that we are used to seeing. I've included a description of each of these functions below.

Using The Makefile

The Makefile file in the lab9 directory contains "targets" which allow you to do several things using the make command. The following targets are supported:

Printing an Ordered Tree in Order

If you haven't realized it yet, it turns out that tree data structures are very easy to handle if you think about them recursively. In other words, if you are given the root node of the tree, and can figure out how to invode your function on the left and right sub-trees, and also how to deal with the root node of the tree, you are all set.

First, let's handle the special case... where the pointer to the root node is a NULL pointer. In that case, the tree is empty, and we don't want to print anything. So, to handle this special case, if the root is NULL, just return. (We don't have to return a value because the return type of this function is "void".

If the root node is not NULL, we know it is the root of an ordered tree, and we want to print that tree in order. Since every value in the left sub-tree of the root node is less than the value of the root, why not just invoke the printTree function recursively on the left sub-tree? Even if the left sub-tree is empty, we've already handled empty trees in our printTree function, so we can invoke printTree on the left sub-tree no matter what its value is.

Once we have printed out everything in the left sub-tree, then we can print out the value at the root node... we know that the root node is the next highest value after the left sub-tree. We can use the printNode function that has been defined for us to print out the value of the root onode.

After printing out the root node, we know that every value in the right sub-tree of the root is greater than the value of the root, so we can invoke printTree recursively on the right sub-tree to print out any remaining values. If the right sub-tree is NULL, no problem... we've already coed printTree to handle that case.

After printing out the left sub-tree, the root node, and the right sub-tree, that's everything in the tree, so we are done.

Checking for Memory Leaks

After you have written and tested your implentation of the printTree function, you can double check to see if the professor messed up the tree command by introducing memory leaks. To do this, we will use the valgrind command.

To run valgrind, execute the following command:
  valgrind --leak-check=full ./tree <input.txt

If the professor implemented insertTree correctly, you should get no memory leaks, and see the message at the end of the valgrind invocation that includes:

 All heap blocks were freed -- no leaks are possible

Lab Report

Download and edit the following file: lab9_report.txt. Then submit your editted file on Blackboard in the Lab_09 report area.