Skip to content

Commit 1ad136c

Browse files
authored
Update HashTable.rb
1 parent 75853cd commit 1ad136c

File tree

1 file changed

+131
-170
lines changed

1 file changed

+131
-170
lines changed

HashTable.rb

+131-170
Original file line numberDiff line numberDiff line change
@@ -1,46 +1,135 @@
1-
# File: LinkedLists.rb
2-
#
3-
# Author: Sasha Goldenson
4-
#
5-
# License: Free to use
6-
#
7-
# Inspiration: Ron Tsui's (https://github.com/vokoshyv) excellent technical guidance has been very helpful in my understanding of these fundamentals.
8-
#
9-
# Motivation: Continuing my education, solidifying my fundamentals. Spreading the love.
10-
#
11-
# Hash Tables (AKA Hash Maps, Dictionaries, Hashes) are associative arrays of key-value storage. We're going to implement one using an array,
12-
# and build the hash table by populating that array with our key-value pairs.
13-
#
14-
# We'll need some properties and methods to describe and manipulate our Hash Table, namely:
15-
#
16-
# Properities: storage, buckets, size
17-
#
18-
# - Storage is our stored data, and will be represented by an array (of arrays, when populated.)
19-
#
20-
# - Buckets is the number of slots we have to store key-value pairs within storage. This number is variable, depending on storage contents. We'll
21-
# start our Hash Table by initializing it to 8.
22-
#
23-
# - Size is the number of key-value pairs we're currently storing in Storage.
24-
#
25-
# Methods: hash, insert, delete, retrieve, and resize
26-
#
27-
# - Hash is a method which takes the key to insert and the number of buckets, and evaluates it to the index which we'll insert into. There are many
28-
# different hashing methods, and we'll use the one provided here.
29-
#
30-
# - Insert(key, value), Delete(key), and Retrieve(key) methods are self-explanatory.
31-
#
32-
# - Resize is used when we need to increase the number of buckets our Hash Table has. If we wanted to double the number of buckets,
33-
# we would also have to reevaluate the data stored and assign them to their new buckets. The rule is when our size
34-
# (number of stored key-value pairs) exceeds 75% of the number of buckets, we'll double our number of buckets, and on the other side, we'll halve
35-
# the number of buckets when the number of stored key-value pairs drop below 25%.
36-
#
37-
# The handling of data collisions, when two different key-value to store hash to the same index, requires a separate chaining strategy.
38-
# Our separate chaining strategy is that we'll use an array in each location we store tuples, so we can store more than one key-value pairs which
39-
# hash to the same index.
40-
#
41-
##########
1+
###############
2+
# HashTable class
3+
###############
4+
5+
class HashTable
6+
7+
attr_accessor :storage, :buckets, :size, :resizing
8+
9+
def initialize
10+
@storage = []
11+
@buckets = 8
12+
@size = 0
13+
@resizing = false
14+
end
15+
16+
def hash(str)
17+
hash = 5381
18+
19+
str.split("").each do |i|
20+
char = i
21+
hash = ((hash << 5) + hash) + char.ord
22+
end
23+
return hash % self.buckets
24+
end
25+
26+
def insert(key, value)
27+
bucket_index = self.hash(key)
28+
if self.storage[bucket_index] == nil
29+
self.storage[bucket_index] = []
30+
self.storage[bucket_index].push([key, value])
31+
self.size += 1
32+
self.resize
33+
else
34+
bucket = self.storage[bucket_index]
35+
36+
bucket.length.times do |counter|
37+
if bucket[counter][0] == key
38+
bucket[counter][1] = value
39+
end
40+
end
41+
42+
bucket.push([key, value])
43+
self.size += 1
44+
self.resize
45+
end
46+
end
47+
48+
def delete(key)
49+
bucket_index = self.hash(key)
50+
51+
if self.storage[bucket_index] == nil
52+
return "Key: '#{key}' not found."
53+
else
54+
bucket = self.storage[bucket_index]
55+
bucket.length.times do |counter|
56+
if bucket[counter][0] == key
57+
temp = bucket[counter][1]
58+
bucket.delete_at(counter)
59+
self.resize
60+
self.size -= 1
61+
return "key-value: [#{key}][#{temp}] was deleted."
62+
end
63+
end
64+
return "This key was not found: '#{key}'"
65+
end
66+
end
67+
68+
def retrieve(key)
69+
bucket_index = self.hash(key)
70+
71+
if self.storage[bucket_index] == nil
72+
return false
73+
else
74+
bucket = self.storage[bucket_index]
75+
bucket.length.times do |counter|
76+
if bucket[counter][0] == key
77+
return true
78+
end
79+
end
80+
end
81+
end
82+
83+
def resize
84+
allElements = []
85+
if self.size > (0.75 * self.buckets) && (self.resizing == false)
86+
self.resizing = true
87+
self.storage.each do |bucket|
88+
if bucket != nil
89+
bucket.each do |tuple|
90+
allElements.push(tuple)
91+
end
92+
end
93+
end
94+
95+
self.storage = []
96+
self.size = 0
97+
self.buckets = (self.buckets * 2)
98+
99+
allElements.each do |tuple|
100+
self.insert(tuple[0], tuple[1])
101+
end
102+
self.resizing = false
103+
return 'HashTable number of buckets has been doubled.'
104+
# We don't want our buckets to go below 8 buckets minimum
105+
elsif (self.size < (0.25 * self.buckets)) && self.buckets >= 9.0 && (self.resizing == false)
106+
self.resizing = true
107+
self.storage.each do |bucket|
108+
if bucket != nil
109+
bucket.each do |tuple|
110+
allElements.push(tuple)
111+
end
112+
end
113+
end
114+
115+
self.storage = []
116+
self.size = 0
117+
self.buckets = (self.buckets * 0.5)
118+
119+
allElements.each do |tuple|
120+
self.insert(tuple[0], tuple[1])
121+
end
122+
123+
self.resizing = false
124+
return 'HashTable number of buckets have been halved.'
125+
end
126+
end
127+
128+
end
129+
130+
############
42131
# Unit Tests
43-
##########
132+
############
44133

