CPSC 221 201/202/203 2021W2
Lab Trees
Skip To Content
Dashboard
  • Login
  • Dashboard
  • Calendar
  • Inbox
  • History
  • Help
Close
  • My Dashboard
  • CPSC 221 201/202/203 2021W2
  • Assignments
  • Lab Trees
2021W2
  • Home
  • Zoom
  • PrairieLearn 2021W2
  • Modules
  • Assignments
  • Syllabus
  • Media Gallery
  • My Media

Lab Trees

  • Due Feb 27, 2022 by 10p.m.
  • Points 1

Assignment Description

In this lab we’ll explore some cool helper functions for binary trees, learn about creating helper functions and thinking recursively, and hopefully see some fancy ascii trees on the terminal!

A new C++ thing

We’ll be using templates again in this lab, and unfortunately, this means we have to walk into a dark scary corner of C++. But hopefully we can take our lantern and cast some light here before any compiler errors bite.

The following function definitions won’t compile:

template <typename T>
Node * BinaryTree<T>::myHelperFunction(Node * node)
// The compiler doesn't know what a Node is, since the return type isn't scoped
// with the function.

So we have to scope it:

template <typename T>
BinaryTree<T>::Node * BinaryTree<T>::myHelperFunction(Node * node)

Using g++, the latter will show an error such as:

error: expected constructor, destructor, or type conversion before '*' token

Clang gives a more helpful error message:

fatal error: missing 'typename' prior to dependent type name 'BinaryTree<T>::Node'

Without going into the ugly details of it, this is happening because your compiler thinks Node is a member variable of the BinaryTree<T> class (since it’s a template). We can resolve this issue simply by adding a nice, friendly, typename keyword before our BinaryTree<T>::Node type. This lets the compiler know that Node really is a type, not a variable:

template <typename T>
typename BinaryTree<T>::Node * BinaryTree<T>::myHelperFunction(Node * node)

The above, fixed, definition compiles correctly. Since you’ll probably want to create your own helper functions for this lab, this is important to remember when you see the strange error above. You won’t be responsible for this nuance of templates on any exam in this class.

Checking Out the Code

You can get the files for this lab by downloading lab_trees.zip.

Testing Your Code

To test your code, compile using make:

make

For a visual test, run it with:

./treefun color

You will see that the output is colored — green means correct output, red means incorrect output, and underlined red means expected output that was not present. This mode is a bit experimental, and it might cause problems with your own debugging output (or other problems in general). To turn it off, simply leave off the “color” argument:

./treefun

You may also diff your solution with our expected output:

./treefun > out
diff -u out soln_treefun.out

You can run a second set of non-visual tests with:

./test

This second set does not test all functions (in particular, those whose output is sent to standard output.) As these tests are less extensive, if your code passes ./treefun, it should pass these as well.

Helper Functions and Recursion

You’ll want to be thinking about the following problems recursively on the nodes of the tree. However, the public functions provided do not supply a Node* parameter! So, to use recursion, you’ll need to implement helper functions with an extra Node* parameter so that you can recursively act differently on different nodes. We describe an example of this below.

The height() Function

There is a function called height() that returns the height of the binary tree. Recall that the height of a binary tree is just the length of the longest path from the root to a leaf, and that the height of an empty tree is -1.

We have implemented height() for you (see binarytree.cpp) to help you get a sense of recursive functions. Please read through the code, and ask questions if you are unsure of how it finds the height of a tree. A key point to note is that the public height() function simply calls the private height(Node* subRoot) function, so that we can recursively find the height on the subtrees.

The printLeftToRight() Function

There is a function called printLeftToRight() that prints out the values of the nodes of a binary tree in order. That is, everything to the left of a node will be printed out before that node itself, and everything to the right of a node will be printed out after that node. The function to_string(subRoot->elem) converts the elem field of a node to a string.

Note that printLeftToRight() uses an in-order-traversal to print out the nodes of a tree. You will need to use one of the three traversals covered in lecture for some of the following functions.

The mirror() Function

The mirror() function should flip our tree over a vertical axis, modifying the tree itself (not creating a flipped copy).

