// Computer Science 367, Section 3, Fall 1997 // Instructor: Michael Siff (siff@cs.wisc.edu) // // Programming Assignment One: Solution // // // FILE: set.C // // A set template class using a list template class. // // Some notes on efficiency: // // Several of these functions require that copies of // the underlying list representation be made in order to preserve the // declared "constness" of the functions. That is, the set should remain // constant, but the obvious implementation manipulates the cursors of the // list representation. This could be avoided if external iterators were // used for the list, rather than its internal one. #include #include // Provides size_t // CONSTRUCTORS // ------------ template Set::Set() // Constructs the empty set. The default List constructor is automatically // called. { } template Set::Set(const ElementType& elem) // Constructs a singleton set by inserting the one element into the newly // (and automatically) constructed list. { rep.insert(elem); } template Set::Set(const Set& originalSet) // Copy constructor - uses List's copy constructor : rep(originalSet.rep) { } // DESTRUCTOR // ---------- template Set::~Set() { // list's destructor will automatically be called } // MODIFICATION MEMBER FUNCTIONS // ----------------------------- template void Set::add(const ElementType& elem) // Library facilities used: assert.h // Adds one element to the set if it's not already there. { assert(!isFull()); if (!rep.isMember(elem)) rep.append(elem); } template void Set::remove(const ElementType& elem) // Removes elem from the set, if it is there. { rep.reset(); // set the list cursor to the beginning of the list rep.find(elem); // look for elem if (!rep.isEnd()) // if it's there cursor won't be at end rep.remove(); // remove it } template void Set::operator=(const Set& source) { rep = source.rep; } template void Set::reset() // Resets the set to be the empty set. { List cleanrep; //initialize a new empty list // use list's assignment op to copy the empty list here // list's assignment will do the necessary cleanup rep = cleanrep; } // CONSTANT MEMBER FUNCTIONS // ------------------------- template size_t Set::size() const // Returns the number of elements in the set (in the list) { return rep.length(); } template bool Set::isEmpty() const // Returns true iff the underlying list is empty { return rep.isEmpty(); } template bool Set::isFull() const // Returns true iff the underlying list is full { return rep.isFull(); } template bool Set::isMember(const ElementType& elem) const // Returns true iff elem is in the underlying list { return rep.isMember(elem); } template bool Set::operator==(const Set& operand) const // Library facilities used: stdlib.h // Returns true if and only if the two sets have the same elements. // Checks that each element in first set is in second and that there are no // elements left in second not in first. { bool result=true; List L,M; // make copies of the underlying lists to preserve constness L = rep; M = operand.rep; for(L.reset(); result && !L.isEnd();) { M.reset(); M.find(L.current()); // if cursor at end then L.current isn't in M so false if (M.isEnd()) result = false; // if L.current is in M then remove it from both of them // this avoids redundancy else { L.remove(); M.remove(); } } return (result && M.isEmpty()); } template Set Set::operator+(const Set& otherSet) const // Return a new set which is the union of this set and otherSet. // If there is not enough room to store all the members, return the empty // set. { List listCopy; Set newSet(otherSet); // initialize newSet as copy of // otherSet listCopy = rep; // make copy of the list rep to preserve constness for(listCopy.reset(); !listCopy.isEnd(); listCopy.advance()) { if (newSet.isFull()) { newSet.reset(); break; } newSet.add(listCopy.current()); } return newSet; } template Set Set::intersection(const Set& otherSet) const // Return a new set which is the intersection of this set and otherSet. { ElementType elem; List listCopy; Set newSet; listCopy = rep; // make copy of the list rep to preserve constness for(listCopy.reset(); !listCopy.isEnd(); listCopy.advance()) { elem = listCopy.current(); if (otherSet.isMember(elem)) newSet.add(elem); } return newSet; } template Set Set::operator-(const Set& otherSet) const // Return a new set which is the difference of this set and otherSet. { List listCopy; Set newSet(*this); listCopy = otherSet.rep; // make copy of the list rep to preserve constness for(listCopy.reset(); !listCopy.isEnd(); listCopy.advance()) newSet.remove(listCopy.current()); return newSet; } template ElementType *Set::toArray() const // Return a pointer to a dynamically allocated array consisting of copies // of the elements in the set. This function can be used to gain access to // the elements of the set. Useful for things like output, iterating across // members, etc. { size_t count = size(); ElementType *array = new ElementType[count]; List temp; temp = rep; // make copy of the list rep to preserve constness temp.reset(); for(size_t i=0; i < count; i++) { array[i] = temp.current(); temp.advance(); } return array; }