We can use complexity analysis to determine the efficiency of the Set ADT operations as implemented in the previous section. For convenience, the relevant portions of that implementation are shown again in the program listing below. The evaluation is quite simple since the ADT was implemented using the list and we just evaluated the methods for that structure. Table 5.9.1 provides a summary of the worst case time-complexities for the set operations implemented earlier in the chapter.
Operation | Worst Case |
---|
s = Set() |
|
len(s) |
|
x in s |
|
s.add(x) |
|
s.isSubsetOf(t) |
|
s == t |
|
s.union(t) |
|
traversal |
|
Table 5.9.1: Time-complexities for the Set ADT implementation from Section 5.9 using an unsorted list.
Listing of the Set ADT implementation. |
# Implementation of the Set ADT container using a Python list.
class Set :
# Creates an empty set instance.
def __init__(self) :
self._theElements = list()
# Returns the number of items in the set.
def __len__(self) :
return len(self._theElements)
# Returns True if the set is empty and False otherwise.
def isEmpty(self) :
return len(self._theElements) == 0
# Determines if an element is in the set.
def __contains__(self, element) :
return element in self._theElements
# Adds a new unique element to the set.
def add(self, element) :
if element not in self :
self._theElements.append( element )
# Removes an element from the set.
def remove(self, element) :
assert element in self, "The element must be in the set."
self._theElements.remove( item )
# Removes all of the elements from the set.
def clear(self) :
......
# Determines if two sets are equal.
def __eq__(self, setB) :
if len(self) != len(setB) :
return False
else :
return self.isSubsetOf(setB)
# Determines if this set is a subset of setB.
def isSubsetOf(self, setB) :
for element in self._theElements :
if element not in setB :
return False
return True
# Creates a new set from the union of this set and setB.
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
# Creates a new set from the intersection: self set and setB.
def interset( self, setB ):
......
# Creates a new set from the difference: self set and setB.
def difference( self, setB ):
......
# Returns an iterator for traversing the list of items.
def __iter__( self ):
return iter(self._theElements)
|
Simple Operations
set contains
set add
Evaluating the constructor and length operation is straightforward as they simply call the corresponding list operation. The __contains__
method, which determines if an element is contained in the set, uses the in
operator to perform a linear search over the elements stored in the underlying list. The search operation, which requires , will be presented in the next chapter and we postpone its analysis until that time. The add
method also requires time in the worst case since it uses the in
operator to determine if the element is unique and the append
method to add the unique item to the underlying list, both of
which require linear time in the worst case.
Operations of Two Sets
The remaining methods of the Set
class involve the use of two sets, which we label and , where is the self
set and is the argument passed to the given method. To simplify the analysis, we assume each set contains elements. A more complete analysis would involve the use of two variables, one for the size of each set. But the analysis of this more specific case is sufficient for our purposes.
set subset
set equals
The isSubsetOf
method determines if is a subset of . It iterates over the elements of set , during which the in
operator is used to determine if the given element is a member of set . Since there are repetitions of the loop and each use of the in
operator requires time, the isSubsetOf
method has a quadratic run time of . The set equality operation is also since it calls isSubsetOf
after determining the two sets are of equal size.
Set Union Operation
The set union
operation creates a new set, , that contains all of the unique elements from both sets and . It requires three steps.
- The first step creates the new set , which can be done in constant time.
- The second step fills set with the elements from set , which requires time since the
extend
list method is used to add the elements to set .
- The last step iterates over the elements of set during which the
in
operator is used to determine if the given element is a member of set . If the element is not a member of set , it's added to set by applying the append
list method. We know from earlier the linear search performed by the in
operator requires time and we can use the amortized cost of the append
method since it is applied in sequence. Given that the loop is performed times and each iteration requires time, this step requires time.
set union
Combining the times for the three steps yields a worst case time of .