Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file not shown.
147 changes: 147 additions & 0 deletions data_structures_and_algorithms/challenges/hash_table/hash_table.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
from hashlib import md5
# from linked_list.linked_list import LinkedList

class LinkedList:
def __init__(self):
self.head = None
self.tail = None

self.length = 0

class Node:
def __init__(self, value):
self.value = value
self.next = None

def __repr__(self):
return f'{self.value}'

'''Adds node to head of linked list'''

def insert(self, value):
node = self.Node(value)
node.next = self.head
self.head = node
self.length += 1

'''Takes in a target value and iterates through Linked List
until the value is found, or the end of the list is reached
returns a boolean'''

def includes(self, value):
current = self.head

while current:
if current.value == value:
return True
current = current.next

return False

def __str__(self):
values = ''
current = self.head
while current:
values += f'Node: {str(current.value)} '
current = current.next
print(values)
return values

'''Iterates to the end of a Linked List and appends a value'''

def append(self, value):
new_node = self.Node(value)
if self.head == None:
self.head = new_node
return
last = self.head

while last.next:
last = last.next

last.next = new_node
self.length += 1

def find(self, value):

if self.head == None:
return None

currentNode = self.head

while not currentNode == None:

if currentNode.value == value:
return currentNode

currentNode = currentNode.next

return None

defaultHashTableSize = 32

class HashTable:

def __init__(self, hashTableSize = defaultHashTableSize):

self.buckets = [LinkedList() for x in range(0, hashTableSize)]

self.keys = {}


def add(self, key, value):

key_index = self.hash(key)
self.keys[key] = key_index

# refers to a Linked List in the bucket array, at the key index
bucket = self.buckets[key_index]

node = bucket.find({key: value})

if node == None: # the key doesn't exist
bucket.append({key: value})
else: # key already exists, add new value
node.value.value = value


def get(self, key):

bucket = self.buckets[self.hash(key)]

currentNode = bucket.head
while not currentNode == None:
for k in currentNode.value:
if k == key:
return currentNode.value[k]
currentNode = currentNode.next

print('key not found')
return None


def hash(self, key):
k = 0
# found via stack overflow, this converts the key to a string encoded to utf-8
# converts the string to a list of seperated vals
# loop through and convert each character into its code point integer
# and accumulate those values with k
for char in list(md5(str(key).encode('utf-8')).hexdigest()):
# ord returns an integer representing the unicode code point
k += ord(char)
# mod by the length of bucket list to obain hashed key
return k % len(self.buckets)


def contains(self, key):
if key in self.keys.keys():
print('key present')
return True
else:
print('key not found')
return False

if __name__ == "__main__":
ht = HashTable()
ht.add('testing', 72)
ht.contains('testing')
15 changes: 15 additions & 0 deletions data_structures_and_algorithms/challenges/hash_table/read.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
Hashtables
A hash table is a data structure that, in a way, combines arrays and linked lists. It has a big o of O(1) for time complexity(kinda) and a space complexity of O(n).

Challenge
Implement a Hash table with the following methods:

add: takes in both the key and value. This method should hash the key, and add the key and value pair to the table, handling collisions as needed. get: takes in the key and returns the value from the table. contains: takes in the key and returns a boolean, indicating if the key exists in the table already. hash: takes in an arbitrary key and returns an index in the collection.

Approach & Efficiency
I took JB's approach during lecture. Make a Hash table class that imports my Linked List class from another file. Add the necessary methods from there.



Tests
Adding a key/value to your hashtable results in the value being in the data structure Retrieving based on a key returns the value stored Successfully returns null for a key that does not exist in the hashtable Successfully handle a collision within the hashtable Successfully retrieve a value from a bucket within the hashtable that has a collision Successfully hash a key to an in-range value
Binary file not shown.
Binary file not shown.
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Stacks and Queues

we created a data structure called **Stack** and **Queue** in Python. We used three classes, _Node_ and _Queue_, and _Stack_.

