I'm new in Python. And I have a task to make a double hash table for arrray and for doubly linked list. I have a code which work with array and code with doubly linked list. But I don't know how convert my object with linked_list to int. I know how convert it on Java just using class Integer but in Python I don't know. I tried to make a function def int(self) and return self.data but it doesn't work. I tried to find how make template or somethig like this but didn't find anything. Please help me.
This is a code:
from random import randint
class doubleHashTable:
# initialize hash Table
def __init__(self):
self.size = int(input("Enter the Size of the hash table : "))
self.num = 5
# initialize table with all elements 0
self.table = list(0 for i in range(self.size))
self.elementCount = 0
self.comparisons = 0
# method that checks if the hash table is full or not
def isFull(self):
if self.elementCount == self.size:
return True
else:
return False
# method that returns position for a given element
# replace with your own hash function
def h1(self, element):
return element % self.size
# method that returns position for a given element
def h2(self, element):
return element % self.num
# method to resolve collision by quadratic probing method
def doubleHashing(self, element, position):
posFound = False
# limit variable is used to restrict the function from going into infinite loop
# limit is useful when the table is 80% full
limit = 50
i = 2
# start a loop to find the position
while i <= limit:
# calculate new position by quadratic probing
newPosition = (i * self.h1(element) + self.h2(element)) % self.size
# if newPosition is empty then break out of loop and return new Position
if self.table[newPosition] == 0:
posFound = True
break
else:
# as the position is not empty increase i
i += 1
return posFound, newPosition
# method that inserts element inside the hash table
def insert(self, element):
# checking if the table is full
if self.isFull():
print("Hash Table Full")
return False
posFound = False
position = self.h1(element)
# checking if the position is empty
if self.table[position] == 0:
# empty position found , store the element and print the message
self.table[position] = element
print("Element " + str(element) + " at position " + str(position))
isStored = True
self.elementCount += 1
# collision occured hence we do linear probing
else:
while not posFound:
print("Collision has occured for element " + str(element) + " at position " + str(
position) + " finding new Position.")
posFound, position = self.doubleHashing(element, position)
if posFound:
self.table[position] = element
self.elementCount += 1
return posFound
# method that searches for an element in the table
# returns position of element if found
# else returns False
def search(self, element):
found = False
position = self.h1(element)
self.comparisons += 1
if (self.table[position] == element):
return position
# if element is not found at position returned hash function
# then we search element using double hashing
else:
limit = 50
i = 2
newPosition = position
# start a loop to find the position
while i <= limit:
# calculate new position by double Hashing
position = (i * self.h1(element) + self.h2(element)) % self.size
self.comparisons += 1
# if element at newPosition is equal to the required element
if self.table[position] == element:
found = True
break
elif self.table[position] == 0:
found = False
break
else:
# as the position is not empty increase i
i += 1
if found:
return position
else:
print("Element not Found")
return found
# method to remove an element from the table
def remove(self, element):
position = self.search(element)
if position is not False:
self.table[position] = 0
print("Element " + str(element) + " is Deleted")
self.elementCount -= 1
else:
print("Element is not present in the Hash Table")
return
# method to display the hash table
def display(self):
print("\n")
for i in range(self.size):
print(str(i) + " = " + str(self.table[i]))
print("The number of element is the Table are : " + str(self.elementCount))
"""DOUBLY-LINKED LIST"""
class Node():
def __init__(self, next_node=None, previous_node=None, data=None):
self.next_node = next_node
self.previous_node = previous_node
self.data = data
class LinkedList():
def __init__(self, node):
assert isinstance(node, Node)
self.first_node = node
self.last_node = node
def push(self, node):
'''Pushes the node <node> at the "front" of the ll
'''
node.next_node = self.first_node
node.previous_node = None
self.first_node.previous_node = node
self.first_node = node
def pop(self):
'''Pops the last node out of the list'''
old_last_node = self.last_node
to_be_last = self.last_node.previous_node
to_be_last.next_node = None
old_last_node.previous_node = None
# Set the last node to the "to_be_last"
self.previous_node = to_be_last
return old_last_node
def removing(self, node):
'''Removes and returns node, and connects the previous and next
'''
next_node = node.next_node
previous_node = node.previous_node
previous_node.next_node = next_node
next_node.previous_node = previous_node
# Make it "free"
node.next_node = node.previous_node = None
return node
# def int(self):
# return self.data
def __str__(self):
next_node = self.first_node
s = ""
while next_node:
s += "--({:2d})--\n".format(next_node.data)
next_node = next_node.next_node
return s
return
# main function
"""LISTS1"""
print("\nLISTS\n")
node1 = Node(data=1)
linked_list = LinkedList(node1)
for i in range(100):
if i == 5:
node1 = Node(data=5)
linked_list.push(node1)
else:
linked_list.push(Node(data=i))
print (linked_list)
print ("popping")
liast = linked_list.pop().data
#print(type(liast))
print(liast)
print (linked_list)
lalalal = linked_list
print(type(lalalal))
#print (linked_list.pop().data)
table_list1 = doubleHashTable()
for i in range (100):
table_list1.insert(lalalal)
# displaying the Table
table_list1.display()
print()
# printing position of elements
print("The position of element 31 is : " + str(table_list1.search(31)))
print("The position of element 28 is : " + str(table_list1.search(28)))
print("The position of element 90 is : " + str(table_list1.search(90)))
print("The position of element 77 is : " + str(table_list1.search(77)))
print("The position of element 1 is : " + str(table_list1.search(1)))
print("\nTotal number of comaprisons done for searching = " + str(table_list1.comparisons))
print()
table_list1.remove(90)
table_list1.remove(12)
table_list1.display()
# storing elements in table
# table1.insert(12)
# table1.insert(26)
# table1.insert(31)
# table1.insert(17)
# table1.insert(90)
# table1.insert(28)
# table1.insert(88)
# table1.insert(40)
# table1.insert(77) # element that causes collision at position 0
This is error
Traceback (most recent call last):
File "python", line 225, in <module>
File "python", line 57, in insert
File "python", line 22, in h1
TypeError: unsupported operand type(s) for %: 'LinkedList' and 'int'
short version use hash(element) on h1() and other places (h2()) at your code that use the hash of the object to determine is position in the hash table
you are inserting a linked_list lalalal
lalalal = linked_list
table_list1.insert(lalalal)
to calculate it's position you are using this method
def h1(self, element):
return element % self.size
you are trying to get mod from linked_list object and int, as the error state
you need to convert your linked list to some representation of number using some logic (uniform hash function is the best)
try to use smth like to_hash() on linked_list that will return int so
def h1(self, element):
return element.to_hash() % self.size
you can also override __hash__ and use hash(element)
Those few changes will make your code run
def h1(self, element):
return hash(element) % self.size
def h2(self, element):
return hash(element) % self.num
and in the LinkedList class add
def __hash__(self):
return randint(1, 1000)
Note: this hash function is for draft purpose only, in case your has map will be bigger than 1000 or what ever fixed value you choose, the elements won't be uniformly distributed over the map, this could effect the map performance...
Related
For school i have to make an assignment -->
"The city of Amsterdam wants to store the maximum values of the past few years for research
purposes. It is important that the current maximum measured value can be accessed very quickly.
One idea to fulfill this requirement is to use a priority queue. Your job is to implement a priority
queue with a maximum heap and return again a tuple of the current maximal measurement and
its corresponding date when the maximum occurred. Output: date,covid level"
The program takes as input:
(string)’yyyy-mm-dd’, (int)sensor id, (int)covid level.
The expected output is: yyyy-mm-dd,covid level.
Input: 2022−09−08, 23, 371; 2022−09−08, 2, 3171; 2022−09−08, 12, 43; 2021−03−21, 4, 129
Output: 2022 −09 −08, 3171
I have provided my code below. When creating a max heap, the max element should be the first element (root). A Max-Heap is a complete binary tree in which the value in each internal node is greater than or equal to the values in the children of that node, though when inserting the tuples the nodes do not get sorted. My output is very strange, i do not understand where it comes from. When putting in the above input, this is my output:
1.1.1977, 9223372036854775807
could somebody help me? what piece of code am i missing, i have gone over it so many times.
import sys
class MaxHeap:
def __init__(self, maxsize):
self.maxsize = maxsize
self.size = 0
self.Heap = [0] * (self.maxsize + 1)
self.Heap[0] = ('1.1.1977', sys.maxsize)
self.FRONT = 1
# Function to return the position of
# parent for the node currently
# at pos
def parent(self, pos):
return pos // 2
# Function to return the position of
# the left child for the node currently
# at pos
def leftChild(self, pos):
return 2 * pos
# Function to return the position of
# the right child for the node currently
# at pos
def rightChild(self, pos):
return (2 * pos) + 1
# Function that returns true if the passed
# node is a leaf node
def isLeaf(self, pos):
if pos >= (self.size // 2) and pos <= self.size:
return True
return False
# Function to swap two nodes of the heap
def swap(self, fpos, spos):
self.Heap[fpos], self.Heap[spos] = (self.Heap[spos],
self.Heap[fpos])
# Function to heapify the node at pos
def maxHeapify(self, pos):
if not self.isLeaf(pos):
if (self.Heap[pos] < self.Heap[self.leftChild(pos)] or
self.Heap[pos] < self.Heap[self.rightChild(pos)]):
if (self.Heap[self.leftChild(pos)] >
self.Heap[self.rightChild(pos)]):
self.swap(pos, self.leftChild(pos))
self.maxHeapify(self.leftChild(pos))
else:
self.swap(pos, self.rightChild(pos))
self.maxHeapify(self.rightChild(pos))
# Function to insert a node into the heap
def insert(self, element):
if self.size >= self.maxsize:
return
self.size += 1
self.Heap[self.size] = element
current = self.size
while (self.Heap[current] >
self.Heap[self.parent(current)]):
self.swap(current, self.parent(current))
current = self.parent(current)
# Function to print the contents of the heap
def Print(self):
for i in range(1, (self.size // 2) + 1):
print(i)
print("PARENT : " + str(self.Heap[i]) +
"LEFT CHILD : " + str(self.Heap[2 * i]) +
"RIGHT CHILD : " + str(self.Heap[2 * i + 1]))
# Function to remove and return the maximum
# element from the heap
def extractMax(self):
extraction = self.Heap[self.FRONT]
self.Heap[self.FRONT] = self.Heap[self.size]
self.size -= 1
self.maxHeapify(self.FRONT)
return extraction
# Driver Code
if __name__ == "__main__":
input = input()
input = input.split(";")
dates = []
values = []
for d in input:
date = d.split(',', 2)
dates.append(date[0])
values.append(date[2])
values = [int(x) for x in values]
tuples = list(zip(dates, values))
heap = MaxHeap(len(tuples) + 1)
# print(tuples)
for t in tuples:
heap.insert(t)
print(t)
print(heap.extractMax())
I need to write a function that deletes a node at the given index value.The index value is passed as a parameter.
Delete: this method deletes a node from the linked list. If an index is passed as a parameter, then the method should delete the node at this index. If no index is passed, then delete the first item in the list
So far I have:
class Node:
def __init__(self, dataval=None):
self.dataval = dataval
self.nextval = None
class LinkedList:
def __init__(self):
self.headval = None
def __str__(self):
node = self.headval
output = "[ "
while(node != None):
output = output + str(node.dataval) + ", "
node = node.nextval
if(len(output) > 2):
output = output[:-2]
return output + " ]"
def delete(self, index=0):
if self.headval is None:
print("This list has no element to delete")
return
if self.headval ==index:
self.headval=self.headval.nextval
return
n=self.headval
while n.nextval is not None:
if n.nextval.dataval==index:
break
n=n.nextval
if n.nextval is None:
print("Item not found in list")
else:
n.nextval=n.nextval.nextval
Right now instead of deleting the value at that index it just deletes whatever index has that value.How can I change that
In the delete method:
(1) Change:
if self.headval ==index:
to:
if index == 0:
(2) And change:
if n.nextval.dataval==index:
...to:
index -= 1
if index == 0:
Attempting to create a method for a singly linked list and struggling to understand why this test case is failing. In my second class SLinkedList, I have a method called insert, it takes the argument pos which is an integer. Now in my test case when I add middle to position 4 it stops referencing any further nodes the linked list meaning that the node containing the data middle does not have a reference to the node containing 77. I'm confused why this is happening? I've programmed it such that when current_pos==pos we set the next of our current (new_node) to be current.getNext() (77). Haven't I assigned the next of 2 to middle and the next of middle to 77?
class SLinkedListNode:
# an instance of this class is a node in a Single Linked List
# a node has a reference to data and reference to next
def __init__(self,initData,initNext):
self.data = initData
self.next = initNext
def getNext(self):
return self.next
def getData(self):
return self.data
def setData(self,newData):
self.data = newData
def setNext(self,newNext):
self.next = newNext
class SLinkedList:
# an instance of this class is a Singly-Linked List object
# it has reference to the first node in the list
def __init__(self):
self.head = None
self.size = 0
def add(self,item):
# adds an item at the start of the list
new_node = SLinkedListNode(item,None)
new_node.setNext(self.head)
self.head = new_node
self.size = self.size + 1
def append(self,item):
# adds an item at the end of the list
new_node = SLinkedListNode(item,None)
current = self.head # Start the traversal
if self.size == 0: # check if list is empty
self.add(item)
else:
while (current.getNext()!=None):
current= current.getNext() # traversing the list
current.setNext(new_node)
self.size = self.size +1
def insert(self,pos,item):
# inserts the item at pos
# pos should be a positive number (or zero) of type int
assert type(pos)==int,'Error:pos is not an integer'
assert pos>=0,'Error:pos must be positive'
current=self.head
new_node= SLinkedListNode(item,None)
if pos==0:
self.add(item)
elif pos==self.size:
self.append(item)
else:
current_pos=0
while(current.getNext()!=None):
if (pos-1)==current_pos:
print(current.getData())
current.setNext(new_node)
if pos==current_pos:
print(current.getData())
new_node.setNext(current.getNext())
current=current.getNext()
current_pos+=1
self.size+=1
# 1--> 2--->inserteditem---> 3-->4---> 5---> 6
# TO DO: write assert statement that tests if pos is int
# TO DO: write assert statement that tests that pos is not negative
# TO DO: COMPLETE THE METHOD
def remove(self,item):
# remove the node containing the item from the list
if self.size == 0:
raise Exception('List is Empty')
current = self.head
previous = None
found = False
while current != None and not found:
if current.getData() == item:
found = True
else:
previous = current
current = current.getNext()
if not found:
raise Exception('Item not in list')
else:
if previous == None: # the item is in the first node of the list
self.head = current.getNext()
else: # item is not in the first node
previous.setNext(current.getNext())
self.size = self.size -1
def index(self,item):
# finds the location of the item in the list
if self.size == 0:
raise Exception('List is empty')
position = 0
found = False
current = self.head
while current != None and not found:
if current.getData() == item:
found = True
else:
current = current.getNext()
position = position + 1
if found:
return position
else:
return 'Item not found'
def pop(self):
# removes the node from the end of the list and returns the item
if self.size == 0:
raise Exception('List is empty')
current = self.head
previous = None
while current.getNext() != None:
previous = current
current = current.getNext()
if previous == None:
self.head = None
else:
previous.setNext(None)
self.size = self.size -1
return current.getData()
def __str__(self):
# returns a string representation of the list
current = self.head
string = ''
while current != None:
string = string + str(current.getData())+'->'
current = current.getNext()
return string
def getSize(self):
return self.size
def main():
# Testing Singly-Linked List
slist = SLinkedList()
slist.add(2)
slist.add(4)
slist.add('A')
slist.append(77)
slist.append(6)
slist.append('Z')
print('Original List:', slist.getSize(), 'elements')
print(slist)
print()
slist.insert(0,'start')
print('After inserting the word start at position 0:', slist.getSize(), 'elements')
print(slist)
print()
slist.insert(7,'end')
print('After inserting the word end at position 7:', slist.getSize(), 'elements')
print(slist)
print()
slist.insert(4,'middle')
print('After inserting middle at position 4:', slist.getSize(), 'elements')
print(slist)
if __name__=="__main__":
main()
Take a look at this code snippet from your insert-method:
else:
current_pos=0
while(current.getNext()!=None):
if (pos-1)==current_pos:
print(current.getData())
current.setNext(new_node)
if pos==current_pos:
new_node.setNext(current.getNext())
current=current.getNext()
current_pos+=1
Once the first if-condition is met, you're setting your new node as the current node's next node. Bear in mind, this new node has no reference to the rest of the list. The second if statement will not execute during this iteration, so the next line to be executed is current=current.getNext(), which sets current to be your new node, still without reference to the rest of the list. Therefore, in the next iteration of the while loop current.getNext() evaluates to None and your iteration terminates right then and there, effectively removing all nodes after your new node from the list.
To fix this, remove the second if and set the new node's next node in the previous if statement. This way, you'll maintain the reference to the rest of the list.
On a side note, get- and set-methods are very unpythonic, you can access and modify these attributes directly, e.g. by using current.next = whatever. Also, a while-loop iterating over your entire list seems fairly inefficient for the insert task since you exactly know the index to insert the new node into. Also also, your insert-method will break for positions greater than the list's length, you might want to add another check for that
There is a sorting function as such:
def iterative_insertion_sort(A):
'''Sort A iteratively.'''
for i, key in enumerate(A[1:]):
while i > -1 and A[i] > key:
print(id(key), id(A[i+1]))
A[i + 1] = A[i]
print(id(key), id(A[i+1]))
i = i - 1
A[i + 1] = key
The sorting function is working fine with floats.
Sample output: ./insertion_sort.py .23 .21 .26
140566861513304 140566861513304
140566861513304 140566861513256
[0.21, 0.23, 0.26]
But I have my custom class called lList which have link(another custom class) type of elements. When I input instances of lList, the sort doesn't work correctly.
Sample output: 0.23 0.21 0.26 /
139732300992808 139732300992808
139732300992808 139732300992808
0.23 0.23 0.26 /
As we can see the id of key and the array element is different after the assignment statement in case of float.
But in case of the custom class even after the assignment operation, the id of key and array element is same. This is the cause of trouble.
I suspect the problem is because of the fact that floats are immutable, whereas my custom class isn't. My question is what is the best way to tackle the situation?
Note: I would prefer zero to minimal changes in my sorting procedure. However, I am willing to customize my lList or link class.
P.S. I have just posted only the relevant pieces of code. If the class definition is also needed, just mention it, I will add that too.
Many Thanks!
Update:
link definition:
class link:
'''Implement link.'''
def __init__(self, key=None):
self.key = key
self.nxt = None
self.prev = None
def __str__(self):
'''Print link.'''
if self:
return str(self.key)
else:
return '/'
def __gt__(self, other):
return self.key > other.key
This is the lList definition:
class lList:
'''Implement list of links.'''
def __init__(self):
self._head = None
self._numberOfLinks = 0
def list_insert(self, x):
'''Insert link x at the beginning of list.'''
x.nxt = self._head
if self._head:
self._head.prev = x
self._head = x
self._numberOfLinks += 1
def __str__(self):
'''Print list of links.'''
listFormat = ''
temp = self._head
while temp:
listFormat += str(temp) + ' '
temp = temp.nxt
else:
listFormat += '/ '
return listFormat
def get_data(self, position):
'''Return link from list at position position from head.'''
i = 0
temp = self._head
while i < position:
temp = temp.nxt
i += 1
return temp
def set_data(self, position, newLink):
'''Overwrite key of link at position distance from head of list with key of newLink.'''
i = 0
temp = self._head
while i < position:
temp = temp.nxt
i += 1
temp.key = newLink.key
def __getitem__(self, position):
if type(position) is slice:
return [self[i] for i in range(*position.indices(len(self)))]
elif type(position) is int:
if position < 0:
position += len(self)
if position >= len(self):
raise IndexError("The index (%d) is out of range."%position)
return self.get_data(position)
else:
raise TypeError("Invalid argument type.")
def __setitem__(self, position, value):
self.set_data(position, value)
def __len__(self):
return self._numberOfLinks
And this is the mimimal code that creates the same scene:
test = lList()
l = link(.26)
test.list_insert(l)
l = link(.21)
test.list_insert(l)
l = link(.23)
test.list_insert(l)
print(test)
iterative_insertion_sort(test)
print(test)
Yes, the problem is less one of immutability and more one of shared references.
When sorting floating point values, you store a reference to the float stored in A[1] in key. You then alter the reference in A[1] with the value from A[0]. That means that A[1] now points to a different object, and later on setting A[0] to key is fine.
But when sorting your linked list, you never alter A[1]. You alter an attribute of A[1]. key and A[1] continue to point to the same link instance, and setting A[1].key is visible in key.key too.
You can fix this by actually replacing the whole link object by a new one:
def set_data(self, position, newLink):
'''Overwrite key of link at position distance from head of list with key of newLink.'''
i = 0
temp = self._head
while i < position:
temp = temp.nxt
i += 1
newlink = link(newLink.key)
if temp.prev:
temp.prev.nxt = newlink
else:
self._head = newlink
newlink.nxt = temp.nxt
This makes it equivalent to setting a new value in a Python list object:
(4302695168, 4302695168)
(4302695168, 4303149248)
0.21 0.23 0.26 /
My assignment is to implement a map with chaining by creating a hash table with two lists, one called "slots" and one called "data. My code seems to work until the 'G' character. I can't quite pinpoint what is going on here and I have tried debugging.
class HashTable:
def __init__(self):
self.size = 11
self.slots = [None] * self.size
self.data = [None] * self.size
def put(self,key,data):
hashvalue = self.hashfunction(key,len(self.slots))
if self.slots[hashvalue] == None:
self.slots[hashvalue] = list()
self.slots[hashvalue].append(key)
self.data[hashvalue] = list()
self.data[hashvalue].append(data)
else:
if self.slots[hashvalue] != None:
self.data[hashvalue].append(data) #replace
def hashfunction(self,key,size):
return key%size
def get(self,key):
startslot = self.hashfunction(key,len(self.slots))
data = None
stop = False
found = False
position = startslot
while self.slots[position] != None and not found and not stop:
for index in range (len(self.slots[position])):
if self.slots[position][index]== key:
found = True
data = self.data[position][index]
break
position+1
if position == startslot:
stop = True
return data
def __getitem__(self,key):
return self.get(key)
def __setitem__(self,key,data):
self.put(key,data)
## TEST FOR HashTable
h = HashTable() # create new hash table
nums = [1, 3, 5, 50, 1000] # some keys
nums = nums + [ len(h.slots)*i for i in range(20)] # some keys that have same hash
vals = [ chr(x) for x in range(ord('A'),ord('Z')) ] # list of single letters from A to Z
# add key/values
for i in range(len(nums)):
# print("adding (%d, %s)"%(nums[i],vals[i]),end=" ")
h[nums[i]] = vals[i]
for i in range(len(nums)):
key = nums[i]
value = vals[i]
gotValue = h[key]
assert gotValue == value,"expected key: %d to lookup value: %s but got value %s instead " % (key, value, gotValue)
print("\nAll TESTS PASSED")
I found my issue:
I forgot to add a line under:
if self.slots[hashvalue] != None:
that adds the key to the [hashvalue] of slots.
So now I have:
if self.slots[hashvalue] != None:
self.slots[hashvalue].append(key)
self.data[hashvalue].append(data)
It was adding the data value to the corresponding list "data", but not the matching key value to the list "slots"