From 76db306c94447d97bb705d1a4fb0770ff007b827 Mon Sep 17 00:00:00 2001 From: Jidong Xiao Date: Mon, 30 Oct 2023 20:47:59 -0400 Subject: [PATCH] adding lab 10 --- labs/10_trees_I/README.md | 44 +++++++++ labs/10_trees_I/ds_set.h | 155 ++++++++++++++++++++++++++++++++ labs/10_trees_I/test_ds_set.cpp | 96 ++++++++++++++++++++ 3 files changed, 295 insertions(+) create mode 100644 labs/10_trees_I/README.md create mode 100644 labs/10_trees_I/ds_set.h create mode 100644 labs/10_trees_I/test_ds_set.cpp diff --git a/labs/10_trees_I/README.md b/labs/10_trees_I/README.md new file mode 100644 index 0000000..0689116 --- /dev/null +++ b/labs/10_trees_I/README.md @@ -0,0 +1,44 @@ +# Lab 10 — Trees, Binary Trees, & Binary Search Trees + +## Checkpoint 1 + +*estimate: 20-30 minutes* + +problem 1: Draw a binary tree with 4 levels with the integers 1-7 such that the sum of elements on every level of the tree is the same. + +problem 2: Create a exactly balanced binary search tree with 7 color words (order the colors alphabetically). + +problem 3: Draw a exactly-balanced binary search tree containing the letters of the word: uncopyrightable + +What is the pre-order traversal of the tree above? + +problem 4: Now draw a exactly-balanced binary tree of characters such that a post-order traversal spells the word: uncopyrightable + +What is the breadth-first traversal of the tree above? + +*To complete this checkpoint*: When you have finished all of the problems, discuss your answers with your lab TA or mentor. + +## Checkpoint 2 + +*estimate: 20-35 minutes* + +Now let’s explore the implementation of the ds_set class, along with the use of recursive functions to + +manipulate binary search trees. Download and examine the files: [ds_set.h](ds_set.h) and [test_ds_set.cpp](test_ds_set.cpp). + +The implementation of find provided in ds_set.h is recursive. Re-implement and test a +non-recursive replacement for this function. + +**To complete this checkpoint**: Show one of the TAs your new code. Be prepared to discuss the running +time for the two different versions of find for various inputs. + +## Checkpoint 3 + +*estimate: 20-35 minutes* + +The implementation of the copy constructor and the assignment operator is not yet complete +because each depends on a private member function called copy tree, the body of which has not yet been +written. Write copy tree and then test to see if it works by “uncommenting” the appropriate code from the +main function. + +**To complete this checkpoint**: Show one of the TAs your new code. Be prepared to discuss the running diff --git a/labs/10_trees_I/ds_set.h b/labs/10_trees_I/ds_set.h new file mode 100644 index 0000000..fcf82cf --- /dev/null +++ b/labs/10_trees_I/ds_set.h @@ -0,0 +1,155 @@ +// Partial implementation of binary-tree based set class similar to std::set. +// The iterator increment & decrement operations have been omitted. +#ifndef ds_set_h_ +#define ds_set_h_ +#include +#include + +// ------------------------------------------------------------------- +// TREE NODE CLASS +template +class TreeNode { +public: + TreeNode() : left(NULL), right(NULL) {} + TreeNode(const T& init) : value(init), left(NULL), right(NULL) {} + T value; + TreeNode* left; + TreeNode* right; +}; + +template class ds_set; + +// ------------------------------------------------------------------- +// TREE NODE ITERATOR CLASS +template +class tree_iterator { +public: + tree_iterator() : ptr_(NULL) {} + tree_iterator(TreeNode* p) : ptr_(p) {} + tree_iterator(const tree_iterator& old) : ptr_(old.ptr_) {} + ~tree_iterator() {} + tree_iterator& operator=(const tree_iterator& old) { ptr_ = old.ptr_; return *this; } + // operator* gives constant access to the value at the pointer + const T& operator*() const { return ptr_->value; } + // comparions operators are straightforward + bool operator== (const tree_iterator& rgt) { return ptr_ == rgt.ptr_; } + bool operator!= (const tree_iterator& rgt) { return ptr_ != rgt.ptr_; } + // increment & decrement will be discussed in Lecture 19 and Lab 11 + +private: + // representation + TreeNode* ptr_; +}; + +// ------------------------------------------------------------------- +// DS SET CLASS +template +class ds_set { +public: + ds_set() : root_(NULL), size_(0) {} + ds_set(const ds_set& old) : size_(old.size_) { + root_ = this->copy_tree(old.root_); } + ~ds_set() { this->destroy_tree(root_); root_ = NULL; } + ds_set& operator=(const ds_set& old) { + if (&old != this) { + this->destroy_tree(root_); + root_ = this->copy_tree(old.root_); + size_ = old.size_; + } + return *this; + } + + typedef tree_iterator iterator; + + int size() const { return size_; } + bool operator==(const ds_set& old) const { return (old.root_ == this->root_); } + + // FIND, INSERT & ERASE + iterator find(const T& key_value) { return find(key_value, root_); } + std::pair< iterator, bool > insert(T const& key_value) { return insert(key_value, root_); } + int erase(T const& key_value) { return erase(key_value, root_); } + + // OUTPUT & PRINTING + friend std::ostream& operator<< (std::ostream& ostr, const ds_set& s) { + s.print_in_order(ostr, s.root_); + return ostr; + } + void print_as_sideways_tree(std::ostream& ostr) const { + print_as_sideways_tree(ostr, root_, 0); } + + // ITERATORS + iterator begin() const { + if (!root_) return iterator(NULL); + TreeNode* p = root_; + while (p->left) p = p->left; + return iterator(p); + } + iterator end() const { return iterator(NULL); } + +private: + // REPRESENTATION + TreeNode* root_; + int size_; + + // PRIVATE HELPER FUNCTIONS + TreeNode* copy_tree(TreeNode* old_root) { + // Implemented in Lab 10 + + + + + + + + + + + } + + void destroy_tree(TreeNode* p) { /* Implemented in Lecture 18 */ } + + iterator find(const T& key_value, TreeNode* p) { + if (!p) return iterator(NULL); + if (p->value > key_value) + return find(key_value, p->left); + else if (p->value < key_value) + return find(key_value, p->right); + else + return iterator(p); + } + + std::pair insert(const T& key_value, TreeNode*& p) { + if (!p) { + p = new TreeNode(key_value); + this->size_++; + return std::pair(iterator(p), true); + } + else if (key_value < p->value) + return insert(key_value, p->left); + else if (key_value > p->value) + return insert(key_value, p->right); + else + return std::pair(iterator(p), false); + } + + int erase(T const& key_value, TreeNode* &p) { /* Implemented in Lecture 19 or 20 */ } + + void print_in_order(std::ostream& ostr, const TreeNode* p) const { + if (p) { + print_in_order(ostr, p->left); + ostr << p->value << "\n"; + print_in_order(ostr, p->right); + } + } + + void print_as_sideways_tree(std::ostream& ostr, const TreeNode* p, int depth) const { + if (p) { + print_as_sideways_tree(ostr, p->right, depth+1); + for (int i=0; ivalue << "\n"; + print_as_sideways_tree(ostr, p->left, depth+1); + } + } +}; + +#endif diff --git a/labs/10_trees_I/test_ds_set.cpp b/labs/10_trees_I/test_ds_set.cpp new file mode 100644 index 0000000..8ca9b05 --- /dev/null +++ b/labs/10_trees_I/test_ds_set.cpp @@ -0,0 +1,96 @@ +#include +#include +#include +#include + +#include "ds_set.h" + +int main() { + + // build a set + ds_set set1; + + std::pair< ds_set::iterator, bool > insert_result; + std::string to_insert = std::string("hello"); + insert_result = set1.insert(to_insert); + assert(insert_result.second); + + insert_result = set1.insert(std::string("good-bye")); + assert(insert_result.second); + + insert_result = set1.insert(std::string("friend")); + assert(insert_result.second); + + insert_result = set1.insert(std::string("abc")); + assert(insert_result.second); + + insert_result = set1.insert(std::string("puppy")); + assert(insert_result.second); + + insert_result = set1.insert(std::string("zebra")); + assert(insert_result.second); + + insert_result = set1.insert(std::string("daddy")); + assert(insert_result.second); + + insert_result = set1.insert(std::string("puppy")); + assert(!insert_result.second && * insert_result.first == std::string("puppy")); + + ds_set::iterator p = set1.begin(); + assert(p != set1.end() && *p == std::string("abc")); + + + // visualize the set + std::cout << "The set size is " << set1.size() + << "\nHere are the elements: \n" << set1 << std::endl; + + p = set1.find("foo"); + if (p == set1.end()) + std::cout << "\"foo\" is not in the set\n"; + else + std::cout << "\"foo\" is in the set\n" + << "The iterator points to " << *p << std::endl; + + p = set1.find("puppy"); + if (p == set1.end()) + std::cout << "\"puppy\" is not in the set\n"; + else + std::cout << "\"puppy\" is in the set\n" + << "The iterator points to " << *p << std::endl; + + p = set1.find("daddy"); + if (p == set1.end()) + std::cout << "\"daddy\" is not in the set\n"; + else + std::cout << "\"daddy\" is in the set\n" + << "The iterator points to " << *p << std::endl; + + std::cout << "\nHere is the tree, printed sideways.\n" + << "The indentation is proportional to the depth of the node\n" + << "so that the value stored at the root is the only value printed\n" + << "without indentation. Also, for each node, the right subtree\n" + << "can be found above where the node is printed and indented\n" + << "relative to it\n\n"; + set1.print_as_sideways_tree(std::cout); + + + /* + // Needed for checkpoint 2, part 2 + ds_set set2(set1); + std::cout << "set1.size() = " << set1.size() << ", set2.size() = " << set2.size() << std::endl; + std::cout << "\nHere is set2 printed sideways:\n"; + set2.print_as_sideways_tree(std::cout); + + // Now add more stuff to set2. + insert_result = set2.insert(std::string("a")); + assert(insert_result.second); + insert_result = set2.insert(std::string("b")); + assert(insert_result.second); + std::cout << "\nAfter two inserts:\n" + << "set1.size() = " << set1.size() << ", set2.size() = " << set2.size() << "\n" + << "\nThe contents of set2:\n" << set2 << std::endl; + + */ + + return 0; +}