### Challenge
- Write queue and stack classes with their methods

## Approach & Efficiency
Stack :
- Define a method called push
- Define a method called pop
- Define a method called peek

Queue:
- Define a method called enqueue
- Define a method called dequeue
- Define a method called peek big
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
class Node:
def __init__(self, value):
self.value = value
self.next = None

def __repr__(self):
return f'{self.value}'


class Stack:

def __init__(self):
'''initialize stack with top, bottom and length'''
self.top = None
self.bottom = None
self.length = 0

def isEmpty(self):
return self.top == None

def push(self, value):
'''adds new node to top of stack by pointing it to self.top'''
node = Node(value)
node.next = self.top
self.top = node
self.length += 1

def pop(self):
'''Takes item from top of stack and returns it by reassigning the current top
to the next item in the stack. Stores the value in a temp variable to be returned'''
if self.length <= 0:
print('nothing to pop')
return

temp = self.top
self.top = self.top.next
popped = temp.value
self.length -= 1
return popped

def peek(self):
'''prints and returns the top of the stack'''
if self.length <= 0:
print('nothing to peek')
return
print(self.top.value)
return self.top.value


class Queue:

def __init__(self):
'''initializes a queue instance'''
self.front = None
self.rear = None
self.length = 0

def isEmpty(self):
return self.front == None

def enqueue(self, value):
'''appends value to front of queue'''

self.length += 1
new_node = Node(value)

if self.rear == None:
self.front = self.rear = new_node

return

self.rear.next = new_node
self.rear = new_node

def dequeue(self):
'''removes value from front of queue, if length is zero it returns the queue
and prints a message'''
self.length -= 1

if self.isEmpty():
self.queue = []
print('queue is empty')
return self.queue

temp = self.front
self.front = temp.next

if self.front == None:
self.rear = None

return str(temp.value)

def peek(self):
'''returns the first value in a queue'''
return self.front.value
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
from stacks_and_queues import Node, Stack, Queue

def test_empty_stack():
test_stack = Stack()
assert isinstance(test_stack, Stack)

def test_push():
test_stack = Stack()
test_stack.push(1)
test_stack.push(2)
assert test_stack.top.value == 2

def test_muliple_nodes():
test_stack = Stack()
test_stack.push(1)
test_stack.push(2)
test_stack.push(3)
assert test_stack.length == 3

def test_pop():
test_stack = Stack()
test_stack.push(1)
test_stack.push(2)
test_stack.push(3)
popped = test_stack.pop()
assert popped == 3
assert test_stack.length == 2
assert test_stack.top.value == 2

def test_multipop():
test_stack = Stack()
test_stack.push(1)
test_stack.push(2)
test_stack.push(3)
test_stack.pop()
test_stack.pop()
test_stack.pop()
assert test_stack.length == 0
assert test_stack.bottom == None

def test_peek():
test_stack = Stack()
test_stack.push(1)
test_stack.push(2)
test_stack.push(3)

assert test_stack.peek() == 3

def test_enqueue():
q = Queue()
q.enqueue(1)
q.enqueue(2)
q.enqueue(3)

assert q.front.value == 1

def test_enqueue_multiple():
q = Queue()
q.enqueue(1)
q.enqueue(2)
q.enqueue(3)

assert q.length == 3

def test_dequeue():
q = Queue()
q.enqueue(1)
q.enqueue(2)
q.enqueue(3)
q.dequeue()

assert q.length == 2
assert q.front.value == 2

def test_enqueue_empty_queue():
q = Queue()
q.enqueue(1)
q.enqueue(2)
q.enqueue(3)
q.dequeue()
q.dequeue()
q.dequeue()

assert q.length == 0

def test_instantiate_empty():
q = Queue()

assert q.length == 0
assert q.front == None


def test_q_peek():
q = Queue()
q.enqueue(1)
q.enqueue(2)
q.enqueue(3)

assert q.peek() == 1
Binary file not shown.
Loading