This assignment is designed for you to put into practice the concept of trees and recursion. Your group will design and implement a set of routines to build and manipulate trees. The driver program will be provided to you.
Rather than implementing binary trees where a node can have no more than two children, you will be implementing trees where a node may have any number of children. For example, a hierarchical file system is a tree where each directory can contain any number of files. One organization for storing trees of this type is for each node to have a pointer to the leftmost child and have a pointer to the next sibling. This organization leads to the following C structure definition for a tree node (all node values will be characters). This structure is defined in the file /cs/cs2005/pub/example/proj4tree.h.
struct TreeNodeType { char chNode; /* value of the node */ TreeNodeType *pTreeLeft; /* pointer to leftmost child */ TreeNodeType *pTreeNext; /* pointer to next sibling */ };
The driver program for your program is in the file /cs/cs2005/pub/example/proj4tree.C (note that we will just be using structures and functions, not classes on this assignment). You should copy this file to your group directory and then create other modules containing the code for the tree manipulation routines. You should create a Makefile that ties all the modules together.
The main interface of your program will implement the following tree-based commands:
Commands (shortened versions of command names can be used, node values are characters): addnode x y -- add the node y with parent x to the tree deletenode x -- delete the node x from the tree, x must be a leaf node exist x -- indicate whether the node currently exists in the tree height -- show the height of the tree leaf -- show the number of leaf nodes in the tree menu -- print this menu node -- show the number of nodes in the tree parent x -- show the parent of the node x quit -- quit the program show -- show the contents of the entire tree
It is possible in the Unix environment to pass strings given in the command line to your program. This is a useful way of passing values to your program without recompiling it each time or reading from standard input. In the proj4tree.C file is the following code to use these values for passing a data file name.
main(int argc, char *argv[]) { TreeNodeType *pTreeRoot; /* root of the tree */ /* stuff deleted */ pTreeRoot = NULL; /* initialize the tree */ if (argc >= 2) { if (ReadTree(pTreeRoot, argv[1]) < 0) { cout << "Initialization of the tree from file " << argv[1] << " failed.\n"; exit(1); } }
This code shows that main() has two arguments--an argument count argc, which is an integer and an argument vector argv, which is a NULL-terminated array of strings. These variables are automatically initialized at program execution. For the command line
> proj4tree treedata
the value of argc will be 2 (the command itself counts as an argument), the value of argv[0] will be the string "proj4tree", the value of argv[1] will be the string "treedata" and the value of argv[2] will be NULL. Thus in the program, if a second argument is given, it is assumed to be a data file name that is passed to the ReadTree() routine for initializing the tree. If there is not a second argument then the tree is initially NULL.
Using the command line shown above with the file treedata containing the following values, the tree shown in Figure 1 should be built. Each line is one set of arguments to AddNode(). Figure 1 also shows the node structure for this tree using the TreeNodeType structure. A couple notes:
*
''. The root node must be added first.
* A A B A C A D B E B F C G G H E L
Figure: Sample Tree and Internal Organization
The driver is already written. Your job is to write the following set of routines and link them with the driver. Most of the routines (with the exception of AddNode() and perhaps DeleteNode()) are best written recursively. You may create additional routines if needed. You must use these parameters and return values as they match those in proj4tree.C. You should note that both AddNode() and DeleteNode() require the pointer to the root of the tree to be passed by reference. This is required in case the root of the tree must be changed. See the corresponding call in proj4tree.C. All return errors (such as EEXIST) are defined in proj4tree.h. These routine definitions are in /cs/cs2005/pub/example/proj4treeaux.C.
/* * MakeTreeNode -- make a tree node. Return pointer to node on success and * NULL on failure. */ TreeNodeType *MakeTreeNode(char chNode) /* * FindParentNode -- recursively find the parent of the node with the given * value, return NULL on failure or if the node is the root */ TreeNodeType *FindParentNode(TreeNodeType *pTreeRoot, char chNode) /* * FindNode -- recursively find the node with the given value, return NULL * on failure */ TreeNodeType *FindNode(TreeNodeType *pTreeRoot, char chNode) /* * AddNode -- add the given node as a child of the parent. If the parent is * ROOT then this node is the root of the tree. Return 0 on success, * EEXIST if the node already exists in the tree * EMULTROOT if a root node is being added and one already exists * EPARENT if the parent node does not exist in the tree * ENOMEMORY if no memory exists to create a node */ int AddNode(TreeNodeType * &pTreeRoot, char chParent, char chNode) /* * DeleteNode -- Delete the given node, which must be a leaf. Return 0 on * success, ENOTLEAF if the node exists but is not a leaf and * ENOEXIST if the node does not exist. */ int DeleteNode(TreeNodeType * &pTreeRoot, char chNode) /* * ShowTree -- recursively print the tree with space indentation * corresponding to the level of the node. */ void ShowTree(TreeNodeType *pTreeRoot, int wLevel) /* * ComputeHeight -- recursively compute the height of the tree */ int ComputeHeight(TreeNodeType *pTreeRoot) /* * CountNode -- recursively compute the number of nodes */ int CountNode(TreeNodeType *pTreeRoot) /* * CountLeafNode -- recursively compute the number of leaf nodes */ int CountLeafNode(TreeNodeType *pTreeRoot)
The following is a sample script using the sample tree data defined previously. Note that commands can be abbreviated to one character.
> proj4tree treedata Command (a,d,e,h,l,m,n,p,q,s): s A D C G H B F E L Command (a,d,e,h,l,m,n,p,q,s): a D Q Add of Q succeeded Command (a,d,e,h,l,m,n,p,q,s): a P S Add failed, parent node P not found Command (a,d,e,h,l,m,n,p,q,s): d C Delete failed, node C is not a leaf Command (a,d,e,h,l,m,n,p,q,s): d F Deletion of F succeeded Command (a,d,e,h,l,m,n,p,q,s): s A D Q C G H B E L Command (a,d,e,h,l,m,n,p,q,s): e L Node L does exist in tree Command (a,d,e,h,l,m,n,p,q,s): p L Parent of node L is E Command (a,d,e,h,l,m,n,p,q,s): n The number of nodes in the tree is 9 Command (a,d,e,h,l,m,n,p,q,s): l The number of leaf nodes in the tree is 3 Command (a,d,e,h,l,m,n,p,q,s): h The height of the tree is 3 Command (a,d,e,h,l,m,n,p,q,s): q
You should discuss the overall organization of the program and make sure that each member of the group understands the overall task to be done. You should also discuss the specifics of each routine that needs to be done. If your group does not understand some aspect of the project you should consult with your PLA, a TA or the instructor. After the discussion your group should break the implementation into pieces. Each group member should implement a portion of the routines. The most crucial routines will be AddNode(), which may use FindNode(), to build the tree and ShowTree() to print out the tree. The other routines can be tested after these routines are built. The DeleteNode() routine will probably be the most difficult to implement.
Each person should implement the routines assigned to them as an individual module. All modules and the driver should be compiled and linked with a Makefile. All modules should contain the header file. You are responsible for testing your program on a variety of input data.
You will be turning in your project as a group using the gturnin command (for ``proj4''). You will also turnin (for ``proj4eval'') an individual assessment of your groups' efforts as done in the previous assignment. Again, you are expected to talk as a group about each member's contributions before submitting your individual assessments.