/* set.h -- Matt Mahoney, mmahoney@cs.fit.edu, assignment 5 set.h defines a Set class. A Set supports the following operations: Set() // Empty set, {} Set(x) // Implicit conversion of x (type T) to {x} a+b // Union (elements in either a or b) a*b // Intersection (elements in both a and b) a-b // Difference (elements in a but not b) a+=b, a-=b, a*=b // Equivalent to a=a+b, a=a-b, a=a*b a==b // Set equality a<=b // true if a is a subset of b ab, a!=b, a>=b // Equivalent to !(b<=a), b containing only x (e.g {x}) in any of the above expressions where a Set is expected. Assignment 5 differs from assignment 4 in that a Set is represented by a binary tree rather than a map */ #include // NO using namespace std; template class Set { private: struct Node { // Node of binary tree T data; // One element of the set Node *left, *right; // Pointers to child nodes, or else 0 Node(const T& x): data(x), left(0), right(0) {} // Init data to x } *root; // Root of the tree void insert(Node* &p, const T& x); // Insert x into branch p void insert_from(const Node* p); // Insert from branch p of another tree void erase(Node* p); // Delete all nodes void insert_if_in(const Set& s, const Node* p); // From p if in s void insert_if_not_in(const Set& s, const Node* p); // From p if not bool in(const T& x, const Node* p) const; // Is x in branch p? int size(const Node* p) const; // Nodes at branch p void print(std::ostream& out, const Node* p) const; // Print branch p public: Set(): root(0) {} // Create empty set {} Set(const T& x): root(0) {insert(root, x);} // One element set {x} Set(const Set& s): root(0) {insert_from(s.root);} // Copy constructor Set& operator = (const Set& s); // Assignment ~Set() {erase(root);} // Destructor Set& operator += (const Set& b); // Union Set& operator -= (const Set& b); // Difference Set& operator *= (const Set& b); // Intersection bool in(const T& x) const {return in(x, root);} // x is element? int size() const {return size(root);}; // Number of elements void print(std::ostream& out) const; // Print in format {x,y,...} }; ////////// Private member functions: // Insert x at the branch (subtree) rooted at p (unless already inserted) template void Set::insert(Node* &p, const T& x) { if (!p) p=new Node(x); else if (x < p->data) insert(p->left, x); else if (p->data < x) insert(p->right, x); } // Insert a copy of all nodes from branch p from another tree into this tree template void Set::insert_from(const Node* p) { if (p) { insert(root, p->data); insert_from(p->left); insert_from(p->right); } } // Delete all nodes in branch p. Does NOT set p to 0 template void Set::erase(Node* p) { if (p) { erase(p->left); erase(p->right); delete p; } } // Insert copies of nodes of branch p if the values are in s template void Set::insert_if_in(const Set& s, const Node* p) { if (p) { if (s.in(p->data)) insert(root, p->data); insert_if_in(s, p->left); insert_if_in(s, p->right); } } // Insert copies of nodes of branch p if the values are not in s template void Set::insert_if_not_in(const Set& s, const Node* p) { if (p) { if (!s.in(p->data)) insert(root, p->data); insert_if_not_in(s, p->left); insert_if_not_in(s, p->right); } } // Is x in branch p? template bool Set::in(const T& x, const Node* p) const { if (!p) return false; else if (x == p->data) return true; else if (x < p->data) return in(x, p->left); else return in(x, p->right); } // Number of nodes in branch p template int Set::size(const Node* p) const { if (p) return 1 + size(p->left) + size(p->right); else return 0; } // Print branch p to out as a comma separated list, e.g. "a,b,c,d" template void Set::print(std::ostream& out, const Node* p) const { if (p) { print(out, p->left); if (p->left) out << ","; out << p->data; if (p->right) out << ","; print(out, p->right); } } ////////// Public member functions: // Assignment template Set& Set::operator = (const Set& s) { if (&s != this) { erase(root); root = 0; insert_from(s.root); } return *this; } // Set union template Set& Set::operator += (const Set& b) { insert_from(b.root); return *this; } // Set difference template Set& Set::operator -= (const Set& b) { Set r; r.insert_if_not_in(b, root); *this = r; return *this; } // Set intersection template Set& Set::operator *= (const Set& b) { Set r; r.insert_if_in(b, root); *this = r; return *this; } // Print whole set to out as a comma separated list in braces, e.g. "{a,b,c,d}" template void Set::print(std::ostream& out) const { out << "{"; print(out, root); out << "}"; } ////////// The following nonmember code is unchaged from assignment 4: // Nonmember binary set operations template Set operator+(Set a, const Set& b) {return a+=b;} template Set operator-(Set a, const Set& b) {return a-=b;} template Set operator*(Set a, const Set& b) {return a*=b;} template bool operator<=(const Set& a, const Set& b) {return (a-b).size()==0;} template bool operator==(const Set& a, const Set& b) {return a<=b && b<=a;} template bool operator!=(const Set& a, const Set& b) {return !(a==b);} template bool operator>=(const Set& a, const Set& b) {return b<=a;} template bool operator< (const Set& a, const Set& b) {return a<=b && !(b<=a);} template bool operator> (const Set& a, const Set& b) {return b<=a && !(a<=b);} // Output template std::ostream& operator << (std::ostream& out, const Set& st) { st.print(out); return out; } // Define binary operators with implicit conversions on the left or right #define op(r, x) \ template r operator x (const T& a, const Set& b) {return Set(a) x b;} \ template r operator x (const Set& a, const T& b) {return a x Set(b);} op(Set, +) op(Set, -) op(Set, *) op(bool, <) op(bool, <=) op(bool, >) op(bool, >=) op(bool, ==) op(bool, !=) #undef op