Hashes are just a kind of Map, and such an important one that it deserves its own challenge. Hashes implement all the Map methods (set, get, etc.)
Hashes are fast. Inserting and retrieving records are both constant time (O(1)). In other words it will take the same amount of time to set and fetch from the hash table no matter how big it is. This is a wonderful property. In addition to providing a fast key:value collection, Hashes can be used to create Sets that can check membership in constant time.
Implement and test a MyHash
class, you can use Ruby's array on this one behind the scenes if you'd like.
Your Hash should only use Strings as keys. Don't worry about other types.
Since a Hash is a kind of Map, it has the same interface:
MyHash::new
: Instantiate a new dictionaryMyHash#set(key, value)
: Add a key-value pair. If the key is already present, replace the valueMyHash#get(key)
: Retrieve the value stored atkey
MyHash#has_key?(key)
: Answer where or not the dictionary has an entry forkey
MyHash#remove(key)
: Remove the entry stored atkey
MyHash#iterate{ |value, key| block }
: Iterate through the Hash, passing the block each value and key
Each of these methods (except iterate) should be O(1). Note that with a perfect hash function (every key maps to a unique number, there are no "collisions") access is always O(1). You might have a "pretty good" hash function that generates a few collisions. It might take longer that constant time, but it should still remain exceptionally fast as n
grows.
- What data structure have you used that provides constant-time reads and writes?
- How can you use that structure to your advantage?
- Read Wikipedia's entry on Hash Tables if you get stuck
- How will you produce a Hash Function for a String? Note: it doesn't need to be a perfect hash function, collisions are OK
Don't spend longer than 30 minutes on your hash function for String. You can look up various implementations online. It's best to pick the simplest one that makes sense to you, even if it's not perfect.
In a file called notes.md
, describe why Hash operations are so fast. What about them gives us these constant time methods? What are some downsides of a hash?
Implement and test a HashSet
class. Your HashSet should conform to the Set interface:
HashSet::new()
: Instantiate a new empty HashSet.HashSet#add(element)
: Add an element to the set (if necessary)HashSet#remove(element)
: Removeelement
from the set if it's presentHashSet#contains?(element)
: Answer whether or notelement
is in the setHashSet#iterate{ |element| block }
: Iterate through all of the elements of the receiverHashSet#size
: Return the size of the set
Make sure #add
, #remove
, #contains
, and #size
are constant time.