-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathhash_table.py
More file actions
139 lines (107 loc) · 3.65 KB
/
hash_table.py
File metadata and controls
139 lines (107 loc) · 3.65 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
"""
Hash Table (Hash Map) Data Structure
A hash table is a data structure that implements an associative array,
mapping keys to values using a hash function to compute an index.
Time Complexity (average case):
- Insertion: O(1)
- Deletion: O(1)
- Search: O(1)
Time Complexity (worst case): O(n) - when all keys hash to same bucket
Space Complexity: O(n)
Note: Uses chaining to handle collisions.
"""
class HashTable:
"""Hash table implementation using chaining for collision resolution."""
def __init__(self, capacity=10):
"""
Initialize hash table.
Args:
capacity: Initial capacity of the hash table
"""
self.capacity = capacity
self.size = 0
self.buckets = [[] for _ in range(capacity)]
def _hash(self, key):
"""Compute hash value for a key."""
if isinstance(key, int):
return key % self.capacity
# For string keys, use sum of character codes
return sum(ord(c) for c in str(key)) % self.capacity
def insert(self, key, value):
"""Insert or update key-value pair."""
index = self._hash(key)
bucket = self.buckets[index]
# Check if key already exists
for i, (k, v) in enumerate(bucket):
if k == key:
bucket[i] = (key, value)
return
# Add new key-value pair
bucket.append((key, value))
self.size += 1
# Resize if load factor > 0.7
if self.size > self.capacity * 0.7:
self._resize()
def get(self, key):
"""Get value for a key."""
index = self._hash(key)
bucket = self.buckets[index]
for k, v in bucket:
if k == key:
return v
raise KeyError(f"Key '{key}' not found")
def delete(self, key):
"""Delete key-value pair."""
index = self._hash(key)
bucket = self.buckets[index]
for i, (k, v) in enumerate(bucket):
if k == key:
bucket.pop(i)
self.size -= 1
return True
return False
def contains(self, key):
"""Check if key exists."""
try:
self.get(key)
return True
except KeyError:
return False
def _resize(self):
"""Resize hash table when load factor is too high."""
old_buckets = self.buckets
self.capacity *= 2
self.buckets = [[] for _ in range(self.capacity)]
self.size = 0
# Rehash all elements
for bucket in old_buckets:
for key, value in bucket:
self.insert(key, value)
def __len__(self):
"""Return number of key-value pairs."""
return self.size
def __str__(self):
"""String representation."""
items = []
for bucket in self.buckets:
for key, value in bucket:
items.append(f"{key}: {value}")
return "{" + ", ".join(items) + "}"
# Example usage
if __name__ == "__main__":
ht = HashTable()
print("Inserting key-value pairs:")
ht.insert("apple", 5)
ht.insert("banana", 3)
ht.insert("cherry", 8)
print(f" {ht}")
print(f" Size: {len(ht)}")
print("\nGetting values:")
print(f" apple: {ht.get('apple')}")
print(f" banana: {ht.get('banana')}")
print(f"\nContains 'cherry': {ht.contains('cherry')}")
print(f"Contains 'date': {ht.contains('date')}")
print("\nDeleting 'banana':")
ht.delete("banana")
print(f" {ht}")
print(f" Size: {len(ht)}")