45134
require 'test/unit'
46135

@@ -204,131 +293,3 @@ def test_hash_table_resize_should_halve_the_number_of_buckets_when_the_size_drop
204293
assert_equal(8, test.buckets)
205294
end
206295
end
207-
###############
208-
# HashTable class
209-
###############
210-
211-
class HashTable
212-
213-
attr_accessor :storage, :buckets, :size, :resizing
214-
215-
def initialize
216-
@storage = []
217-
@buckets = 8
218-
@size = 0
219-
@resizing = false
220-
end
221-
222-
def hash(str)
223-
hash = 5381
224-
225-
str.split("").each do |i|
226-
char = i
227-
hash = ((hash << 5) + hash) + char.ord
228-
end
229-
return hash % self.buckets
230-
end
231-
232-
def insert(key, value)
233-
bucket_index = self.hash(key)
234-
if self.storage[bucket_index] == nil
235-
self.storage[bucket_index] = []
236-
self.storage[bucket_index].push([key, value])
237-
self.size += 1
238-
self.resize
239-
else
240-
bucket = self.storage[bucket_index]
241-
242-
bucket.length.times do |counter|
243-
if bucket[counter][0] == key
244-
bucket[counter][1] = value
245-
end
246-
end
247-
248-
bucket.push([key, value])
249-
self.size += 1
250-
self.resize
251-
end
252-
end
253-
254-
def delete(key)
255-
bucket_index = self.hash(key)
256-
257-
if self.storage[bucket_index] == nil
258-
return "Key: '#{key}' not found."
259-
else
260-
bucket = self.storage[bucket_index]
261-
bucket.length.times do |counter|
262-
if bucket[counter][0] == key
263-
temp = bucket[counter][1]
264-
bucket.delete_at(counter)
265-
self.resize
266-
self.size -= 1
267-
return "key-value: [#{key}][#{temp}] was deleted."
268-
end
269-
end
270-
return "This key was not found: '#{key}'"
271-
end
272-
end
273-
274-
def retrieve(key)
275-
bucket_index = self.hash(key)
276-
277-
if self.storage[bucket_index] == nil
278-
return false
279-
else
280-
bucket = self.storage[bucket_index]
281-
bucket.length.times do |counter|
282-
if bucket[counter][0] == key
283-
return true
284-
end
285-
end
286-
end
287-
end
288-
289-
def resize
290-
allElements = []
291-
if self.size > (0.75 * self.buckets) && (self.resizing == false)
292-
self.resizing = true
293-
self.storage.each do |bucket|
294-
if bucket != nil
295-
bucket.each do |tuple|
296-
allElements.push(tuple)
297-
end
298-
end
299-
end
300-
301-
self.storage = []
302-
self.size = 0
303-
self.buckets = (self.buckets * 2)
304-
305-
allElements.each do |tuple|
306-
self.insert(tuple[0], tuple[1])
307-
end
308-
self.resizing = false
309-
return 'HashTable number of buckets has been doubled.'
310-
# We don't want our buckets to go below 8 buckets minimum
311-
elsif (self.size < (0.25 * self.buckets)) && self.buckets >= 9.0 && (self.resizing == false)
312-
self.resizing = true
313-
self.storage.each do |bucket|
314-
if bucket != nil
315-
bucket.each do |tuple|
316-
allElements.push(tuple)
317-
end
318-
end
319-
end
320-
321-
self.storage = []
322-
self.size = 0
323-
self.buckets = (self.buckets * 0.5)
324-
325-
allElements.each do |tuple|
326-
self.insert(tuple[0], tuple[1])
327-
end
328-
329-
self.resizing = false
330-
return 'HashTable number of buckets have been halved.'
331-
end
332-
end
333-
334-
end

0 commit comments

Comments
 (0)