5.8 Implementing the SetTo implement the Set ADT, we must select a data structure based on the same criteria we used for the Bag ADT from Section 2.2. Since we are trying to replicate the functionality of the set structure provided by Python, we don't want to use that structure. That leaves the array, list, and map containers for consideration in implementing the Set ADT. The storage requirements for the bag and set are very similar with the difference being that a set cannot contain duplicates. The map would seem to be the ideal choice since it can store unique items, but it would waste space in this case. Remember, the dictionary stores key/value pairs, which requires two data fields per entry. We could store the individual items of the set in the key fields and leave the value fields empty, but that would use twice the amount of storage than necessary. This waste does not occur with an array or list. An array could be used to implement the set, but a set can contain any number of elements and by definition an array has a fixed size. To use the array structure, we would have to manage the expansion of the array when necessary in the same fashion as is done for the list. Since the list can grow as needed, it seems ideal for storing the elements of a set just as it was for the bag and it does provide for the complete functionality of the ADT. Since the list allows for duplicate values, however, we must make sure as part of the implementation that no duplicates are added to our set. Sample instances for two sets representing the course schedules for two students is illustrated in Figure 5.8.1. The ConstructorThe definition of the class constructor for the Set ADT specifies the creation of an empty set. Thus, we must decide how to represent an empty set using the vector. The easiest approach is to represent an empty set with an empty vector as we did for the class Set : def __init__(self) : self._theElements = list() The def isEmpty(self) : return len(self._theElements) == 0 Set ContentsAs with the def __len__(self) : return len(self._theElements) The definition of the Set ADT explicitly indicates that the elements added to the set must be comparable. That is, we must be able to use any of Python's relational operators to compare two elements in the set. Since the elements must be comparable, we can use the def __contains__(self, element) : return element in self._theElements Adding ElementsAs indicated earlier, we must ensure that duplicate values are not added to set since the list structure does not handle this for us. When implementing the add method, we must first determine if the supplied def add(self, element) : if element not in self : self._theElements.append( element ) If the Removing ElementsThe definition of the def remove(self, element) : assert element in self, "The element must be in the set." self._theElements.remove( item ) The implementation of the Comparing Two SetsFor the operations that require a second set as an argument, we can use the operations of the Set ADT itself to access and manipulate the data of the second set. Consider the subset operation. To determine if one set is the subset of another, we can iterate over the list of elements in the def isSubsetOf(self, setB) : for element in self._theElements : if element not in setB : return False return True To determine if two sets contain the exact same elements, we first check to make sure the two sets contain the same number of elements; otherwise, by definition they cannot be equal. It would be inefficient to compare the individual elements since we already know the two sets cannot be equal. After verifying the size of the lists, we can test to see if the def __eq__(self, setB) : if len(self) != len(setB) : return False else : return self.isSubsetOf(setB)
The Set UnionSome of the operations create and return a new set based on the original, but the original is not modified. This is accomplished by creating a new set and populating it with the appropriate data from the other sets. Consider the def union(self, setB) : newSet = Set() newSet._theElements.extend(self._theElements) for element in setB._theElements : if element not in self : newSet._theElements.append(element) return newSet Creating a new set, populated with the unique elements of the other two sets, requires three steps:
For the first step, we simply create a new instance of the The unique elements are added to the Program ListingThe implementation of the Set ADT using a Python list to store and manage the elements is provided in the listing below Program Listing
|