From 0819fc9b49a2d5cf8fe81f4c6ecf06c4d5a69462 Mon Sep 17 00:00:00 2001 From: CarlosETurcios Date: Tue, 27 Oct 2020 20:18:19 -0700 Subject: [PATCH 1/8] started project --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index f766a6189..b24233992 100644 --- a/README.md +++ b/README.md @@ -22,6 +22,7 @@ Task: Implement a basic hash table without collision resolution. You can test this with: + ``` python test_hashtable_no_collisions.py ``` From 0a97937ce435491afd92d34ddd8fbf68bdb435bc Mon Sep 17 00:00:00 2001 From: CarlosETurcios Date: Wed, 28 Oct 2020 21:12:07 -0700 Subject: [PATCH 2/8] rewatched videos time to code --- hashtable/hashtable.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/hashtable/hashtable.py b/hashtable/hashtable.py index 0205f0ba9..48b699db6 100644 --- a/hashtable/hashtable.py +++ b/hashtable/hashtable.py @@ -22,6 +22,10 @@ class HashTable: def __init__(self, capacity): # Your code here + self.capacity = capacity + + + def get_num_slots(self): @@ -44,6 +48,7 @@ def get_load_factor(self): Implement this. """ # Your code here + # dont do yet def fnv1(self, key): @@ -104,6 +109,7 @@ def get(self, key): Implement this. """ # Your code here + def resize(self, new_capacity): @@ -114,8 +120,9 @@ def resize(self, new_capacity): Implement this. """ # Your code here + # dont do yet - +hash_table = HashTable(100) if __name__ == "__main__": ht = HashTable(8) From cfdee4942181ba78e492192452b03e3f2dc9e878 Mon Sep 17 00:00:00 2001 From: CarlosETurcios Date: Thu, 29 Oct 2020 21:27:11 -0700 Subject: [PATCH 3/8] finished but couldnt get test to pass --- hashtable/hashtable.py | 49 +++++++++++++++++++++++++++++++++++++++--- 1 file changed, 46 insertions(+), 3 deletions(-) diff --git a/hashtable/hashtable.py b/hashtable/hashtable.py index 48b699db6..24becf893 100644 --- a/hashtable/hashtable.py +++ b/hashtable/hashtable.py @@ -22,7 +22,10 @@ class HashTable: def __init__(self, capacity): # Your code here - self.capacity = capacity + self.capacity = MIN_CAPACITY + self.size = 0 + self.table = [None] * self.capacity + @@ -39,6 +42,8 @@ def get_num_slots(self): Implement this. """ # Your code here + return self.capacity + def get_load_factor(self): @@ -59,6 +64,26 @@ def fnv1(self, key): """ # Your code here + # what is a FNV-1 Hash, 64 bit? + # Non-crytographic hash function created by Glenn Fowler, London Curt Noll, and Kiem-Phong Vo. + # Constatnts + # Start with an initail hash value + FNV_prime = 1099511628211 + offset_basis = 14695981039346656037 + key_of_data_bytes = key.encode() + + hash = offset_basis + for letter in key_of_data_bytes: + hash = hash * FNV_prime + # Use the XOR operator ^ between two values to perform bitwise "exclusive or" on their binary representations. When used between two integers, the XOR operator returns an integer. + hash = hash^letter + + return hash + + + + + def djb2(self, key): @@ -68,6 +93,7 @@ def djb2(self, key): Implement this, and/or FNV-1. """ # Your code here + def hash_index(self, key): @@ -75,8 +101,8 @@ def hash_index(self, key): Take an arbitrary key and return a valid integer index between within the storage capacity of the hash table. """ - #return self.fnv1(key) % self.capacity - return self.djb2(key) % self.capacity + return self.fnv1(key) % self.capacity + #return self.djb2(key) % self.capacity def put(self, key, value): """ @@ -87,6 +113,10 @@ def put(self, key, value): Implement this. """ # Your code here + hashed_string = self.hash_index(key) + idx = hashed_string % len(self.table) + self.table[idx] = value + def delete(self, key): @@ -98,6 +128,14 @@ def delete(self, key): Implement this. """ # Your code here + hashed_string = self.hash_index(key) + + if self.table[hashed_string]: + self.table[hashed_string] = None + else: + print(f'{key} not found ') + + def get(self, key): @@ -109,6 +147,11 @@ def get(self, key): Implement this. """ # Your code here + hashed_string = self.hash_index(key) + idx = hashed_string % len(self.table) + value = self.table[idx] + + return value if value else None From 519127aff3630d1e06626dc42e3b1ef58d7c386a Mon Sep 17 00:00:00 2001 From: CarlosETurcios Date: Thu, 29 Oct 2020 22:26:43 -0700 Subject: [PATCH 4/8] finished met mvp and test are passing --- README.md | 2 +- hashtable/hashtable.py | 16 +++++++++------- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index b24233992..c524b4970 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,7 @@ Task: Implement a basic hash table without collision resolution. 4. Implement the `put()`, `get()`, and `delete()` methods. You can test this with: - + ``` python test_hashtable_no_collisions.py diff --git a/hashtable/hashtable.py b/hashtable/hashtable.py index 24becf893..917fae716 100644 --- a/hashtable/hashtable.py +++ b/hashtable/hashtable.py @@ -22,7 +22,7 @@ class HashTable: def __init__(self, capacity): # Your code here - self.capacity = MIN_CAPACITY + self.capacity = capacity self.size = 0 self.table = [None] * self.capacity @@ -78,7 +78,7 @@ def fnv1(self, key): # Use the XOR operator ^ between two values to perform bitwise "exclusive or" on their binary representations. When used between two integers, the XOR operator returns an integer. hash = hash^letter - return hash + return hash @@ -114,8 +114,10 @@ def put(self, key, value): """ # Your code here hashed_string = self.hash_index(key) - idx = hashed_string % len(self.table) - self.table[idx] = value + + self.table[hashed_string] = value + + @@ -133,7 +135,7 @@ def delete(self, key): if self.table[hashed_string]: self.table[hashed_string] = None else: - print(f'{key} not found ') + print('key not found ') @@ -148,8 +150,8 @@ def get(self, key): """ # Your code here hashed_string = self.hash_index(key) - idx = hashed_string % len(self.table) - value = self.table[idx] + + value = self.table[hashed_string] return value if value else None From 3eadc87c3933083aa6eaab47ec6b5f6ed4dee65b Mon Sep 17 00:00:00 2001 From: CarlosETurcios Date: Fri, 30 Oct 2020 20:02:17 -0700 Subject: [PATCH 5/8] started on the project part2 --- hashtable/hashtable.py | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/hashtable/hashtable.py b/hashtable/hashtable.py index 917fae716..8e4bf2d1a 100644 --- a/hashtable/hashtable.py +++ b/hashtable/hashtable.py @@ -23,7 +23,7 @@ class HashTable: def __init__(self, capacity): # Your code here self.capacity = capacity - self.size = 0 + self.load = 0 self.table = [None] * self.capacity @@ -114,9 +114,14 @@ def put(self, key, value): """ # Your code here hashed_string = self.hash_index(key) + + if self.table[hashed_string] != None: + print("warning collistion!!!") self.table[hashed_string] = value + self.load += 1 + @@ -131,11 +136,16 @@ def delete(self, key): """ # Your code here hashed_string = self.hash_index(key) - - if self.table[hashed_string]: - self.table[hashed_string] = None + if self.table == None: + print("warning no key!!") + else: - print('key not found ') + + self.table[hashed_string] = None + + self.load -= 1 + + From 517e9ae9c91e63c0a2df0f53f7fb4a3a281f360f Mon Sep 17 00:00:00 2001 From: CarlosETurcios Date: Wed, 4 Nov 2020 20:38:53 -0800 Subject: [PATCH 6/8] finished hash table --- hashtable/hashtable.py | 131 +++++++++++++++++++++++++++-------------- 1 file changed, 87 insertions(+), 44 deletions(-) diff --git a/hashtable/hashtable.py b/hashtable/hashtable.py index 8e4bf2d1a..853a3e617 100644 --- a/hashtable/hashtable.py +++ b/hashtable/hashtable.py @@ -2,6 +2,7 @@ class HashTableEntry: """ Linked List hash table key/value pair """ + def __init__(self, key, value): self.key = key self.value = value @@ -26,11 +27,6 @@ def __init__(self, capacity): self.load = 0 self.table = [None] * self.capacity - - - - - def get_num_slots(self): """ Return the length of the list you're using to hold the hash @@ -44,8 +40,6 @@ def get_num_slots(self): # Your code here return self.capacity - - def get_load_factor(self): """ Return the load factor for this hash table. @@ -53,8 +47,10 @@ def get_load_factor(self): Implement this. """ # Your code here - # dont do yet - + # dont do yet + # number of items divided by number of buckets + # try to keep between 20% and 70% + return self.load / self.capacity def fnv1(self, key): """ @@ -66,25 +62,19 @@ def fnv1(self, key): # Your code here # what is a FNV-1 Hash, 64 bit? # Non-crytographic hash function created by Glenn Fowler, London Curt Noll, and Kiem-Phong Vo. - # Constatnts - # Start with an initail hash value + # Constatnts + # Start with an initail hash value FNV_prime = 1099511628211 offset_basis = 14695981039346656037 key_of_data_bytes = key.encode() - hash = offset_basis + hash = offset_basis for letter in key_of_data_bytes: hash = hash * FNV_prime # Use the XOR operator ^ between two values to perform bitwise "exclusive or" on their binary representations. When used between two integers, the XOR operator returns an integer. - hash = hash^letter - - return hash - - - - - + hash = hash ^ letter + return hash def djb2(self, key): """ @@ -93,8 +83,6 @@ def djb2(self, key): Implement this, and/or FNV-1. """ # Your code here - - def hash_index(self, key): """ @@ -102,7 +90,7 @@ def hash_index(self, key): between within the storage capacity of the hash table. """ return self.fnv1(key) % self.capacity - #return self.djb2(key) % self.capacity + # return self.djb2(key) % self.capacity def put(self, key, value): """ @@ -113,18 +101,24 @@ def put(self, key, value): Implement this. """ # Your code here - hashed_string = self.hash_index(key) + # hashed_string = self.hash_index(key) - if self.table[hashed_string] != None: - print("warning collistion!!!") - - self.table[hashed_string] = value + # if self.table[hashed_string] != None: + # print("warning collistion!!!") - self.load += 1 - - + # self.table[hashed_string] = value + # self.load += 1 + hashed_string = self.hash_index(key) + new_node = HashTableEntry(key, value) + curr = self.table[hashed_string] + if self.table is not None: + self.table[hashed_string] = new_node + self.table[hashed_string].next = curr + else: + self.table = new_node + self.load += 1 def delete(self, key): """ @@ -135,20 +129,39 @@ def delete(self, key): Implement this. """ # Your code here + # hashed_string = self.hash_index(key) + # if self.table == None: + # print("warning no key!!") + + # else: + + # self.table[hashed_string] = None + + # self.load -= 1 hashed_string = self.hash_index(key) - if self.table == None: - print("warning no key!!") + removed = False - else: - - self.table[hashed_string] = None + if self.table[hashed_string].key == key: + self.table[hashed_string] = self.table[hashed_string].next + self.load -= 1 + removed = True - self.load -= 1 - - + else: + curr = self.table[hashed_string] + prev_node = None + while curr is not None: + if curr.key == key: + prev_node.next = curr.next + self.load -= 1 + removed = True + return + prev_node = curr + curr = curr.next + if removed == False: + print("warning no key!!") def get(self, key): """ @@ -159,13 +172,21 @@ def get(self, key): Implement this. """ # Your code here + + # hashed_string = self.hash_index(key) + + # value = self.table[hashed_string] + + # return value if value else None hashed_string = self.hash_index(key) - - value = self.table[hashed_string] + current_node = self.table[hashed_string] - return value if value else None - + while current_node is not None: + if current_node.key == key: + return current_node.value + current_node = current_node.next + return None def resize(self, new_capacity): """ @@ -175,7 +196,29 @@ def resize(self, new_capacity): Implement this. """ # Your code here - # dont do yet + # save your old storage in a new variable + # make a new storage , with new capacity + # then loop over your old starage + # for each index, if its not not + # iterate through the linked list + # for each node , call put for key and value + # that way, its rehashed and inserted to new storage + # self.load remain the same + # self.capacity + # + new_hashtable = HashTable(new_capacity) + + for i in range(self.capacity): + if self.table[i] is not None: + entry = self.table[i] + while entry: + new_hashtable.put(entry.key, entry.value) + entry = entry.next + + self.table = new_hashtable.table + self.capacity = new_capacity + self.load = new_hashtable.load + hash_table = HashTable(100) From d9ca0fed9051bf533b3b82b6ba12d701f87d51fb Mon Sep 17 00:00:00 2001 From: CarlosETurcios Date: Wed, 4 Nov 2020 20:40:09 -0800 Subject: [PATCH 7/8] started applications --- applications/crack_caesar/crack_caesar.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/applications/crack_caesar/crack_caesar.py b/applications/crack_caesar/crack_caesar.py index 1418f0ef3..08cc389af 100644 --- a/applications/crack_caesar/crack_caesar.py +++ b/applications/crack_caesar/crack_caesar.py @@ -1,5 +1,5 @@ # Use frequency analysis to find the key to ciphertext.txt, and then # decode it. -# Your code here +# Your code here From fad3d5011b47c14d524a9d0e6afe43227864b8f1 Mon Sep 17 00:00:00 2001 From: CarlosETurcios Date: Thu, 5 Nov 2020 19:40:24 -0800 Subject: [PATCH 8/8] started applictions --- applications/crack_caesar/crack_caesar.py | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/applications/crack_caesar/crack_caesar.py b/applications/crack_caesar/crack_caesar.py index 08cc389af..857376a63 100644 --- a/applications/crack_caesar/crack_caesar.py +++ b/applications/crack_caesar/crack_caesar.py @@ -3,3 +3,22 @@ # Your code here +# U - make a table with letter frequency in it ? +# use the table to iderate through the ciphertext.text +# the most fequent letter in the ciphertext will == the most common letter in the alphabel +# to create a new table of common code . + +# p +# E +# R +from csv import reader +with open("ciphertext.txt") as file: + csv_reader = reader(file) + for letter in csv_reader: + print(letter) + +text_letter = letter + + +def frequencyLetter(): + pass