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())
Related
I am trying to implement an A-star search algorithm to find a path in a square maze from (0,0) to (dimension - 1, dimension - 1). My algorithm returns the correct path when it exists; however, if there is no path, then it runs in an infinite loop. How do I fix this? For now, I've put a condition to run if the length of the open list exceeds (dimension ^ 4), but this is obviously not a permanent fix. I am using Python 3.7.3.
import numpy as np
class node():
def __init__(self, parent=None, location=None):
self.parent = parent
self.location = location
self.g = float(0)
self.h = float(0)
self.f = float(0)
#returns euclidean distance between two nodes
#takes the locations/tuples of two nodes as arguments
#works properly
def euclidean_distance(node_1, node_2):
return float((((node_2[1] - node_1[1])**2) + ((node_2[0] - node_1[0])**2))**0.5)
#to make extracting the value at a given location in the maze easier
#takes the maze and two integers as arguments
def get_value(maze, a, b):
return maze[a][b]
def out_of_bounds(a, b, dim):
return (a < 0 or a >= dim) or (b < 0 or b >= dim)
#Euclidean A* Search, takes the maze and dimension as arguments
def a_star_euclidean(maze, dim):
#initializing start node and end node
start = node(None, (0,0))
end = node(None, (dim-1, dim-1))
#initializing open list and closed list
open_list = []
closed_list = []
open_list.append(start)
while len(open_list) > 0:
#assigning currentNode
currentNode = open_list[0]
currentNode_index = 0
#current location
for index, item in enumerate(open_list):
if item.f < currentNode.f:
currentNode = item
currentNode_index = index
#(currentNode.location)
row = currentNode.location[0]
column = currentNode.location[1]
#updating open list and closed list
open_list.pop(currentNode_index)
closed_list.append(currentNode)
#in case goal node is already reached
if currentNode.location == end.location:
path = []
current = currentNode
while current is not None:
path.append(current.location)
current = current.parent
#return path[::-1] #returning the path from start to end
path.reverse()
return path
else:
closed_list.append(currentNode)
#generating childs
child_locations = [(row+1, column), (row-1, column), (row, column+1), (row, column-1)]
#print(child_locations)
child_nodes = [node(currentNode, location) for location in child_locations]
#print(child_nodes)
for child in child_nodes:
#declaring row and column variables for child nodes
child_row = int(child.location[0])
child_column = int(child.location[1])
if not out_of_bounds(child_row, child_column, dim):
# Child is on the closed list
if child in open_list:
continue
#computing g(n), h(n), f(n)
child.g = float(currentNode.g + 1)
child.h = float(euclidean_distance(child.location, end.location))
child.f = float(child.g + child.h)
#child is in open list
if child in closed_list:
continue
if get_value(maze, child_row, child_column) == 0:
open_list.append(child)
else:
continue
else:
continue
#if (len(open_list) > dim**4): #b^d worst case
#return None
def main():
maze = []
dim = int(input("Enter the dimension of the game: "))
print(dim)
for row in range(dim):
maze.append([])
for column in range(dim):
maze[row].append(int(np.random.binomial(1, 0.3, 1)))
maze[0][0] = 0
maze[dim-1][dim-1] = 0
print(maze)
print("----------")
print(a_star_euclidean(maze,dim))
#print(euclidean_distance((1,1), (2,2)))
main()
I believe the issue is that child in closed_list is never true, because you haven't overriden the __eq__ operator of the node class. Because of this, python doesn't know how to compare two instances of the node class, so falls back to comparing if they are references to the same object in memory, otherwise it returns false. So two nodes are never equal when searching through closed_list.
Try defining the __eq__ operator for the node class like so. You can change the comparison to include other properties as you need.
class node():
def __init__(self, parent=None, location=None):
self.parent = parent
self.location = location
self.g = float(0)
self.h = float(0)
self.f = float(0)
def __eq__(self, other):
return self.location == other.location
I am trying to create a binary tree from an array of values. I dont want to add a duplicate entry to the tree, if a duplicate value is found, I need to increment the counter of existing node.
class eNode:
def __init__(self, data):
self.data = data
self.left = self.right = None
self.Counter = 1
def __str__(self):
return str(self.data) + " Counter: " + str(self.Counter)
def insertLevelOrder(arr, root, i, n):
if i < n:
temp = eNode(arr[i])
root = temp
root.left = insertLevelOrder(arr, root.left,
2 * i + 1, n)
root.right = insertLevelOrder(arr, root.right,
2 * i + 2, n)
return root
def main():
empList = [1, 2, 2, 3, 5]
n = len(empList)
root = None
root = insertLevelOrder(empList, root, 0, n)
print (root);
print (root.left);
print (root.right);
print (root.left.left);
print (root.left.right);
#inOrder(root)
main()
Is there a way to achieve this ? all helps are appreciated.
Since your tree building algorithm assigns a value to a specific location in the tree, that only depends on the index in the input array, it becomes a problem when certain values would not become a node in a tree (but would increment a counter of some other node):
The would-be children of that value will be orphaned.
Take the example:
[1, 2, 2, 3, 5, 6]
Without any special treatment for duplicates, this produces the following tree:
1
/ \
2 2
/ \ /
3 5 6
The fact that 6 ends up on the third level, at the 3rd place, is completely determined by the fact that this value occurs at index 5 in the input array (zero-based indexing), and nothing else. If we would not create the node for the second 2, we would get an orphaned 6:
1
/
2
/ \
3 5 6
One way to solve this, is to agree that the index in the original input array is no longer defining the position of the node, and the tree would become:
1
/ \
2* 3
/ \
5 6
...where the asterisk represents a count of 2. Note that this is a completely different tree. For instance, now 3 is a direct child of 1, and only because there was a duplicate 2...
If this is however how you would want it to work, then make your algorithm iterative instead of recursive, and keep track of what the parent is of any newly created node:
class eNode:
def __init__(self, data):
self.data = data
self.left = self.right = None
self.counter = 1
def __str__(self):
return str(self.data) + " Counter: " + str(self.counter)
def insertLevelOrder(arr):
if arr == []:
return
root = eNode(arr[0])
nodes = [root]
d = {root.data: root}
right = False
parent = 0
for val in arr[1:]:
if val in d:
d[val].counter += 1
else:
node = eNode(val)
nodes.append(node)
d[val] = node
if right:
nodes[parent].right = node
parent += 1
else:
nodes[parent].left = node
right = not right
return root
def main():
empList = [1, 2, 2, 3, 5]
root = insertLevelOrder(empList)
print (root);
print (root.left);
print (root.right);
print (root.left.left);
print (root.left.right);
main()
You can maintain a dictionary of value to binary tree nodes. If the value being inserted already exists in the dictionary, you can get the reference to the node and update it.
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...
I'm working on a small project where I'm implementing a queue as a circular array. As a challenge, I was assigned to not use any list functions like append when implementing this ADT. It's assumed that I only need to resize the queue when it gets full. When I ran my code through a debugger and step through it, I find that the issue revolves around my self.read value (read pointer) which is the global variable in question. This is kind of perplexing to me since neither of my functions that would be affected increments my pointer. Could anyone shed some light on this problem for me?
This class is coded as:
class CircularQueue(object):
def __init__(self, capacity=2):
"""
Initialize the queue to be empty with a fixed capacity
:param capacity: Initial size of the queue
"""
self.capacity = capacity
self.size = 0
self.list = [0] * self.capacity
self.sum = 0
self.read = 0
self.write = 0
def __eq__(self, other):
return self.capacity == other.capacity
and self.size == other.size
and self.read == other.read
and self.write == other.write
def __str__(self):
if self.size == 0:
return "Queue is empty"
content = ""
while ((self.read + 1) % self.size) != self.write:
content = content + str(self.list[self.read]) + " -> "
self.read = (self.read + 1) % self.size
content = content[:-3]
return f"Contents: {content}"
__repr__ = __str__
The portion that I'm interested in looking at is my enqueue and resize functions:
def resize(self):
bigger = [None] * (self.capacity * 2) #create bigger queue
b_ind = 0
read_ptr = self.read
while read_ptr != (self.write + 1): #iterate through old queue to copy into new queue
bigger[b_ind] = self.list[read_ptr]
b_ind += 1
read_ptr += 1
self.capacity *= 2 #setting capacity
self.list = bigger #setting new list as queue
self.read = 0 #normalize queue
self.write = b_ind
def enqueue(self, number):
if self.size == 0: #if queue was originally empty
self.list[self.read] = number
self.write += 1
else:
self.list[self.write] = number #add onto end of queue
if ((self.write + 1) % self.capacity == self.read): #resize if queue loops back and the write pointer is the same as the read pointer
self.resize()
else:
self.write = (self.write + 1) % self.capacity #set write pointer
self.sum += number #add to sum
self.size += 1 # increment size
This was the test case I ran for my code:
queue = CircularQueue()
queue.enqueue(23)
queue.enqueue(42)
queue.enqueue(2)
queue.enqueue(195)
print(queue)
You mutate the state of your queue when printing. print() calls __str__, and that method alters your state:
self.read = (self.read + 1) % self.size
Use a local variable instead of self.read:
def __str__(self):
if self.size == 0:
return "Queue is empty"
content = ""
read = self.read
while (read % self.capacity) != self.write:
if content:
content += ' -> '
content += str(self.list[read])
read = (read + 1) % self.capacity
return f"Contents: {content}"
Note the while loop condition; you want to see if the current read position is not the same as the write position (meaning you can display the current value), not the next position, and you want to wrap round at the capacity.
I adjusted your separator handling a little to only add the arrow in between values if at least one entry has been added to content already, that avoids having to remove a portion again.
Demo using the fixed __str__ method (no other changes made):
>>> queue = CircularQueue()
>>> print(queue)
Queue is empty
>>> queue.enqueue(23)
>>> print(queue)
Contents: 23
>>> queue.enqueue(42)
>>> print(queue)
Contents: 23 -> 42
>>> queue.enqueue(2)
>>> print(queue)
Contents: 23 -> 42 -> 2
>>> queue.enqueue(195)
>>> print(queue)
Contents: 23 -> 42 -> 2 -> 195
I'm creating a class for a K-Order Min-heap. I'm storing the heap as a list. I'm having trouble with implementing remove_min. I know that the process of removing the minimum of a heap is:
Remove first element. This is the minimum.
Swap the first element and the last element.
Bubble the new top element down until it satisfies the heap property.
So I need a remove_min and a helper function, bubbledown. I can't use heapq because it only accounts for binary heaps and this class needs to take a k-order heap. Here's what I have so far:
class KHeap:
def __init__(self, lst=[], k=2):
self.heap = []
self.k = k #order of heap
for v in lst:
self.insert(v)
def children(self, i): #returns a list of the children of the item in index i
heap = self.heap
result = []
for x in range(self.k*i+1, self.k*i+self.k+1):
if x<len(heap):
result.append(heap[x])
else:
pass
return result
def parent(self, i): #returns the parent of item in index i
heap = self.heap
if i==0:
return None
result = i//self.k
return heap[result]
def bubbleup(self, i):
if i == 0:
return None
elif self.heap[i] < self.parent(i):
self.heap[i], self.heap[i // self.k] = self.heap[i // self.k], self.heap[i]
self.bubbleup(i // self.k)
def insert(self, value): #use bubbleup
self.heap.append(value)
self.bubbleup(len(self.heap)-1)
def bubbledown(self, i, d=1):
if i==0:
return None
small = i
for k in range(self.children(i)):
if self.heap[k]<self.heap[small]:
small = k
self.heap[i], self.heap[small] = self.heap[small], self.heap[i]
self.bubbledown(small)
def remove_min(self): #use bubbledown
if len(self.heap) == 0:
return None
if len(self.heap) == 1:
return self.heap.pop()
minimum = self.heap[0]
self.heap[0] = self.heap.pop()
self.bubbledown(0)
return minimum
Now, when I remove_min, the result isn't heapified. For example, if I have a ternary heap [1, 10, 18, 22, 15, 30], k=3 and I remove the minimum, the result is [30, 10, 18, 22, 15]. It seems like the element that I move to the top never gets bubbled down.
So I post a iteration version, which can solve the i == 0 problem.
def bubbledown(self, i, d=1):
small = i
size = len(self.heap)
while (i < size):
// find the smallest child
for k in range(self.children(i)):
if self.heap[k] < self.heap[small]:
small = k
self.heap[i], self.heap[small] = self.heap[small], self.heap[i]
// stop here
if small == i:
break
else:
i = small