Lab #6: Trees¶
Due Date Wednesday, May 11th at 9pm.
The purpose of this lab is to give you practice working with:
writing recursive functions,
structures and pointers to structures, and
navigating binary trees.
You’ll also get practice writing helper functions.
You must complete this lab on a CS Linux machine. You can use the machines in CSIL or can use VSCode + ssh on your own machine to get to one of the Linux servers.
Getting Started¶
You will be using the same repository for all the labs in this course.
To pick up the files you need for this lab (aka, the distribution),
you should navigate to your cmsc15200/labs-GITHUB_USERID
directory
(where GITHUB_USERID
is replaced with your GitHub account name)
and then run:
$ git pull upstream main
(We will use $
to indicate the Linux command-line prompt. It is
not part of the command that you will run.)
If this command succeeded, you will have a subdirectory named
lab6
. You will do all of your work for this lab in this
directory. See the file README.md
for a description of the files
in the distribution.
As in earlier labs, we have provided a Makefile
that has targets
for compiling your code with tests that you write, for compiling your
code with our automated tests, and for cleaning up generated files.
Trees¶
In this lab, you will answer questions about binary trees. The tasks below make use of the following typedef and struct:
typedef struct inttree inttree_t;
struct inttree {
int val;
inttree_t *left
inttree_t *right;
};
An inttree_t
is one node in a tree with integer values. Each node stores
an integer along with references to its left and right subtrees. left
or
right
can be NULL
if a node does not have a left or right subtree (or
both, if it’s a leaf).
As usual, the entire tree is represented using a pointer to the root node.
You can find these definitions in lab6.h
.
Restriction You do not need to make use of arrays anywhere on this lab. That is, you should not create an array representation of the nodes in a tree, then process that array. It is not necessary to use queues or other types of linked lists, either. All of the computations can be done using the tree directly.
None of the tasks require you to traverse the tree multiple times. That is, an efficient solution to each problem will involve visiting each tree node at most once. Make sure you are not making multiple passes over the tree.
We encourage you to use recursion throughout this assignment and to write helper functions where you see fit.
Deliverables¶
Task 1
Complete the function no_onlies
which takes a pointer to an inttree_t
and
returns true
if no node in the tree is an “only child”
(“onlies” is a term for couples that have only one child).
That is, this function returns true
if no nodes in the tree have just one child,
and false
otherwise.
This function should return true
if the input tree is empty.
For example, consider the trees t1
and t2
:
t1: t2:
5 5
/ \ / \
3 7 3 7
/ \ / / \
1 4 1 8 9
A call to
no_onlies
witht1
should returntrue
. Every node has either zero or two children.A call to
no_onlies
witht2
should returnfalse
. The node with the value 3 has just one child. That is to say, the node with the value 1 is an only child.
Task 2
Complete the function postorder
which takes a pointer to an inttree_t
and num
, an integer. postorder
should search for num
in t
using postorder traversal and returns
the number of steps it took to find num
. If num
is not in the tree, it
should return the number of steps it took to determine that num
is not in the tree.
Here are some examples:
A call to
postorder
witht1
and 7 should return 4. It takes 4 steps to find the value 7 int1
using postorder traversal.A call to
postorder
witht1
and 1 should return 1. It takes just 1 step to find the value 1 int1
.A call to
postorder
witht1
and 8 should return 5. All 5 nodes in the tree need to be checked in order to determine that the value 8 is not in the tree.A call to
postorder
with the empty tree (NULL
) should return 0. There are no nodes to search in the empty tree.
A note about efficiency: This task can be completed with just one pass over the
tree (or less, if val
is found). That is, the number returned from postorder
should
really be the total number of nodes visited in order to find val
.
Make sure you’re not making multiple passes over the tree.
Hint: Consider using a helper function for this task. Remember that your helper functions should be properly documented.
Task 3
A path is a sequence of nodes in a tree that connects the root node to a leaf node.
Complete the function even_odd
which takes a pointer to an inttree_t
and returns true
if every path in a tree
from the root to a leaf alternates between even and odd numbers, and false
otherwise. This function should return true
if the input tree is empty (it is
vacuously true).
Let t3
and t4
be the following trees:
t3: t4:
3 6
/ \ / \
2 6 3 9
/ / \ / / \
1 5 9 2 5 8
/ \
4 8
A call to
even_odd
witht3
should returntrue
. Every path throught3
alternates between even and odd integers. Note that it doesn’t matter whether the path starts with an even or add number, as long as it alternates between the two.A call to
even_odd
witht4
should returnfalse
. The path 6-9-5 does not alternate between even and odd integers.
Task 4
Complete the function path_adds_to
which takes a pointer to an inttree_t
and num
, an integer, and returns true
if there is a path of nodes in the tree whose
values add to num
, and false
otherwise.
Here are some examples:
A call to
path_adds_to
witht3
and 14 should returntrue
. The path 3-5-6 adds to 14.A call to
path_adds_to
witht3
and 26 should returntrue
. The path 3-6-9-8 adds to 26.A call to
paths_add_to
witht3
and 10 should returnfalse
. There is no path int3
that adds to 10.A call to
paths_add_to
with the empty tree (NULL
) and any number should returnfalse
. There are no paths in the empty tree that add to an integer.
Grading¶
Your grade on this assignment will be fully determined by the automated tests on Gradescope. There will not be a code quality portion of your grade for this lab.
If you do not implement code for a particular task, you will get a zero for that porition of the autograder. You will also recieve a zero for a task if you do not follow the restrictions stated above.
The weights for the tasks are:
Task 1: 20%
Task 2: 30%
Task 3: 25%
Task 4: 25%
Cleaning up¶
Before your submit your work, we strongly encourage you to get your
directory into a clean state. Run make clean
to remove any
executables that are laying around and then run git status .
to
make sure you did not forget to add/commit any of the required files.
Also, remove directives, such as:
// YOUR CODE HERE
// Replace 0.0 with an appropriate return value
from your code. Make sure to recompile and rerun the tests after you clean up. It is easy to introduce a syntax error at this stage.
Submission¶
Before you upload your submission, make sure you have added the
required information to the header comment in lab6.c
:
your name,
the names of anyone beyond the course staff you discussed the assignment with, and
links to any resources that you used other than course materials and the course textbook.
Note: write None
in the relevant field, to indicate that you did
not use any sources and/or consult anyone beyond the course staff.
To submit your work, you will need to add, commit, and push
lab6.c
to GitHub and then upload your
repository to Gradescope under the Lab #6 assignment.
You are welcome to upload your code to Gradescope multiple times before the deadline, but it is wildly inefficient to use Gradescope as a compute server. You should test your code on the CS Linux machines and only upload it when you think you are finished or when you are getting close to the deadline and want to do a “safety” submission.
You are responsible for making sure that the code you upload compiles and runs. You will get zero credit for code that does not compile.
Finally, a reminder that we will not accept late work.