From 3f8d737f68e991068c2f9f5a949c82470e5a98c1 Mon Sep 17 00:00:00 2001 From: Veto Ramirez Date: Thu, 29 Oct 2020 17:47:55 -0700 Subject: [PATCH 01/10] Push for retro' --- hashtable/hashtable.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/hashtable/hashtable.py b/hashtable/hashtable.py index 0205f0ba9..7acde6514 100644 --- a/hashtable/hashtable.py +++ b/hashtable/hashtable.py @@ -22,6 +22,8 @@ class HashTable: def __init__(self, capacity): # Your code here + self.capacity = 8 + self.arr = [none for i in range(self.capacity)] def get_num_slots(self): From 3734b9c3665852fe2710f73481300c9db9dfa77a Mon Sep 17 00:00:00 2001 From: Veto Ramirez Date: Sat, 31 Oct 2020 10:51:03 -0700 Subject: [PATCH 02/10] Created a linked list for chaining. --- hashtable/hashtable.py | 23 +++++++++++--- hashtable/linked_list.py | 65 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 84 insertions(+), 4 deletions(-) create mode 100644 hashtable/linked_list.py diff --git a/hashtable/hashtable.py b/hashtable/hashtable.py index 7acde6514..7996b5199 100644 --- a/hashtable/hashtable.py +++ b/hashtable/hashtable.py @@ -21,9 +21,12 @@ class HashTable: """ def __init__(self, capacity): - # Your code here - self.capacity = 8 - self.arr = [none for i in range(self.capacity)] + # self.table = [None] * capacity + # self.capacity = capacity + + self.table = [] * capacity + self.capacity = capacity + def get_num_slots(self): @@ -37,6 +40,7 @@ def get_num_slots(self): Implement this. """ # Your code here + return len(self.table) def get_load_factor(self): @@ -65,7 +69,10 @@ def djb2(self, key): Implement this, and/or FNV-1. """ # Your code here - + hash = 5381 + for x in key: + hash = ((hash << 5) + hash) + ord(x) + return hash & 0xFFFFFFFF def hash_index(self, key): """ @@ -84,6 +91,9 @@ def put(self, key, value): Implement this. """ # Your code here + # self.table[self.hash_index(key)] = value + + def delete(self, key): @@ -95,6 +105,10 @@ def delete(self, key): Implement this. """ # Your code here + value = self.table[self.hash_index(key)] + if value == None: + print('value is already None') + self.table[self.hash_index(key)] = None def get(self, key): @@ -106,6 +120,7 @@ def get(self, key): Implement this. """ # Your code here + return self.table[self.hash_index(key)] def resize(self, new_capacity): diff --git a/hashtable/linked_list.py b/hashtable/linked_list.py new file mode 100644 index 000000000..730ed2cfb --- /dev/null +++ b/hashtable/linked_list.py @@ -0,0 +1,65 @@ +class Node: + def __init__(self, value): + self.value = value + self.next = None + +class LinkedList: + def __init__(self): + self.head = None + + def __repr__(self): + currStr = "" + curr = self.head + while curr != None: + currStr += f'{str(curr.value)} ->' + curr = curr.next + return currStr + + # return node w/ value + # runtime: O(n) where n = number nodes + def find(self, value): + curr = self.head + while curr != None: + if curr.value == value: + return curr + curr = curr.next + return None + + # deletes node w/ given value then return that node + # runtime: O(n) where n = number of nodes + def delete(self, value): + curr = self.head + + # special case if we need to delete the head + if curr.value == value: + self.head = curr.next + curr.next = None + return curr + + prev = None + + while curr != None: + if curr.value == value: + prev.next = curr.next + curr.next = None + return curr + else: + prev = curr + curr = curr.next + + return None + + # insert node at head of list + # runtime: O(1) + def insert_at_head(self, node): + node.next = self.head + self.head = node + + # overwrite node or insert node at head + # runtime: O(n) + def insert_at_head_or_overwrite(self, node): + existingNode = self.find(node.value) # O(n) + if existingNode != None: + existingNode.value = node.value + else: + self.insert_at_head(node) # O(1) \ No newline at end of file From 28f7d6b6e3a797bd9050cbb905708a2772e3e30a Mon Sep 17 00:00:00 2001 From: Veto Ramirez Date: Sat, 31 Oct 2020 11:51:59 -0700 Subject: [PATCH 03/10] Added a add to tail function for the linked list. --- hashtable/hashtable.py | 9 ++++++++- hashtable/linked_list.py | 14 +++++++++++++- 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/hashtable/hashtable.py b/hashtable/hashtable.py index 7996b5199..484061432 100644 --- a/hashtable/hashtable.py +++ b/hashtable/hashtable.py @@ -1,3 +1,5 @@ +from linked_list import LinkedList + class HashTableEntry: """ Linked List hash table key/value pair @@ -93,7 +95,12 @@ def put(self, key, value): # Your code here # self.table[self.hash_index(key)] = value - + # h = self.hash_index(key) + for element in self.table: + if len(element) == 2 and element[0] == key: + self.table[key][value].add_to_tail() + else: + self.table[self.hash_index(key)] = value def delete(self, key): diff --git a/hashtable/linked_list.py b/hashtable/linked_list.py index 730ed2cfb..9962c22af 100644 --- a/hashtable/linked_list.py +++ b/hashtable/linked_list.py @@ -62,4 +62,16 @@ def insert_at_head_or_overwrite(self, node): if existingNode != None: existingNode.value = node.value else: - self.insert_at_head(node) # O(1) \ No newline at end of file + self.insert_at_head(node) # O(1) + + def add_to_tail(self, value): + # 0. create new node from value + new_node = Node(value, None) + # 1. check if list is empty + if not self.head: + # if list is empty, set both head and tail to new node + self.head = new_node + self.tail = new_node + else: + self.tail.set_next(new_node) + self.tail = new_node \ No newline at end of file From 924e26c4687b7d607f78aee4b5230ea2afac7e68 Mon Sep 17 00:00:00 2001 From: Veto Ramirez Date: Wed, 4 Nov 2020 20:28:38 -0800 Subject: [PATCH 04/10] Pushing for retro --- hashtable/hashtable.py | 111 +++++++++++++++++++++++++++++++++------ hashtable/linked_list.py | 26 ++++----- 2 files changed, 108 insertions(+), 29 deletions(-) diff --git a/hashtable/hashtable.py b/hashtable/hashtable.py index 484061432..6d8036158 100644 --- a/hashtable/hashtable.py +++ b/hashtable/hashtable.py @@ -1,3 +1,4 @@ +from linked_list import Node from linked_list import LinkedList class HashTableEntry: @@ -9,6 +10,11 @@ def __init__(self, key, value): self.value = value self.next = None + def __eq__(self, other): + if isinstance(other, HashTableEntry): + return self.key == other.keys + return False + # Hash table can't have fewer than this many slots MIN_CAPACITY = 8 @@ -26,9 +32,9 @@ def __init__(self, capacity): # self.table = [None] * capacity # self.capacity = capacity - self.table = [] * capacity + self.table = [None] * capacity self.capacity = capacity - + self.num_elements = 0 def get_num_slots(self): @@ -52,6 +58,8 @@ def get_load_factor(self): Implement this. """ # Your code here + # load factor = num of elements in the hash table / num slots + return self.num_elements / self.get_num_slots() def fnv1(self, key): @@ -62,8 +70,7 @@ def fnv1(self, key): """ # Your code here - - + def djb2(self, key): """ DJB2 hash, 32-bit @@ -95,12 +102,35 @@ def put(self, key, value): # Your code here # self.table[self.hash_index(key)] = value - # h = self.hash_index(key) - for element in self.table: - if len(element) == 2 and element[0] == key: - self.table[key][value].add_to_tail() - else: - self.table[self.hash_index(key)] = value + # index = self.hash_index(key) + # current_entry = self.table[index] + + # while current_entry is not None and current_entry.key != key: + # current_entry = current_entry.next + # if current_entry is not None: + # current_entry.value = value + # else: + # new_entry = HashTableEntry(key, value) + # new_entry.next = self.table[index] + # self.table[index] = new_entry + + # self.item_count += 1 + # if self.get_load_factor() > 0.7: + # self.resize(self.capacity * 2) + + hash_index = self.hash_index(key) + if self.table[hash_index] != None: + linked_list = self.table[hash_index] + did_add_new_node = linked_list.insert_at_head_or_overwrite(Node(HashTableEntry(key, value))) + if did_add_new_node: + self.num_elements += 1 + else: + linked_list = LinkedList() + linked_list.insert_at_head(Node(HashTableEntry(key, value))) + self.table[hash_index] = linked_list + self.num_elements += 1 + if self.get_load_factor() > 0.7: + self.resize(self.get_num_slots() * 2) def delete(self, key): @@ -112,10 +142,21 @@ def delete(self, key): Implement this. """ # Your code here - value = self.table[self.hash_index(key)] - if value == None: - print('value is already None') - self.table[self.hash_index(key)] = None + # value = self.table[self.hash_index(key)] + # if value == None: + # print('value is already None') + # self.table[self.hash_index(key)] = None + + hash_index = self.hash_index(key) + if self.table[hash_index] != None: + linked_list = self.table[hash_index] + did_delete_node = linked_list.delete(HashTableEntry(key, None)) + if did_delete_node != None: + self.num_elements -= 1 + if self.get_load_factor() < 0.2: + self.resize(self.get_num_slots() / 2) + else: + print("Warning: node not found") def get(self, key): @@ -127,7 +168,23 @@ def get(self, key): Implement this. """ # Your code here - return self.table[self.hash_index(key)] + # return self.table[self.hash_index(key)] + # index = self.hash_index(key) + + # current_entry = self.table[index] + + # while current_entry is not None: + # if(current_entry.key == key): + # return current_entry.value + # current_entry = current_entry.next + + hash_index = self.hash_index(key) + if self.table[hash_index] != None: + linked_list = self.table[hash_index] + node = linked_list.find(HashTableEntry(key, None)) + if node != None: + return node.value.value + return None def resize(self, new_capacity): @@ -137,8 +194,28 @@ def resize(self, new_capacity): Implement this. """ - # Your code here - + old_table = self.table + self.table = [None] * int(new_capacity) + self.num_elements = 0 + + for element in old_table: + if element is None: + continue + curr_node = element.head + while curr_node != None: + temp = curr_node.next + curr_node.next = None + hash_index = self.hash_index(curr_node.value.key) + + if self.table[hash_index] != None: + self.table[hash_index].insert_at_head(curr_node) + else: + linked_list = LinkedList() + linked_list.insert_at_head(curr_node) + self.table[hash_index] = linked_list + + curr_node = temp + self.num_elements += 1 if __name__ == "__main__": diff --git a/hashtable/linked_list.py b/hashtable/linked_list.py index 9962c22af..88e268713 100644 --- a/hashtable/linked_list.py +++ b/hashtable/linked_list.py @@ -28,24 +28,24 @@ def find(self, value): # deletes node w/ given value then return that node # runtime: O(n) where n = number of nodes def delete(self, value): - curr = self.head + cur = self.head # special case if we need to delete the head - if curr.value == value: - self.head = curr.next - curr.next = None - return curr + if cur.value == value: + self.head = cur.next + return cur prev = None + cur = cur.next - while curr != None: - if curr.value == value: - prev.next = curr.next - curr.next = None - return curr + while cur != None: + if cur.value == value: + prev.next = cur.next + cur.next = None + return cur else: - prev = curr - curr = curr.next + prev = cur + cur = cur.next return None @@ -61,8 +61,10 @@ def insert_at_head_or_overwrite(self, node): existingNode = self.find(node.value) # O(n) if existingNode != None: existingNode.value = node.value + return False else: self.insert_at_head(node) # O(1) + return True def add_to_tail(self, value): # 0. create new node from value From 133fef7bd3ed75861ae04da6eceb8d00ee4ca666 Mon Sep 17 00:00:00 2001 From: Veto Ramirez Date: Thu, 5 Nov 2020 20:01:02 -0800 Subject: [PATCH 05/10] Got hashtables to work --- hashtable/hashtable.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hashtable/hashtable.py b/hashtable/hashtable.py index 6d8036158..eaa1d2d25 100644 --- a/hashtable/hashtable.py +++ b/hashtable/hashtable.py @@ -12,7 +12,7 @@ def __init__(self, key, value): def __eq__(self, other): if isinstance(other, HashTableEntry): - return self.key == other.keys + return self.key == other.key return False From ad1f717ab54fcbe204119ebdb28ec2702a3cae4d Mon Sep 17 00:00:00 2001 From: Veto Ramirez Date: Thu, 5 Nov 2020 22:48:58 -0800 Subject: [PATCH 06/10] Still trying to work this out --- applications/lookup_table/lookup_table.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/applications/lookup_table/lookup_table.py b/applications/lookup_table/lookup_table.py index 05b7d37fa..91c2dbf88 100644 --- a/applications/lookup_table/lookup_table.py +++ b/applications/lookup_table/lookup_table.py @@ -1,5 +1,5 @@ # Your code here - +import random def slowfun_too_slow(x, y): v = math.pow(x, y) From 36835b976f41c38f5fad3c6664c7c326f55c5bfc Mon Sep 17 00:00:00 2001 From: Veto Ramirez Date: Fri, 6 Nov 2020 16:07:33 -0800 Subject: [PATCH 07/10] Erased code for lookup table. --- applications/lookup_table/lookup_table.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/applications/lookup_table/lookup_table.py b/applications/lookup_table/lookup_table.py index 91c2dbf88..5514b6106 100644 --- a/applications/lookup_table/lookup_table.py +++ b/applications/lookup_table/lookup_table.py @@ -9,13 +9,14 @@ def slowfun_too_slow(x, y): return v + def slowfun(x, y): """ Rewrite slowfun_too_slow() in here so that the program produces the same output, but completes quickly instead of taking ages to run. """ # Your code here - + # Do not modify below this line! From 4d7ebb2177ca048546a373f3d513f60551139fde Mon Sep 17 00:00:00 2001 From: Veto Ramirez Date: Fri, 6 Nov 2020 16:33:44 -0800 Subject: [PATCH 08/10] Not gettong itjk --- applications/lookup_table/lookup_table.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/applications/lookup_table/lookup_table.py b/applications/lookup_table/lookup_table.py index 5514b6106..122893483 100644 --- a/applications/lookup_table/lookup_table.py +++ b/applications/lookup_table/lookup_table.py @@ -1,22 +1,28 @@ # Your code here import random +prevV = {} + def slowfun_too_slow(x, y): v = math.pow(x, y) v = math.factorial(v) v //= (x + y) v %= 982451653 + prevV[x, y] = v return v - def slowfun(x, y): """ Rewrite slowfun_too_slow() in here so that the program produces the same output, but completes quickly instead of taking ages to run. """ # Your code here - + if x and y in prevV: + return prevV[x, y] + + else: + slowfun_too_slow(x, y) # Do not modify below this line! From ccfe40e1d0262fc7126f41fdf3e329043b04bd6c Mon Sep 17 00:00:00 2001 From: Veto Ramirez Date: Fri, 6 Nov 2020 18:22:16 -0800 Subject: [PATCH 09/10] Not passing all testes --- applications/expensive_seq/README.md | 3 +++ applications/expensive_seq/expensive_seq.py | 2 +- applications/word_count/word_count.py | 10 ++++++++++ 3 files changed, 14 insertions(+), 1 deletion(-) diff --git a/applications/expensive_seq/README.md b/applications/expensive_seq/README.md index 20ad36c17..78b7595af 100644 --- a/applications/expensive_seq/README.md +++ b/applications/expensive_seq/README.md @@ -25,5 +25,8 @@ ends. Hint: Va Clguba, n qvpg xrl pna or nal vzzhgnoyr glcr... vapyhqvat n ghcyr. +In Python, a dict key can be any immutable type... including a +tuple. + (That's encrypted with ROT13--Google `rot13 decoder` to decode it if you want the hint.) \ No newline at end of file diff --git a/applications/expensive_seq/expensive_seq.py b/applications/expensive_seq/expensive_seq.py index 5c82b8453..21e73009a 100644 --- a/applications/expensive_seq/expensive_seq.py +++ b/applications/expensive_seq/expensive_seq.py @@ -3,7 +3,7 @@ def expensive_seq(x, y, z): # Your code here - + if __name__ == "__main__": diff --git a/applications/word_count/word_count.py b/applications/word_count/word_count.py index a20546425..c3b433c6a 100644 --- a/applications/word_count/word_count.py +++ b/applications/word_count/word_count.py @@ -1,6 +1,16 @@ def word_count(s): # Your code here + counts = {} + words = s.lower() + lowerWords = words.split() + for word in lowerWords: + if word in counts: + counts[word] += 1 + else: + counts[word] = 1 + + return counts if __name__ == "__main__": From 7508da55fd5114b9ef023aea1d8ff363eddcf05f Mon Sep 17 00:00:00 2001 From: Veto Ramirez Date: Fri, 6 Nov 2020 19:31:53 -0800 Subject: [PATCH 10/10] i don't know --- applications/no_dups/no_dups.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/applications/no_dups/no_dups.py b/applications/no_dups/no_dups.py index caa162c8c..686cbe151 100644 --- a/applications/no_dups/no_dups.py +++ b/applications/no_dups/no_dups.py @@ -1,6 +1,6 @@ def no_dups(s): # Your code here - + pass if __name__ == "__main__":