Descending Order Using Heapq
Solution 1:
As we discussed in the comments, your concerns about copying data when using negated values to flip a min-heap into a max-heap don't matter when you're starting with an empty heap and adding the values as you go. Since that's the use case when finding the running median of a stream of values, negating the values as you add them should work just fine.
Here's a running median generator I wrote just to double check that it works the way I expected:
def running_median(iterable):
left_q = [] # heap of smaller-than-median elements, stored negated
right_q = [] # heap of larger-than-median elementsfor value in iterable:
if len(left_q) == len(right_q): # push to left_q when they're equal sizeif len(right_q) > 0and value > right_q[0]:
value = heapq.heapreplace(right_q, value)
heapq.heappush(left_q, -value)
else: # push to right_q only when it's (strictly) smallerif value < -left_q[0]:
value = -heapq.heapreplace(left_q, -value)
heapq.heappush(right_q, value)
# len(left_q) is always >= len(right_q) so we never yield right_q[0]if len(left_q) > len(right_q):
yield -left_q[0]else:
yield (-left_q[0] + right_q[0]) / 2
The left_q
heap stores the less-than-or-equal-to-median values. Each value is negated when it's pushed, so using the normal min-heap operations on it makes it work like a max-heap. We just need to remember to re-negate any value we take out of it, to get back to the original sign.
Solution 2:
I think you are looking instead for a sorted linked list in this case, I modify someone I found here so it will insert with ascending order (I added the pop function, for some reason it wasn't in the code, but I think you may need it):
# Python program to insert in sorted list# Node class classNode:
# Constructor to initialize the node objectdef__init__(self, data):
self.data = data
self.next = NoneclassLinkedList:
# Function to initialize headdef__init__(self):
self.head = NonedefsortedInsert(self, new_node):
# Special case for the empty linked list if self.head isNone:
new_node.next = self.head
self.head = new_node
# Special case for head at endelif self.head.data <= new_node.data:
new_node.next = self.head
self.head = new_node
else :
# Locate the node before the point of insertion
current = self.head
while(current.nextisnotNoneand
current.next.data > new_node.data):
current = current.next
new_node.next = current.next
current.next = new_node
# Function to insert a new node at the beginningdefpush(self, new_data):
new_node = Node(new_data)
new_node.next = self.head
self.head = new_node
# Utility function to prit the linked LinkedListdefprintList(self):
temp = self.head
while(temp):
print(temp.data),
temp = temp.nextdefpop(self):
val = self.head.data
self.head = self.head.nextreturn val
# Driver program
llist = LinkedList()
new_node = Node(5)
llist.sortedInsert(new_node)
new_node = Node(10)
llist.sortedInsert(new_node)
new_node = Node(7)
llist.sortedInsert(new_node)
new_node = Node(3)
llist.sortedInsert(new_node)
new_node = Node(1)
llist.sortedInsert(new_node)
new_node = Node(9)
llist.sortedInsert(new_node)
print("Create Linked List")
llist.printList()
As you can see, it was just change the >= to <=, it does the job perfectly
Solution 3:
There are private methods for this (tested at python 3.8)
import heapq
if __name__ == '__main__':
a = [1, 3, 2, 5]
heapq._heapify_max(a)
for item inrange(0, len(a)):
print(heapq._heappop_max(a)
And result is
sorted heap 5
sorted heap 3
sorted heap 2
sorted heap 1
But using of private methods maybe looks not enough correct for somebody. For this reason we can change ordering with placing your object inside modified wrapper
classDescOrder:
def__init__(self, entity):
self.entity = entity
def__lt__(self, o):
return self.entity.__gt__(o.entity)
def__repr__(self):
returnstr(self.entity)
defcheck_sorting(a, b):
new_heap = []
for element in a:
heapq.heappush(new_heap, DescOrder(element))
for index inrange(0, len(b)):
assert heapq.heappop(new_heap).entity == b[index]
if __name__ == '__main__':
check_sorting([5, 1, -1, 3, 2], [5, 3, 2, 1, -1])
check_sorting([5, 2, -1, 3, 1], [5, 3, 2, 1, -1])
check_sorting([-1, 2, 5, 3, 1], [5, 3, 2, 1, -1])
Post a Comment for "Descending Order Using Heapq"