Python: Using my heap in a priority queue implementation - python

I am having real trouble using my custom-made heap class functions to be used in my Priority Queue class. I am having trouble on what functions from my heap class to use for my "enqueue", "dequeue", "front" and "size" functions for my PriorityQueue. I know for "enqueue" I need to use my insert function, but I don't know how to go about this because I have a priority. Could someone help me out what I need to do in order to make my PriorityQueue class to use the functions from my Heap class in order to work properly? I have been stuck on this for awhile and I keep finding answers that include using the built in python functions such as queue and heapq.
class Heap(object):
def __init__(self, items=None):
'''Post: A heap is created with specified items.'''
self.heap = [None]
if items is None:
self.heap_size = 0
else:
self.heap += items
self.heap_size = len(items)
self._build_heap()
def size(self):
'''Post: Returns the number of items in the heap.'''
return self.heap_size
def _heapify(self, position):
'''Pre: Items from 0 to position - 1 satisfy the Heap property.
Post: Heap Property is satisfied for the entire heap.'''
item = self.heap[position]
while position * 2 <= self.heap_size:
child = position * 2
# If the right child, determine the maximum of two children.
if (child != self.heap_size and self.heap[child+1] > self.heap[child]):
child += 1
if self.heap[child] > item:
self.heap[position] = self.heap[child]
position = child
else:
break
self.heap[position] = item
def delete_max(self):
'''Pre: Heap property is satisfied
Post: Maximum element in heap is removed and returned. '''
if self.heap_size > 0:
max_item = self.heap[1]
self.heap[1] = self.heap[self.heap_size]
self.heap_size -= 1
self.heap.pop()
if self.heap_size > 0:
self._heapify(1)
return max_item
def insert(self, item):
'''Pre: Heap Property is Satisfied.
Post: Item is inserted in proper location in heap.'''
self.heap_size += 1
# extend the length of the list.
self.heap.append(None)
position = self.heap_size
parent = position // 2
while parent > 0 and self.heap[parent] < item:
# Move the item down.
self.heap[position] = self.heap[parent]
position = parent
parent = position // 2
# Puts the new item in the correct spot.
self.heap[position] = item
def _build_heap(self):
''' Pre: Self.heap has values in 1 to self.heap_size
Post: Heap property is satisfied for entire heap. '''
# 1 through self.heap_size.
for i in range(self.heap_size // 2, 0, -1): # Stops at 1.
self._heapify(i)
def heapsort(self):
'''Pre: Heap Property is satisfied.
Post: Items are sorted in self.heap[1:self.sorted_size].'''
sorted_size = self.heap_size
for i in range(0, sorted_size -1):
# Since delete_max calls pop to remove an item, we need to append a dummy value to avoid an illegal index.
self.heap.append(None)
item = self.delete_max()
self.heap[sorted_size - i] = item
So this is working but like I previously stated I am having trouble on how to make a priority queue out of this? I know asking for code is wrong, but I'm desperate could anyone help me out here? I have the basic rundown on what I want my priority code to do..
#PriorityQueue.py
from MyHeap import Heap
class PriorityQueue(object):
def __init__(self):
self.heap = None
def enqueue(self, item, priority):
'''Post: Item is inserted with specified priority in the PQ.'''
self.heap.insert((priority, item))
def first(self):
'''Post: Returns but does not remove the highest priority item from the PQ.'''
return self.heap[0]
def dequeue(self):
'''Post: Removes and returns the highest priority item from the PQ.'''
if self.heap is None:
raise ValueError("This queue is empty.")
self.heap.delete_max()
def size(self):
'''Post: Returns the number of items in the PQ.'''
return self.size
This is what I got so far but I do not know if it is entirely correct. Could anyone help me out?
I edited my code to the most current version of it.

Since this is presumably homework, all I can do is give hints, which is often easier done as comments. Since this ended up being a fairly thorough series of hints I'm summarizing them as an answer here.
For the most part, methods in your PriorityQueue class will map to methods you've already implemented in your Heap class:
PriorityQueue.enqueue() maps pretty easily to Heap.insert()
PriorityQueue.first() does not have a corresponding heap method, but can still be implemented in one line. You just need to return the maximum value, which will always be at a specific place in your heap.
PriorityQueue.dequeue() is a little more complicated. It needs to save the value of the top item first so that it can return it after calling heap.delete_max()
The heap class already has a size() method, which PriorityQueue.size() can call, instead of maintaining a separate size variable within the PriorityQueue class.
Additionally, you need an init function, This should create a new Heap object that will be maintained by the class.
In order to make an iterator, you'll need to make a new class. It will need to maintain an integer variable (let's call it self.index), indicating its current place in the queue. You'll also want a method that increases self.index and returns the value that was at the previous index location. That should be about it.

