# Hash Table Based Sets

In this section, we walk through the pseudocode for some basic set operations built on our hash table class above. In this new version of the set class, we declare `mySet`

as a hash table and use that throughout our operations.

`mySet = new HashTable()`

When using a hash table to implement sets, one of the most important choices we must make is what to use for a key. This is really difficult in the case of sets since we do not know exactly what types of objects may be put into the set. Our only real option at this point is just to use the entire object as our key. Our choice to use a default hash function in our hash table turns out to be a good one (at least in modern languages such as Python, Java, and C#), since most default hash functions work on any type of objects.

Next, we discuss the implementation of the important set operations using hash tables.

## Contains

The `contains`

operation is straightforward since we are using the entire object as the key. We simply return the value from the hash table `containsKey`

operation, which performs the exact function we need.

```
function contains(object o) returns boolean
return mySet.containsKey(o)
end function
```

## Add

The `add`

operation maps almost exactly to the hash table `put`

operation except that the `put`

operation does not return a boolean value. So, we first check to see if the key is already contained in the hash table. If so, we just return `false`

, since we don’t need to add the value to the set. Otherwise, we add a new tuple to the hash table, and then return `true`

.

```
function add(object o) returns boolean
if mySet.containsKey(o)
return false
end if
mySet.put(o, o)
return true
end function
```

## Remove

The set `remove`

operation maps almost exactly to the hash table `remove`

operation, so we just call it and then check to see if the result is not null. If it is null, we will return `false`

since the element was not in the set; otherwise we return `true`

.

```
function remove(object o) returns boolean
return mySet.remove(o) != null
end function
```

## Intersection

The `intersection`

operation creates a new set that has only elements which exist in both sets under consideration. In code, we basically accomplish this by looping through the elements in one set and then checking to see if they exist in the other set. If they do, then we include them in the intersection.

The pseudocode follows that basic algorithm using the hash table iterator to loop through and look at each element in `set1`

. We start by creating a new set, `result,`

to hold the intersection of `set1`

and `set2`

in line 2. Then we get the first element pair from `set1`

by calling the hash table `reset`

operation in line 2 and the `getNext`

operation in line 3.

```
1function intersection(set1, set2) returns set
2 result = new Set()
3
4 set1.reset()
5 current = set1.getNext()
6 while current != null
7 if set2.contains(current.getKey())
8 result.add(current.getKey())
9 end if
10 current = set1.getNext()
11 end while
12
13 return result
14end function
```

Lines 6 - 10 implement the loop that walks through each element in `set1`

. If the current element is contained in `set2`

(line 7), the operation calls the `add`

operation to insert the key of the `current`

element into the `result`

set. Line 10 gets the next element from `set1`

and loops back to the top.
Eventually, we look at each element in `set1`

and fall out of the loop. When that happens, the intersection operation is complete, and it returns the `result`

set in line 13.

## Union

The `union`

operation is similar to the `intersection`

operation in that we need to use the hash table iterator operations to walk through our sets. The difference lies in what we include in the new `result`

set. While we only walked through `set1`

in the `intersection`

operation, picking only those objects that existed in `set2`

, here we start by copying all elements from `set2`

into the `result`

set and then walk through `set1`

adding each of its elements to the `result`

set as well. (Here we don’t need to worry about adding duplicates since the `add`

operation takes care of that for us.)

The code starts in line 2 by making a `copy`

of `set2`

and assigning it to our new `result`

set. Then, lines 4 and 5 reset the `set1`

iterator and get the first item from `set1`

. Lines 6 - 8 form the `while`

loop that we use to walk through each element in `set1`

. This time, however, we simply add every element we find in line 7 before getting the next object in line 8. Once the loop exists we are done and we return the `result`

set in line 11.

```
1function union(set1, set2) returns set
2 result = set2.copy()
3
4 set1.reset()
5 current = set1.getNext()
6 while current != null
7 result.add(current.getKey())
8 current = set1.getNext()
9 end while
10
11 return result
12end function
```

## isSubset

The `isSubset`

operation below is very much like the `intersection`

operation above as we have a loop in lines 4 - 8 that checks each element of `set1`

and checks to see if it is in `set2`

. The difference between the two operations is that in the `isSubset`

operation, we do not build a third `result`

set. Instead, if any element in `set1`

is not found in `set2`

, then we return `false`

since not all elements of `set1`

are contained in `set2`

. If we get all the way through the loop, we have checked that each element in `set1`

was found in `set2`

and we can return `true`

; `set1`

is a subset of `set2`

.

```
1function isSubset (set1, set2) returns boolean
2 set1.reset()
3 current = set1.getNext()
4 while current != null
5 if set2.contains(current.getKey())
6 return false
7 end if
8 current = set1.getNext()
9 end while
10
11 return true
12end function
```