CS 261 - HashMap

HashMap Implementation
Overview
This project implements two types of hash maps: Separate Chaining HashMap and Open Addressing HashMap. These data structures are used to store key-value pairs and provide efficient operations for insertion, deletion, and lookup.
Key Concepts
Dynamic Array
The DynamicArray
class is a custom implementation of a dynamic array that supports the following methods:
append(value)
: Adds a new element at the end of the array.pop()
: Removes and returns the element from the end of the array.swap(i, j)
: Swaps the elements at indicesi
andj
.get_at_index(index)
: Returns the value at the specified index.set_at_index(index, value)
: Sets the value at the specified index.length()
: Returns the length of the array.
Hash Functions
Two hash functions are provided to compute the hash value of a given key:
hash_function_1(key)
: Computes the hash value by summing the ASCII values of the characters in the key.hash_function_2(key)
: Computes the hash value by summing the product of the character’s ASCII value and its position in the key.
Separate Chaining HashMap
The HashMap
class in hash_map_sc.py
implements a hash map using separate chaining for collision resolution. Key concepts include:
- Buckets: Each bucket is a linked list that stores key-value pairs.
- Insertion: New key-value pairs are inserted into the appropriate bucket based on the hash value of the key.
- Collision Resolution: Collisions are resolved by adding the new key-value pair to the linked list at the corresponding bucket.
- Resizing: The hash map is resized when the load factor exceeds a certain threshold to maintain efficient operations.
Open Addressing HashMap
The HashMap
class in hash_map_oa.py
implements a hash map using open addressing with quadratic probing for collision resolution. Key concepts include:
- Buckets: Each bucket stores a single key-value pair or a tombstone indicating a deleted entry.
- Insertion: New key-value pairs are inserted into the appropriate bucket based on the hash value of the key. Quadratic probing is used to find an empty bucket in case of collisions.
- Collision Resolution: Collisions are resolved by probing the next available bucket using a quadratic function.
- Resizing: The hash map is resized when the load factor exceeds a certain threshold to maintain efficient operations.
Linked List
The LinkedList
class is used in the separate chaining hash map to store key-value pairs in each bucket. Key methods include:
insert(key, value)
: Inserts a new node with the given key and value at the front of the list.remove(key)
: Removes the node with the specified key from the list.contains(key)
: Checks if a node with the specified key exists in the list.length()
: Returns the length of the list.
Hash Entry
The HashEntry
class is used in the open addressing hash map to store key-value pairs. Each entry also has a is_tombstone
attribute to indicate if the entry has been logically deleted.
Usage
The hash maps can be used to store and retrieve key-value pairs efficiently. The provided test cases in the if __name__ == "__main__":
block demonstrate the usage of various methods and functionalities of the hash maps.
Conclusion
This project demonstrates the implementation of hash maps using two different collision resolution techniques: separate chaining and open addressing. The key concepts and data structures used in this project provide a solid foundation for understanding hash maps and their operations.