class MyHashTable:
def __init__(self, capacity):
self.capacity = capacity
self.slots = [None] * self.capacity
def __str__(self):
return str(self.slots )
def __len__(self):
count = 0
for i in self.slots:
if i != None:
count += 1
return count
def hash_function(self, key):
slot = key % len(self.slots)
if key in self.slots:
return slot
elif (not key in self.slots) and len(self.slots) == self.capacity:
return slot
else:
for i in self.slots:
count = 0
if i == None:
return count
count += 1
def insert(self, key):
print(len(self.slots)) #Why does this show an output of 2?
if key in self.slots:
return -2
elif (not key in self.slots) and (len(self.slots) != self.capacity): #Now this cant execute
num = hash_function(key)
self.slots[num] = key
return num
elif (not key in self.slots) and len(self.slots) == self.capacity:
return -1
Im wondering why the commented part above in the insert(self, key) the print statement gives (2) instead of (0). The elif statement underneath wont execute since its giving a result of (2) instead of (0)
A function call of
x = MyHashTable(2)
print(len(x))
Should give: 0
You're initializing self.slots = [None] * self.capacity, so with capacity = 2, self.slots is [None, None], which is of length 2.
Your __len__ method doesn't run because len(self.slot) calls self.slot.__len__, not self.__len__. If you'd like to use your override method, you should be calling len(self) instead.
You have to call your __len__ function (by calling self.__len__() ) if you want the length of the elements which are not None. For lists None are valid entries.
By the way. It is always best to compare with None by a is None or a is not None instead of == or !=.
Related
class Algorithms:
class SearchAlgorithms:
class RecursiveBinarySearch:
def RecursiveBinarySearchAlgo(List, Target):
'''
Return true value if it exists and a false if it doesn't
'''
# If the length of the List is equal to 0 : return False
if len(List) == 0:
return False
# Else if the list is not empty
else:
Midpoint = (len(List))//2
# IF the Midpoint value within the list is equal to Target value: return true
if List[Midpoint] == Target:
return True
else:
if List[Midpoint] < Target:
return Algorithms.SearchAlgorithm.RecursiveBinarySearch.RecursiveBinarySearchAlgo(List[Midpoint + 1:], Target)
else:
return Algorithms.SearchAlgorithm.RecursiveBinarySearch.RecursiveBinarySearchAlgo(List[:Midpoint], Target)
def Verify(Result):
print("Target found: ", Result)
Numbers = [1,2,3,4,5,6,7,8]
# Test Cases 1
Result = RecursiveBinarySearchAlgo(Numbers, 12)
Verify(Result)
# Test Case 2
Result = RecursiveBinarySearchAlgo(Numbers, 5)
Verify(Result)
I am getting a name error that the class is not defined name 'Algorithms' is not defined.
I tried entering init function with each class with self. But I am still getting the same error
the program should result in:
Target found : True
target found: False
I don't know why within inner class we cannot call method directly, but as #juanpa.arrivillaga suggested moving to one level up and using an instance of inner class works in addition to self keyword on methods:
class Algorithms:
class SearchAlgorithms:
class RecursiveBinarySearch:
def RecursiveBinarySearchAlgo(self, List, Target):
'''
Return true value if it exists and a false if it doesn't
'''
# If the length of the List is equal to 0 : return False
if len(List) == 0:
return False
# Else if the list is not empty
else:
Midpoint = (len(List))//2
# IF the Midpoint value within the list is equal to Target value: return true
if List[Midpoint] == Target:
return True
else:
if List[Midpoint] < Target:
return self.RecursiveBinarySearchAlgo(List[Midpoint + 1:], Target)
else:
return self.RecursiveBinarySearchAlgo(List[:Midpoint], Target)
def Verify(self, Result):
print("Target found: ", Result)
rbs = RecursiveBinarySearch()
Numbers = [1,2,3,4,5,6,7,8]
# Test Cases 1
Result = rbs.RecursiveBinarySearchAlgo(Numbers, 12)
rbs.Verify(Result)
# Test Case 2
Result = rbs.RecursiveBinarySearchAlgo(Numbers, 5)
rbs.Verify(Result)
If you don't want to create an instance in that case you can use #classmethod annotation as well:
class Algorithms:
class SearchAlgorithms:
class RecursiveBinarySearch:
#classmethod
def RecursiveBinarySearchAlgo(cls, List, Target):
'''
Return true value if it exists and a false if it doesn't
'''
# If the length of the List is equal to 0 : return False
if len(List) == 0:
return False
# Else if the list is not empty
else:
Midpoint = (len(List))//2
# IF the Midpoint value within the list is equal to Target value: return true
if List[Midpoint] == Target:
return True
else:
if List[Midpoint] < Target:
return cls.RecursiveBinarySearchAlgo(List[Midpoint + 1:], Target)
else:
return cls.RecursiveBinarySearchAlgo(List[:Midpoint], Target)
def Verify(Result):
print("Target found: ", Result)
Numbers = [1,2,3,4,5,6,7,8]
# Test Cases 1
Result = RecursiveBinarySearch.RecursiveBinarySearchAlgo(Numbers, 12)
RecursiveBinarySearch.Verify(Result)
# Test Case 2
Result = RecursiveBinarySearch.RecursiveBinarySearchAlgo(Numbers, 5)
RecursiveBinarySearch.Verify(Result)
The function searches the index of a value and if it is called again then it returns the next index of that value. Here is what i tried, where I'm getting error is that my list is not getting overridden and after every call I am getting same result.
Note: I have not included linked list classes here
If anyone knows a better way to make this function please suggest
class Node:
def __init__(self,value):
self.value = value
self.next = None
self.previous = None
class LinkedList:
def __init__(self):
self.head = None
self.tail = None
class DynamicSharpSearch(LinkedList):
def __init__(self, data):
super().__init__()
self.data = data
self.count = 0
self.lim = 0 # using in search function
for i in self.data:
self.InsertatEnd(i)
self.count += 1
self.demlst = [-1 for i in range(self.count)] # using in Search function only
self.seclist = self.demlst
def Search(self,n):
x = self.head
#demlst = [-1 for i in range(self.count)]
y = 0
tst = -1 # checks value if not in our data
##############################
for i in range(self.count):
if n == x.value:
# demlst.append(i)
self.demlst[y] = i
tst = 0
x = x.next
y += 1
##############################
if tst == -1:
return -1
else:
pass
"""Demlist containes "indexes" """
for i in range(self.count):
if self.seclist[i] >= 0:
#y = self.seclist[i]
self.seclist[i] = -1
self.lim = i
return i
obj = DynamicSharpSearch([53,4,52,7,5,4,5,5,5,6,4,2,4,5,459]) # c = 6
print(obj.Search(5))
print(obj.Search(5))
print(obj.Search(5))
What output I am getting:
4
4
4
I would use a dictionary to keep track of the last returned index for each value.
When the Search method is called, it looks to see if it's looked for that value before: start_index = self.last_returned.get(n, 0). If start_index is >0, then you fast-forward to that index before initiating the search. Once you've found what you're looking for, update the dictionary: self.last_returned[n] = returned_index + 1. Why "+1"? Because otherwise you'll get what you're getting right now, the same index returned over and over. You need to start searching after the last index you returned. (You'd want to make sure you're not storing a value which would result in an IndexError, however.)
class _ListNode:
def __init__(self, value, next_):
self._data = value
self._next = next_
return
class List:
def __init__(self):
self._front = None
self._count = 0
return
def _linear_search(self,key):
previous = None
current = self._front
index = 0
while current is not None and key > current._data:
previous = current
current = current._next
index += 1
if current._data != key:
previous = None
current = None
index = -1
return previous, current, index
def __contains__(self, key):
_, _, i = self._linear_search(key)
return i != -1
def append(self, value):
if self._front is None:
self._front = _ListNode(value,None)
else:
self._front._next = _ListNode(value,None)
self._count += 1
l = List()
lst = [1,2,3,4]
i = 0
n = len(lst)
while i < n:
l.append(lst[i])
i += 1
print("{}".format(l.__contains(3))
To explain more, I implement the linear search method and the contains method. The contains method check if the number is in the list or not (returns true or false). Now when I need to check that #3 in the list using contains method, the answer is false!! i cant know what's the problem
Your append method does not walk down the list. It simply always appends to self._front._next if self.front is already present. Meaning the contents at the end of the append loop are the first thing you appended, the last thing you appended and nothing in between.
To correct it walk the list looking for a _next equal to None and append there.
def append(self, value):
if self._front is None:
self._front = _ListNode(value, None)
else:
n = self._front
while n._next is not None:
n = n._next
n._next = _ListNode(value, None)
self._count += 1
You could also define a _str__ method to print the content of the List
e.g.
def __str__(self):
res = []
n = self._front
while n is not None:
res.append(str(n._data))
n = n._next
return ', '.join(res)
This is not a particularly efficient implementation as it builds an intermediate builtin list object.
You also don't need those bare return statements in your methods. You can remove those.
I have an entire Deque Array class that looks like this:
from collections import deque
import ctypes
class dequeArray:
DEFAULT_CAPACITY = 10 #moderate capacity for all new queues
def __init__(self):
self.capacity = 5
capacity = self.capacity
self._data = self._make_array(self.capacity)
self._size = 0
self._front = 0
def __len__(self):
return self._size
def __getitem__(self, k): #Return element at index k
if not 0 <= k < self._size:
raise IndexError('invalid index')
return self._data[k]
def isEmpty(self):
if self._data == 0:
return False
else:
return True
def append(self, item): #add an element to the back of the queue
if self._size == self.capacity:
self._data.pop(0)
else:
avail = (self._front + self._size) % len(self._data)
self._data[avail] = item
self._size += 1
#def _resize(self, c):
#B = self._make_array(c)
#for k in range(self._size):
#B[k] = self._A[k]
#self._data = B
#self.capacity = capacity
def _make_array(self, c):
capacity = self.capacity
return (capacity * ctypes.py_object)()
def removeFirst(self):
if self._size == self.capacity:
self._data.pop(0)
else:
answer = self._data[self._front]
self._data[self._front] = None
self._front = (self._front + 1) % len(self._data)
self._size -= 1
print(answer)
def removeLast(self):
return self._data.popleft()
def __str__(self):
return str(self._data)
and when I try to print the deque in the main it prints out something like this,
<bound method dequeArray.__str__ of <__main__.dequeArray object at 0x1053aec88>>
when it should be printing the entire array. I think i need to use the str function and i tried adding
def __str__(self):
return str(self._data)
and that failed to give me the output. I also tried just
def __str__(self):
return str(d)
d being the deque array but I still am not having any success. How do I do i get it to print correctly?
you should call the str function of each element of the array that is not NULL, can be done with the following str function:
def __str__(self):
contents = ", ".join(map(str, self._data[:self._size]))
return "dequeArray[{}]".format(contents)
What I get when I try to q = dequeArray(); print(q) is <__main__.py_object_Array_5 object at 0x006188A0> which makes sense. If you want it list-like, use something like this (print uses __str__ method implicitly):
def __str__(self):
values = []
for i in range(5):
try:
values.append(self._data[i])
except ValueError: # since accessing ctypes array by index
# prior to assignment to this index raises
# the exception
values.append('NULL (never used)')
return repr(values)
Also, several things about the code:
from collections import deque
This import is never user and should be removed.
DEFAULT_CAPACITY = 10
is never used. Consider using it in the __init__:
def __init__(self, capacity=None):
self.capacity = capacity or self.DEFAULT_CAPACITY
This variable inside __init__ is never user and should be removed:
capacity = self.capacity
def _make_array(self, c):
capacity = self.capacity
return (capacity * ctypes.py_object)()
Though this is a valid code, you're doing it wrong unless you're absolutely required to do it in your assignment. Ctypes shouldn't be used like this, Python is a language with automated memory management. Just return [] would be fine. And yes, variable c is never used and should be removed from the signature.
if self._data == 0
In isEmpty always evaluates to False because you're comparing ctypes object with zero, and ctypes object is definitely not a zero.
I need help implementing a method for my "MyHashTable" class:
def search(self, search_key):
The method is supposed to use linear probing to handle collision resolution. If the search_key is in the hash table then the method returns the slot number of the slot containing that search_key. If the search_key is not in the hash table, the method returns -1
My class looks like this:
class MyHashTable:
def __init__(self, capacity):
self.capacity = capacity
self.slots = [None] * self.capacity
def __str__(self):
return str(self.slots )
def __len__(self):
count = 0
for i in self.slots:
if i != None:
count += 1
return count
def hash_function(self, key):
i = key % self.capacity
return i
def insert(self, key):
slot = self.hash_function(key)
orig = slot
while True:
if self.slots[slot] is None:
self.slots[slot] = key
return slot
if self.slots[slot] == key:
return -2
slot = (slot + 1) % self.capacity
if slot == orig:
return -1
def search(self, search_key):
Any help or tutorial links would be awesome.
Thanks
You are only using a single list to store all the values, if you wanted a hash table you might use a list of lists where each list was a bucket but if you just want to check if the element is in your hash table with your own code:
def search(self, search_key):
hsh = self.hash_function(search_key)
if self.slots[hsh] is None:
return -1
while hsh < self.capacity:
if self.slots[hsh] == search_key:
return hsh
hsh += 1
return -1
You also have to handle the case where you have multiple collisions so we need at worst to check every element in the hash table to find the correct value:
def search(self, search_key):
hsh = self.hash_function(search_key)
if self.slots[hsh] is None:
return -1
for i in range(self.capacity):
mod = (hsh + i) % self.capacity
if self.slots[mod] == search_key:
return mod
return -1
The first while loop will probe one value over at a time but if we have wrapped around the list from multiple collisions it would miss elements at the start so using range and mod = (hsh + i) % self.capacity makes sure we check all entries like the example below.
m = MyHashTable(5)
m.insert(13) # 13 % 5 = 3
m.insert(73) # 83 % 5 = 3
m.insert(93) # 93 & 5 = 3
print(m.search(13)) # 3
print(m.search(73)) # 4
print(m.search(93)) # 0
print(m.search(2)) # -1
You can make your len method O(1) by keeping track of when you add a unique value to your hash table, there is also a nice wiki page on Open_addressing parts of which you can adopt into your code and it will help you create a proper mapping of keys to values and resized your hash table when needed. If you want to store more than just numbers you need to use a different hash function, I just use hash but you can use whatever you like. Also using in when your hash table is full and the key does not exist will cause an infinite loop so you will need to handle that case:
class MyHashTable:
def __init__(self, capacity):
self.capacity = capacity
self.slots = [None] * self.capacity
self.count = 0
def __str__(self):
return str(self.slots)
def __contains__(self, item):
return self.search(item) != -1
def __len__(self):
return self.count
def hash_function(self, key):
return hash(key) % self.capacity
def find_slot(self, key):
slot = self.hash_function(key)
while self.slots[slot] is not None and self.slots[slot] != key:
slot = (slot + 1) % self.capacity
return slot
def insert(self, key):
slot = self.find_slot(key)
if self.slots[slot] != key:
self.slots[slot] = key
self.count += 1
def search(self, key):
i = self.find_slot(key)
if self.slots[i] is not None:
return i
return -1
Add a __contains__ will also allow you to use in to test for membership:
m = MyHashTable(5)
m.insert("foo")
m.insert(73)
m.insert(93)
m.insert(1)
print(m.search(73))
print(m.search(93))
print(m.search(1))
print(m.search("foo"))
m.insert(73)
print(m.slots)
print(len(m))
print("foo" in m)
print(5 in m)
Output:
3
4
1
0
['foo', 1, None, 73, 93]
4
True
False