Related

How to Initialize a Min Heap?

I'm trying to figure out how I can initialize a min heap using an array. So far my function looks like this:
def start_heap(self,n):
# None positions to be filled with Nodes
arr = [none][] * n
for i in arr:
heapify(i)
def heapify(self):
start = self.parent(len(self) - 1) # Start at parent of last leaf
for j in range(start, -1, -1): # going to and including the root.
self.heapify_down(j)
def heapify_down(self, i):
n = len(self._pq)
left, right = self.left(i), self.right(i)
if left < n:
child = left
if right < n and self.pq[right] < self.pq[left]:
child = right
if self.pq[child] < self.pq[i]:
self.swap(i, child)
self.heapify_down(child)
Heapify Down Pseudocode:
Heapify-down(H,i): Let n = length(H) If 2i>n then
Terminate with H unchanged Else if 2i<n then
Let left=2i, and right=2i+1
Let j be the index that minimizes key[H[left]] and key[H[right]] Else if 2i=n then
Let j=2i Endif
If key[H[j]] < key[H[i]] then
swap the array entries H[i] and H[j] Heapify-down(H , j)
Endif
I'm going to build a simple node class that just holds data but I'm not sure how to actually get the start_heap function working. Keep in mind n is the maximum number of elements that can be stored.
Some remarks on the code you provided (not on the code you didn't provide):
arr is a local variable, so whatever you do with it, once the function returns, that arr will be out of scope... and lost. You need an attribute or else subclass list
It is not common practice to "allocate" the array and fill it with None. In Python lists are dynamic, so you don't need to reserve slots ahead of time. You just need an empty list to start with.
There is no need to call heapify when the heap is empty.
There is certainly no need to call heapify many times in a loop. All the logic for heapifying is already present in that method, so no need to call it on each index individually. But as stated in the previous point: no need to call it on an empty list -- there is nothing to move.
So the correction is quite basic:
def start_heap(self, max_size):
self.max_size = max_size
self._pq = []
Then, in many of your other methods, you will have to work with self._pq and self.max_size.
For instance, it could have a method that indicates whether the heap is full:
def is_full(self):
return len(self._pq) >= self.max_size
If you have an add method, it would first check if there is still room:
def add(self, node):
if is_full(self):
raise ValueError("Cannot add value to the heap: it is full")
# ... rest of your code ...

Rotate a linked list k times (Python)

While practicing for my final in Python programming I ran into this question "def rotaten" of rotating k times. The problem says that k can range from 0 to any positive integer number (even greater than list size, if k < 0 raise ValueError
and it must execute in O( (n-k)%n ) where n is the length of the list. It also has the following warnings:
WARNING: DO NOT call .rotate() k times !!!!
WARNING: DO NOT try to convert whole linked list to a python list
WARNING: DO NOT swap node data or create nodes
The problem is that I'm not understanding the solution given. Is there an easier way to solve this problem? Thank you in advance
class Node:
def __init__(self,initdata):
self._data = initdata
self._next = None
def get_data(self):
return self._data
def get_next(self):
return self._next
def set_data(self,newdata):
self._data = newdata
def set_next(self,newnext):
self._next = newnext
class LinkedList:
def rotaten(self, k):
if k < 0:
raise ValueError
if self._size > 1:
m = k % self._size
if m > 0 and m < self._size:
current = self._head
for i in range(self._size - m - 1):
current = current.get_next()
chain_b = current.get_next()
old_head = self._head
old_last = self._last
self._last = current
self._last.set_next(None)
self._head = chain_b
old_last.set_next(old_head)
The easiest ways are forbidden
warning forbids implementing the singular rotation, then calling it repeatedly
warning forbids using native python structure - python has list built-in in basic collections list(), which can be then transformed to a deque, which can then be rotated by popping from the end and inserting the same node to the beginning.
warning is preventing you from making your life easier by creating some other nodes or worse - copying data. (copying data from one node to another would remove any advantage you had from storing the data into the lists in the first place)
The example solution is basically this:
Take the current first node(head of the list) and the tail node which is stored in the List structure. (the bookkeeping of the example list consists of holding the head and tail, the rest is done in the nodes themselves)
Find the k-th node - so that you rotate the whole list at once. This is where the list needs to be cut.
Add the last node as the new head, doing all the necessary reference-linking and unlinking. (Which is I guess the point of this question - to test if you understand the references. In C these would be pointers, python has the references implicitly.)
So as far as the linked lists go, this is the most straightforward solution with the requested O((n-k)%n) complexity.
Good luck with your pointers :-).

Making a priority queue using a Heap. Without using "queue" or "heapq"

I have made a heap class and I am trying to make a PriorityQueue class as well so both of them can work together. However, I need help on the Priority Queue part of my code. I have already made a working Heap. I tried looking up help on the internet but I keep getting answers with people using either the "queue" or "heapq" python implementation. Could anyone help me on how to make a working Priority Queue class? I have the basic function names written down but I have no idea on where to go from there. Please I have been stuck on this for awhile and really need some help. Here is my working Heap Code.
class Heap(object):
def __init__(self, items=None):
'''Post: A heap is created with specified items.'''
self.heap = [None]
if items is None:
self.heap_size = 0
else:
self.heap += items
self.heap_size = len(items)
self._build_heap()
def size(self):
'''Post: Returns the number of items in the heap.'''
return self.heap_size
def _heapify(self, position):
'''Pre: Items from 0 to position - 1 satisfy the Heap property.
Post: Heap Property is satisfied for the entire heap.'''
item = self.heap[position]
while position * 2 <= self.heap_size:
child = position * 2
# If the right child, determine the maximum of two children.
if (child != self.heap_size and self.heap[child+1] > self.heap[child]):
child += 1
if self.heap[child] > item:
self.heap[position] = self.heap[child]
position = child
else:
break
self.heap[position] = item
def delete_max(self):
'''Pre: Heap property is satisfied
Post: Maximum element in heap is removed and returned. '''
if self.heap_size > 0:
max_item = self.heap[1]
self.heap[1] = self.heap[self.heap_size]
self.heap_size -= 1
self.heap.pop()
if self.heap_size > 0:
self._heapify(1)
return max_item
def insert(self, item):
'''Pre: Heap Property is Satisfied.
Post: Item is inserted in proper location in heap.'''
self.heap_size += 1
# extend the length of the list.
self.heap.append(None)
position = self.heap_size
parent = position // 2
while parent > 0 and self.heap[parent] < item:
# Move the item down.
self.heap[position] = self.heap[parent]
position = parent
parent = position // 2
# Puts the new item in the correct spot.
self.heap[position] = item
def _build_heap(self):
''' Pre: Self.heap has values in 1 to self.heap_size
Post: Heap property is satisfied for entire heap. '''
# 1 through self.heap_size.
for i in range(self.heap_size // 2, 0, -1): # Stops at 1.
self._heapify(i)
def heapsort(self):
'''Pre: Heap Property is satisfied.
Post: Items are sorted in self.heap[1:self.sorted_size].'''
sorted_size = self.heap_size
for i in range(0, sorted_size -1):
# Since delete_max calls pop to remove an item, we need to append a dummy value to avoid an illegal index.
self.heap.append(None)
item = self.delete_max()
self.heap[sorted_size - i] = item
So this is working but like I previously stated I am having trouble on how to make a priority queue out of this? I know asking for code is wrong, but I'm desperate could anyone help me out here? I have the basic rundown on what I want my priority code to do..
#PriorityQueue.py
from MyHeap import Heap
class PriorityQueue(object):
def enqueue(self, item, priority):
'''Post: Item is inserted with specified priority in the PQ.'''
def first(self):
'''Post: Returns but does not remove the highest priority item from the PQ.'''
def dequeue(self):
'''Post: Removes and returns the highest priority item from the PQ.'''
def size(self):
'''Post: Returns the number of items in the PQ.'''
return Heap.heap_size
I think the key idea you're missing to implement your PriorityQueue class is that each PriorityQueue instance should have a Heap instance as an attribute. Set it up in __init__:
class PriorityQueue(object):
def __init__(self)
self.heap = Heap()
When a user makes a call to a PriorityQueue method, that method will mostly just make a call to a method of self.heap, with just a little extra work modifying the arguments or the return value. The items to insert into the heap should probably be (priority, value) tuples, since they will compare appropriately (higher priority items comparing higher).
Note that if you compare code written for heapq with your Heap, you'll need to modify the logic for the indexes and priorities, since heapq implements a zero-indexed min-heap, and your code implements a one-indexed max-heap.

Priority Queues: Enqueue returns 'None' instead of int value

I am having problems with my PriorityQueue class in python. I think I set it up all the way and now I'm trying to test it, but I keep getting the word "None" when I print out the value I am enqueuing which isn't right.
This is my test code, following that is my Output and Expected Output:
from PriorityQueue import PriorityQueue
PQ = PriorityQueue()
print(PQ.enqueue(1, 10))
print(PQ.enqueue(2, 5))
print(PQ.enqueue(3, 90))
print(PQ)
print(PQ.size())
Output:
None
None
None
<PriorityQueue.PriorityQueue object at 0x01EE5250>
2
Expected Output:
10
5
90
90,5,10
2
Why would it print the word None? I have no idea why it would do that. Here is my PriorityQueue class where it gets the functions from.
#PriorityQueue.py
from MyHeap import Heap
class PriorityQueue(object):
def __init__(self):
self.heap = Heap()
def enqueue(self, priority, item):
'''Post: Item is inserted with specified priority in the PQ.'''
self.heap.insert((priority, item))
def first(self):
'''Post: Returns but does not remove the highest priority item from the PQ.'''
return self.heap.size()
def dequeue(self):
'''Post: Removes and returns the highest priority item from the PQ.'''
if self.heap.size() is None:
raise ValueError("Error your queue is empty.")
x = self.first()
self.heap.delete_max()
return x
def size(self):
'''Post: Returns the number of items in the PQ.'''
return self.heap.size()
All these functions, or well most of them take from my custom heap class which is this.
class Heap(object):
def __init__(self, items=None):
'''Post: A heap is created with specified items.'''
self.heap = [None]
if items is None:
self.heap_size = 0
else:
self.heap += items
self.heap_size = len(items)
self._build_heap()
def size(self):
'''Post: Returns the number of items in the heap.'''
return self.heap_size
def _heapify(self, position):
'''Pre: Items from 0 to position - 1 satisfy the Heap property.
Post: Heap Property is satisfied for the entire heap.'''
item = self.heap[position]
while position * 2 <= self.heap_size:
child = position * 2
# If the right child, determine the maximum of two children.
if (child != self.heap_size and self.heap[child+1] > self.heap[child]):
child += 1
if self.heap[child] > item:
self.heap[position] = self.heap[child]
position = child
else:
break
self.heap[position] = item
def delete_max(self):
'''Pre: Heap property is satisfied
Post: Maximum element in heap is removed and returned. '''
if self.heap_size > 0:
max_item = self.heap[1]
self.heap[1] = self.heap[self.heap_size]
self.heap_size -= 1
self.heap.pop()
if self.heap_size > 0:
self._heapify(1)
return max_item
def insert(self, item):
'''Pre: Heap Property is Satisfied.
Post: Item is inserted in proper location in heap.'''
self.heap_size += 1
# extend the length of the list.
self.heap.append(None)
position = self.heap_size
parent = position // 2
while parent > 0 and self.heap[parent] < item:
# Move the item down.
self.heap[position] = self.heap[parent]
position = parent
parent = position // 2
# Puts the new item in the correct spot.
self.heap[position] = item
def _build_heap(self):
''' Pre: Self.heap has values in 1 to self.heap_size
Post: Heap property is satisfied for entire heap. '''
# 1 through self.heap_size.
for i in range(self.heap_size // 2, 0, -1): # Stops at 1.
self._heapify(i)
def heapsort(self):
'''Pre: Heap Property is satisfied.
Post: Items are sorted in self.heap[1:self.sorted_size].'''
sorted_size = self.heap_size
for i in range(0, sorted_size -1):
# Since delete_max calls pop to remove an item, we need to append a dummy value to avoid an illegal index.
self.heap.append(None)
item = self.delete_max()
self.heap[sorted_size - i] = item
Could anyone tell me the problem of why it isn't working? I thought it was supposed to return the value. I also know I need an iter for my PriorityQueue class, but I don't know what it would look like. Could anyone help me?
Your enqueue method doesn't have a return statement, so it returns None.
If you were expecting Python to be like, say, Ruby or Scheme, and return the value of the last expression evaluated--well, Python isn't Ruby; one of the biggest differences is that, unlike Ruby, Python is a statement-based language where not everything is an expression, so there usually is no "last expression", just a last statement, which has no value.
Meanwhile, returning None from a method that mutates self is considered the Pythonic thing to do (see list.append, for example), so you actually wrote your code correctly, even if you didn't intend to. :)
This means that Python doesn't lend itself to the method-chaining "fluent style" that's popular in some other languages. This is a deliberate design choice; although Guido has never really articulated why, consider that a single giant expression doesn't let you see the flow of control through vertical space and horizontal indentation the way a chain of statements does, discourages you from giving meaningful names to meaningful intermediate values, is harder to debug with tracebacks or a traditional step debugger, etc.

A* Search in Python Priority Queue

I am trying to write an A* search to solve a maze in Python, however I am struggling to find a built in priority queue that works for this. I am using PriorityQueue at the moment, but it offers no functionality in order to change an items priority, which is a problem in the commented section at the bottom of the algorithm (in the else if statement).
Does anyone have any idea what I could do in that else if block, or what built in priority queue would give me this functionality?
def A_search(maze, start, end):
expanded = 0 # use to track number of nodes expanded by the algorithm
node1 = Node(start,0)
frontier = PriorityQueue()
frontier.put((dist_to_goal(node1,end) + node1.get_cost(), node1))
visited = []
in_frontier = [] # keep track of items in frontier, PriorityQueue has no way to peek
in_frontier.append(node1)
while(True):
if(frontier == []):
return(None,expanded)
curr = (frontier.get())[1]
in_frontier.remove(curr)
expanded += 1
if(curr.get_loc() == end):
return(curr,expanded)
visited.append(curr.get_loc())
neighbors = find_neighbors(maze, curr.get_loc())
for neighbor in neighbors:
node_n = Node(neighbor,node1.get_cost()+1)
node_n.parent = curr
if(neighbor not in visited) and (node_n not in in_frontier):
frontier.put((dist_to_goal(node_n,end) + node1.get_cost(), node_n))
in_frontier.append(node_n)
# else if node_n is in frontier w/ a higher path cost then replace it w/ current
The closest you will find in the built-in libraries is heapq.
After changing the priority you need to call either heapq.heapify (costs O(n) time but will not change A* overall complexity) or use the internal heapq._siftdown function at O(log n) time.
Updating the item priority, is discussed in the official python documentation about the heapq module in the priority queue implementation notes: https://docs.python.org/3.7/library/heapq.html#priority-queue-implementation-notes
Using these notes, I managed to write my own PriorityQueue Implementation that supports adding a task and updating it's priority if it exists. It consists in using an entry_finder dict which point to tasks in the priority queue. Updating a task's priority, simply consists in marking the existing task as deleted and inserting it with the new priority.
In this implementation, you can use method add_task
class PriorityQueue():
REMOVED = '<removed-task>'
def __init__(self):
self.pq = []
self.entry_finder = {}
self.counter = itertools.count()
def add_task(self, task, priority=0):
if task in self.entry_finder:
self.remove_task(task)
count = next(self.counter)
entry = [priority, count, task]
self.entry_finder[task] = entry
heappush(self.pq, entry)
def remove_task(self, task):
entry = self.entry_finder.pop(task)
entry[-1] = self.REMOVED
def pop_task(self):
while self.pq:
priority, count, task = heappop(self.pq)
if task is not self.REMOVED:
del self.entry_finder[task]
return task
return None

Categories

Resources