For example, if our original tree was

                        ______ 8 ______
                 ______/               \______
            __ 5 __                            9 __
         __/       \__                             \__
       2               7                               10
     /   \           /
   1       4       6
          /
         3

Our mirrored tree would be

                        ______ 8 ______
                 ______/               \______
            __ 9                            __ 5 __
         __/                             __/       \__
       10                              7               2
                                         \           /   \
                                           6       4       1
                                                    \
                                                     3

The printPaths() Function

The printPaths()function will print out all the possible paths from the root of the tree to any leaf node —all sequences starting at the root node and continuing downwards, ending at a leaf node. Paths ending in a left node should be printed before paths ending in a node further to the right. For example, for the following tree

            __ 1 __
         __/       \__
       2               3
     /   \           /   \
   4       8       6       7
  / \                     /
 5   10                  9

printPaths() would output

Path: 1 2 4 5
Path: 1 2 4 10
Path: 1 2 8
Path: 1 3 6
Path: 1 3 7 9

The sumDistances() Function

Good work! We just have one more function for you to write. Each node in a tree has a distance from the root node - the depth of that node, or the number of edges along the path from that node to the root. sumDistances() returns the sum of the distances of all nodes to the root node (the sum of the depths of all the nodes). Your solution should take LaTeX: O(n) time, where LaTeX: n is the number of nodes in the tree. For example, on the following tree:

           __ 5 __
        __/       \__
      0               8
        \
          2
         / \
        1   4

sumDistances() should return 0+1+2+3+3+1 = 10.

OPTIONAL TASKS:

The isOrdered() Function

The isOrdered() function returns true if an in-order traversal of the tree would produce a nondecreasing list output values, and false otherwise. (This is also the criterion for a binary tree to be a binary search tree.)

For example, isOrdered() should return true on the following tree:

           __ 5 __
        __/       \__
      1               8
        \
          2
           \
            4

but false for

           __ 5 __
        __/       \__
      1               8
        \
          2
           \
            11

Hint: What conditions need to be true for a tree to be in order (as defined above)? How can we check this recursively?

FlatTree

So far we have looked at representing trees using explicit Nodes and pointers. For complete binary trees, an alternate approach is to store the elements in a vector. Instead of maintaining an explicit root and left/right pointers, we instead use the following scheme:

  • the root element is stored at index 1
  • the left child of an element at index i is stored at index 2*i
  • the right child of an element at index i is stored at index 2*i+1

Note that the vector will have a "dummy" element at index 0, which does not correspond to any actual element in the tree.

For example, the following tree:

       2
     /   \
   4       8
  / \
 5   10

would be stored as: [X, 2, 4, 8, 5, 10], where the dummy element X can have any value.

You have the following functions to implement (in "flattree.cpp") which are documented in the corresponding header file.

  • printLeftToRight
  • getElement
  • fromBinaryTree
  • toBinaryTree

Marking Your Work

You will let us know you’ve worked on the lab by submitting your work to the autograder in PrarieLearn. We will run a very few simple test cases on your code, and if you pass any of them, you will get credit for the programming portion of the lab. (It’s a low bar.)

Submitting the lab is as simple as dragging your completed code into the PrarieLearn interface for the lab_trees assignment.

Please submit the following files:

  • binarytree.cpp
  • binarytree.h
  • flattree.cpp
  • flattree.h

Good luck!

Thanks to Nick Parlante/Stanford, Princeton’s CS 126, and CS 473 Spring 2011 for the exercises and inspiration.

1646028000 02/27/2022 10:00pm
Please include a description
Additional Comments:
Rating max score to > pts
Please include a rating title

Rubric

Find Rubric
Please include a title
Find a Rubric
Title
You've already rated students with this rubric. Any major changes could affect their assessment results.
 
 
 
 
 
 
 
     
Can't change a rubric once you've started using it.  
Title
Criteria Ratings Pts
This criterion is linked to a Learning Outcome Description of criterion
threshold: 5 pts
Edit criterion description Delete criterion row
5 to >0 pts Full Marks blank
0 to >0 pts No Marks blank_2
This area will be used by the assessor to leave comments related to this criterion.
pts
  / 5 pts
--
Additional Comments
Total Points: 5 out of 5