629 lines
15 KiB
C
629 lines
15 KiB
C
|
/*
|
||
|
* File: set.h
|
||
|
* -----------
|
||
|
* This file exports the <code>Set</code> class, which implements a
|
||
|
* collection for storing a set of distinct elements.
|
||
|
*/
|
||
|
|
||
|
#ifndef _set_h
|
||
|
#define _set_h
|
||
|
|
||
|
#include <iostream>
|
||
|
#include "foreach.h"
|
||
|
#include "map.h"
|
||
|
#include "vector.h"
|
||
|
|
||
|
/*
|
||
|
* Class: Set<ValueType>
|
||
|
* ---------------------
|
||
|
* This class stores a collection of distinct elements.
|
||
|
*/
|
||
|
|
||
|
template <typename ValueType>
|
||
|
class Set {
|
||
|
|
||
|
public:
|
||
|
|
||
|
/*
|
||
|
* Constructor: Set
|
||
|
* Usage: Set<ValueType> set;
|
||
|
* --------------------------
|
||
|
* Creates an empty set of the specified element type.
|
||
|
*/
|
||
|
|
||
|
Set();
|
||
|
|
||
|
/*
|
||
|
* Destructor: ~Set
|
||
|
* ----------------
|
||
|
* Frees any heap storage associated with this set.
|
||
|
*/
|
||
|
|
||
|
virtual ~Set();
|
||
|
|
||
|
/*
|
||
|
* Method: size
|
||
|
* Usage: count = set.size();
|
||
|
* --------------------------
|
||
|
* Returns the number of elements in this set.
|
||
|
*/
|
||
|
|
||
|
int size() const;
|
||
|
|
||
|
/*
|
||
|
* Method: isEmpty
|
||
|
* Usage: if (set.isEmpty()) ...
|
||
|
* -----------------------------
|
||
|
* Returns <code>true</code> if this set contains no elements.
|
||
|
*/
|
||
|
|
||
|
bool isEmpty() const;
|
||
|
|
||
|
/*
|
||
|
* Method: add
|
||
|
* Usage: set.add(value);
|
||
|
* ----------------------
|
||
|
* Adds an element to this set, if it was not already there. For
|
||
|
* compatibility with the STL <code>set</code> class, this method
|
||
|
* is also exported as <code>insert</code>.
|
||
|
*/
|
||
|
|
||
|
void add(const ValueType & value);
|
||
|
void insert(const ValueType & value);
|
||
|
|
||
|
/*
|
||
|
* Method: remove
|
||
|
* Usage: set.remove(value);
|
||
|
* -------------------------
|
||
|
* Removes an element from this set. If the value was not
|
||
|
* contained in the set, no error is generated and the set
|
||
|
* remains unchanged.
|
||
|
*/
|
||
|
|
||
|
void remove(const ValueType & value);
|
||
|
|
||
|
/*
|
||
|
* Method: contains
|
||
|
* Usage: if (set.contains(value)) ...
|
||
|
* -----------------------------------
|
||
|
* Returns <code>true</code> if the specified value is in this set.
|
||
|
*/
|
||
|
|
||
|
bool contains(const ValueType & value) const;
|
||
|
|
||
|
/*
|
||
|
* Method: isSubsetOf
|
||
|
* Usage: if (set.isSubsetOf(set2)) ...
|
||
|
* ------------------------------------
|
||
|
* Implements the subset relation on sets. It returns
|
||
|
* <code>true</code> if every element of this set is
|
||
|
* contained in <code>set2</code>.
|
||
|
*/
|
||
|
|
||
|
bool isSubsetOf(const Set & set2) const;
|
||
|
|
||
|
/*
|
||
|
* Method: clear
|
||
|
* Usage: set.clear();
|
||
|
* -------------------
|
||
|
* Removes all elements from this set.
|
||
|
*/
|
||
|
|
||
|
void clear();
|
||
|
|
||
|
/*
|
||
|
* Operator: ==
|
||
|
* Usage: set1 == set2
|
||
|
* -------------------
|
||
|
* Returns <code>true</code> if <code>set1</code> and <code>set2</code>
|
||
|
* contain the same elements.
|
||
|
*/
|
||
|
|
||
|
bool operator==(const Set & set2) const;
|
||
|
|
||
|
/*
|
||
|
* Operator: !=
|
||
|
* Usage: set1 != set2
|
||
|
* -------------------
|
||
|
* Returns <code>true</code> if <code>set1</code> and <code>set2</code>
|
||
|
* are different.
|
||
|
*/
|
||
|
|
||
|
bool operator!=(const Set & set2) const;
|
||
|
|
||
|
/*
|
||
|
* Operator: +
|
||
|
* Usage: set1 + set2
|
||
|
* set1 + element
|
||
|
* ---------------------
|
||
|
* Returns the union of sets <code>set1</code> and <code>set2</code>, which
|
||
|
* is the set of elements that appear in at least one of the two sets. The
|
||
|
* right hand set can be replaced by an element of the value type, in which
|
||
|
* case the operator returns a new set formed by adding that element.
|
||
|
*/
|
||
|
|
||
|
Set operator+(const Set & set2) const;
|
||
|
Set operator+(const ValueType & element) const;
|
||
|
|
||
|
/*
|
||
|
* Operator: *
|
||
|
* Usage: set1 * set2
|
||
|
* ------------------
|
||
|
* Returns the intersection of sets <code>set1</code> and <code>set2</code>,
|
||
|
* which is the set of all elements that appear in both.
|
||
|
*/
|
||
|
|
||
|
Set operator*(const Set & set2) const;
|
||
|
|
||
|
/*
|
||
|
* Operator: -
|
||
|
* Usage: set1 - set2
|
||
|
* set1 - element
|
||
|
* ---------------------
|
||
|
* Returns the difference of sets <code>set1</code> and <code>set2</code>,
|
||
|
* which is all of the elements that appear in <code>set1</code> but
|
||
|
* not <code>set2</code>. The right hand set can be replaced by an
|
||
|
* element of the value type, in which case the operator returns a new
|
||
|
* set formed by removing that element.
|
||
|
*/
|
||
|
|
||
|
Set operator-(const Set & set2) const;
|
||
|
Set operator-(const ValueType & element) const;
|
||
|
|
||
|
/*
|
||
|
* Operator: +=
|
||
|
* Usage: set1 += set2;
|
||
|
* set1 += value;
|
||
|
* ---------------------
|
||
|
* Adds all of the elements from <code>set2</code> (or the single
|
||
|
* specified value) to <code>set1</code>. As a convenience, the
|
||
|
* <code>Set</code> package also overloads the comma operator so
|
||
|
* that it is possible to initialize a set like this:
|
||
|
*
|
||
|
*<pre>
|
||
|
* Set<int> digits;
|
||
|
* digits += 0, 1, 2, 3, 4, 5, 6, 7, 8, 9;
|
||
|
*</pre>
|
||
|
*/
|
||
|
|
||
|
Set & operator+=(const Set & set2);
|
||
|
Set & operator+=(const ValueType & value);
|
||
|
|
||
|
/*
|
||
|
* Operator: *=
|
||
|
* Usage: set1 *= set2;
|
||
|
* --------------------
|
||
|
* Removes any elements from <code>set1</code> that are not present in
|
||
|
* <code>set2</code>.
|
||
|
*/
|
||
|
|
||
|
Set & operator*=(const Set & set2);
|
||
|
|
||
|
/*
|
||
|
* Operator: -=
|
||
|
* Usage: set1 -= set2;
|
||
|
* set1 -= value;
|
||
|
* ---------------------
|
||
|
* Removes the elements from <code>set2</code> (or the single
|
||
|
* specified value) from <code>set1</code>. As a convenience, the
|
||
|
* <code>Set</code> package also overloads the comma operator so
|
||
|
* that it is possible to remove multiple elements from a set
|
||
|
* like this:
|
||
|
*
|
||
|
*<pre>
|
||
|
* digits -= 0, 2, 4, 6, 8;
|
||
|
*</pre>
|
||
|
*
|
||
|
* which removes the values 0, 2, 4, 6, and 8 from the set
|
||
|
* <code>digits</code>.
|
||
|
*/
|
||
|
|
||
|
Set & operator-=(const Set & set2);
|
||
|
Set & operator-=(const ValueType & value);
|
||
|
|
||
|
/*
|
||
|
* Method: first
|
||
|
* Usage: ValueType value = set.first();
|
||
|
* -------------------------------------
|
||
|
* Returns the first value in the set in the order established by the
|
||
|
* <code>foreach</code> macro. If the set is empty, <code>first</code>
|
||
|
* generates an error.
|
||
|
*/
|
||
|
|
||
|
ValueType first() const;
|
||
|
|
||
|
/*
|
||
|
* Method: toString
|
||
|
* Usage: string str = set.toString();
|
||
|
* -----------------------------------
|
||
|
* Converts the set to a printable string representation.
|
||
|
*/
|
||
|
|
||
|
std::string toString();
|
||
|
|
||
|
/*
|
||
|
* Method: mapAll
|
||
|
* Usage: set.mapAll(fn);
|
||
|
* ----------------------
|
||
|
* Iterates through the elements of the set and calls <code>fn(value)</code>
|
||
|
* for each one. The values are processed in ascending order, as defined
|
||
|
* by the comparison function.
|
||
|
*/
|
||
|
|
||
|
void mapAll(void (*fn)(ValueType)) const;
|
||
|
void mapAll(void (*fn)(const ValueType &)) const;
|
||
|
|
||
|
template <typename FunctorType>
|
||
|
void mapAll(FunctorType fn) const;
|
||
|
|
||
|
/*
|
||
|
* Additional Set operations
|
||
|
* -------------------------
|
||
|
* In addition to the methods listed in this interface, the Set class
|
||
|
* supports the following operations:
|
||
|
*
|
||
|
* - Stream I/O using the << and >> operators
|
||
|
* - Deep copying for the copy constructor and assignment operator
|
||
|
* - Iteration using the range-based for statement and STL iterators
|
||
|
*
|
||
|
* The iteration forms process the Set in ascending order.
|
||
|
*/
|
||
|
|
||
|
/* Private section */
|
||
|
|
||
|
/**********************************************************************/
|
||
|
/* Note: Everything below this point in the file is logically part */
|
||
|
/* of the implementation and should not be of interest to clients. */
|
||
|
/**********************************************************************/
|
||
|
|
||
|
private:
|
||
|
|
||
|
Map<ValueType,bool> map; /* Map used to store the element */
|
||
|
bool removeFlag; /* Flag to differentiate += and -= */
|
||
|
|
||
|
public:
|
||
|
|
||
|
/*
|
||
|
* Hidden features
|
||
|
* ---------------
|
||
|
* The remainder of this file consists of the code required to
|
||
|
* support the comma operator, deep copying, and iteration.
|
||
|
* Including these methods in the public interface would make
|
||
|
* that interface more difficult to understand for the average client.
|
||
|
*/
|
||
|
|
||
|
/* Extended constructors */
|
||
|
|
||
|
template <typename CompareType>
|
||
|
explicit Set(CompareType cmp) : map(Map<ValueType,bool>(cmp)) {
|
||
|
/* Empty */
|
||
|
}
|
||
|
|
||
|
Set & operator,(const ValueType & value) {
|
||
|
if (this->removeFlag) {
|
||
|
this->remove(value);
|
||
|
} else {
|
||
|
this->add(value);
|
||
|
}
|
||
|
return *this;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Iterator support
|
||
|
* ----------------
|
||
|
* The classes in the StanfordCPPLib collection implement input
|
||
|
* iterators so that they work symmetrically with respect to the
|
||
|
* corresponding STL classes.
|
||
|
*/
|
||
|
|
||
|
class iterator : public std::iterator<std::input_iterator_tag,ValueType> {
|
||
|
|
||
|
private:
|
||
|
|
||
|
typename Map<ValueType,bool>::iterator mapit; /* Iterator for the map */
|
||
|
|
||
|
public:
|
||
|
|
||
|
iterator() {
|
||
|
/* Empty */
|
||
|
}
|
||
|
|
||
|
iterator(typename Map<ValueType,bool>::iterator it) : mapit(it) {
|
||
|
/* Empty */
|
||
|
}
|
||
|
|
||
|
iterator(const iterator & it) {
|
||
|
mapit = it.mapit;
|
||
|
}
|
||
|
|
||
|
iterator & operator=(const iterator & it) {
|
||
|
if(*this != it){
|
||
|
mapit = it.mapit;
|
||
|
}
|
||
|
return *this;
|
||
|
}
|
||
|
|
||
|
iterator & operator++() {
|
||
|
++mapit;
|
||
|
return *this;
|
||
|
}
|
||
|
|
||
|
iterator operator++(int) {
|
||
|
iterator copy(*this);
|
||
|
operator++();
|
||
|
return copy;
|
||
|
}
|
||
|
|
||
|
bool operator==(const iterator & rhs) {
|
||
|
return mapit == rhs.mapit;
|
||
|
}
|
||
|
|
||
|
bool operator!=(const iterator & rhs) {
|
||
|
return !(*this == rhs);
|
||
|
}
|
||
|
|
||
|
ValueType operator*() {
|
||
|
return *mapit;
|
||
|
}
|
||
|
|
||
|
ValueType *operator->() {
|
||
|
return mapit;
|
||
|
}
|
||
|
};
|
||
|
|
||
|
iterator begin() const {
|
||
|
return iterator(map.begin());
|
||
|
}
|
||
|
|
||
|
iterator end() const {
|
||
|
return iterator(map.end());
|
||
|
}
|
||
|
|
||
|
};
|
||
|
|
||
|
extern void error(std::string msg);
|
||
|
|
||
|
template <typename ValueType>
|
||
|
Set<ValueType>::Set() {
|
||
|
/* Empty */
|
||
|
}
|
||
|
|
||
|
template <typename ValueType>
|
||
|
Set<ValueType>::~Set() {
|
||
|
/* Empty */
|
||
|
}
|
||
|
|
||
|
template <typename ValueType>
|
||
|
int Set<ValueType>::size() const {
|
||
|
return map.size();
|
||
|
}
|
||
|
|
||
|
template <typename ValueType>
|
||
|
bool Set<ValueType>::isEmpty() const {
|
||
|
return map.isEmpty();
|
||
|
}
|
||
|
|
||
|
template <typename ValueType>
|
||
|
void Set<ValueType>::add(const ValueType & value) {
|
||
|
map.put(value, true);
|
||
|
}
|
||
|
|
||
|
template <typename ValueType>
|
||
|
void Set<ValueType>::insert(const ValueType & value) {
|
||
|
map.put(value, true);
|
||
|
}
|
||
|
|
||
|
template <typename ValueType>
|
||
|
void Set<ValueType>::remove(const ValueType & value) {
|
||
|
map.remove(value);
|
||
|
}
|
||
|
|
||
|
template <typename ValueType>
|
||
|
bool Set<ValueType>::contains(const ValueType & value) const {
|
||
|
return map.containsKey(value);
|
||
|
}
|
||
|
|
||
|
template <typename ValueType>
|
||
|
void Set<ValueType>::clear() {
|
||
|
map.clear();
|
||
|
}
|
||
|
|
||
|
template <typename ValueType>
|
||
|
bool Set<ValueType>::isSubsetOf(const Set & set2) const {
|
||
|
iterator it = begin();
|
||
|
iterator end = this->end();
|
||
|
while (it != end) {
|
||
|
if (!set2.map.containsKey(*it)) return false;
|
||
|
++it;
|
||
|
}
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Implementation notes: set operators
|
||
|
* -----------------------------------
|
||
|
* The implementations for the set operators use iteration to walk
|
||
|
* over the elements in one or both sets.
|
||
|
*/
|
||
|
|
||
|
template <typename ValueType>
|
||
|
bool Set<ValueType>::operator==(const Set & set2) const {
|
||
|
if (size() != set2.map.size()) return false;
|
||
|
iterator it1 = begin();
|
||
|
iterator it2 = set2.map.begin();
|
||
|
iterator end = this->end();
|
||
|
while (it1 != end) {
|
||
|
if (map.compareKeys(*it1, *it2) != 0) return false;
|
||
|
++it1;
|
||
|
++it2;
|
||
|
}
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
template <typename ValueType>
|
||
|
bool Set<ValueType>::operator!=(const Set & set2) const {
|
||
|
return !(*this == set2);
|
||
|
}
|
||
|
|
||
|
template <typename ValueType>
|
||
|
Set<ValueType> Set<ValueType>::operator+(const Set & set2) const {
|
||
|
Set<ValueType> set = *this;
|
||
|
foreach (ValueType value in set2) {
|
||
|
set.add(value);
|
||
|
}
|
||
|
return set;
|
||
|
}
|
||
|
|
||
|
template <typename ValueType>
|
||
|
Set<ValueType> Set<ValueType>::operator+(const ValueType & element) const {
|
||
|
Set<ValueType> set = *this;
|
||
|
set.add(element);
|
||
|
return set;
|
||
|
}
|
||
|
|
||
|
template <typename ValueType>
|
||
|
Set<ValueType> Set<ValueType>::operator*(const Set & set2) const {
|
||
|
Set<ValueType> set = *this;
|
||
|
set.clear();
|
||
|
foreach (ValueType value in *this) {
|
||
|
if (set2.contains(value)) set.add(value);
|
||
|
}
|
||
|
return set;
|
||
|
}
|
||
|
|
||
|
template <typename ValueType>
|
||
|
Set<ValueType> Set<ValueType>::operator-(const Set & set2) const {
|
||
|
Set<ValueType> set = *this;
|
||
|
foreach (ValueType value in set2) {
|
||
|
set.remove(value);
|
||
|
}
|
||
|
return set;
|
||
|
}
|
||
|
|
||
|
template <typename ValueType>
|
||
|
Set<ValueType> Set<ValueType>::operator-(const ValueType & element) const {
|
||
|
Set<ValueType> set = *this;
|
||
|
set.remove(element);
|
||
|
return set;
|
||
|
}
|
||
|
|
||
|
template <typename ValueType>
|
||
|
Set<ValueType> & Set<ValueType>::operator+=(const Set & set2) {
|
||
|
foreach (ValueType value in set2) {
|
||
|
this->add(value);
|
||
|
}
|
||
|
return *this;
|
||
|
}
|
||
|
|
||
|
template <typename ValueType>
|
||
|
Set<ValueType> & Set<ValueType>::operator+=(const ValueType & value) {
|
||
|
this->add(value);
|
||
|
this->removeFlag = false;
|
||
|
return *this;
|
||
|
}
|
||
|
|
||
|
template <typename ValueType>
|
||
|
Set<ValueType> & Set<ValueType>::operator*=(const Set & set2) {
|
||
|
Vector<ValueType> toRemove;
|
||
|
foreach (ValueType value in *this) {
|
||
|
if (!set2.map.containsKey(value)) toRemove.add(value);
|
||
|
}
|
||
|
foreach (ValueType value in toRemove) {
|
||
|
this->remove(value);
|
||
|
}
|
||
|
return *this;
|
||
|
}
|
||
|
|
||
|
template <typename ValueType>
|
||
|
Set<ValueType> & Set<ValueType>::operator-=(const Set & set2) {
|
||
|
Vector<ValueType> toRemove;
|
||
|
foreach (ValueType value in *this) {
|
||
|
if (set2.map.containsKey(value)) toRemove.add(value);
|
||
|
}
|
||
|
foreach (ValueType value in toRemove) {
|
||
|
this->remove(value);
|
||
|
}
|
||
|
return *this;
|
||
|
}
|
||
|
|
||
|
template <typename ValueType>
|
||
|
Set<ValueType> & Set<ValueType>::operator-=(const ValueType & value) {
|
||
|
this->remove(value);
|
||
|
this->removeFlag = true;
|
||
|
return *this;
|
||
|
}
|
||
|
|
||
|
template <typename ValueType>
|
||
|
ValueType Set<ValueType>::first() const {
|
||
|
if (isEmpty()) error("first: set is empty");
|
||
|
return *begin();
|
||
|
}
|
||
|
|
||
|
template <typename ValueType>
|
||
|
std::string Set<ValueType>::toString() {
|
||
|
ostringstream os;
|
||
|
os << *this;
|
||
|
return os.str();
|
||
|
}
|
||
|
|
||
|
template <typename ValueType>
|
||
|
void Set<ValueType>::mapAll(void (*fn)(ValueType)) const {
|
||
|
map.mapAll(fn);
|
||
|
}
|
||
|
|
||
|
template <typename ValueType>
|
||
|
void Set<ValueType>::mapAll(void (*fn)(const ValueType &)) const {
|
||
|
map.mapAll(fn);
|
||
|
}
|
||
|
|
||
|
template <typename ValueType>
|
||
|
template <typename FunctorType>
|
||
|
void Set<ValueType>::mapAll(FunctorType fn) const {
|
||
|
map.mapAll(fn);
|
||
|
}
|
||
|
|
||
|
template <typename ValueType>
|
||
|
std::ostream & operator<<(std::ostream & os, const Set<ValueType> & set) {
|
||
|
os << "{";
|
||
|
bool started = false;
|
||
|
foreach (ValueType value in set) {
|
||
|
if (started) os << ", ";
|
||
|
writeGenericValue(os, value, true);
|
||
|
started = true;
|
||
|
}
|
||
|
os << "}";
|
||
|
return os;
|
||
|
}
|
||
|
|
||
|
template <typename ValueType>
|
||
|
std::istream & operator>>(std::istream & is, Set<ValueType> & set) {
|
||
|
char ch;
|
||
|
is >> ch;
|
||
|
if (ch != '{') error("operator >>: Missing {");
|
||
|
set.clear();
|
||
|
is >> ch;
|
||
|
if (ch != '}') {
|
||
|
is.unget();
|
||
|
while (true) {
|
||
|
ValueType value;
|
||
|
readGenericValue(is, value);
|
||
|
set += value;
|
||
|
is >> ch;
|
||
|
if (ch == '}') break;
|
||
|
if (ch != ',') {
|
||
|
error(std::string("operator >>: Unexpected character ") + ch);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return is;
|
||
|
}
|
||
|
|
||
|
// hashing functions for sets; defined in hashmap.cpp
|
||
|
int hashCode(const Set<std::string>& s);
|
||
|
int hashCode(const Set<int>& s);
|
||
|
int hashCode(const Set<char>& s);
|
||
|
int hashCode(const Set<long>& s);
|
||
|
int hashCode(const Set<double>& s);
|
||
|
|
||
|
#endif
|