0

I have designed a circular priority queue. But it took me a while because it is so conditional and has a bit much of a time complexity.

I implemented it using a list. But I need a more efficient circular priority queue implementation.

I'll illustrate my queue structure, sometimes it would be helpful for someone who seeks for a code to understand circular priority queues.

class PriorityQueue:

    def __init__(self,n,key=None):
        if key is None:
            key=lambda x:x
        self.maxsize = n
        self.key=key
        self.arr = list(range(self.maxsize))
        self.rear = -1
        self.front = 0
        self.nelements=0

    def isPQueueful(self):
        return self.nelements==self.maxsize

    def isPQueueempty(self):
        return self.nelements==0

    def insert(self, item):

        if not self.isPQueueful():
            pos=self.rear+1
            scope = range(self.rear - self.maxsize, self.front - self.maxsize - 1, -1)
            if self.rear==0 and self.rear<self.front:
                scope=range(0,self.front-self.maxsize-1,-1)
            for i in scope:
                if self.key(item)>self.key(self.arr[i]):
                    self.arr[i+1]=self.arr[i]
                    pos=i
                else:
                    break
            self.rear+=1
            if self.rear==self.maxsize:
                self.rear=0
            if pos==self.maxsize:
                pos=0
            self.arr[pos]=item
            self.nelements+=1
        else:
            print("Priority Queue is full")

    def remove(self):

        revalue=None
        if not self.isPQueueempty():
            revalue=self.arr[self.front]
            self.front+=1
            if self.front==self.maxsize:
                self.front=0
            self.nelements-=1

        else:
            print("Priority Queue is empty")
        return revalue

I really appreciate if someone can say whether what I designed is suitable for used in a production code. I think mostly it is not an efficient one.

If so can you point out to me how to design a efficient circular priority queue?

Clarke
  • 185
  • 10
  • @jonrsharpe It handles priority by taking a `key` function and based on its return value for an entry, this algorithm chooses the correct spot for the entry. – Clarke May 15 '20 at 17:24
  • Ah, I see. Some docstrings might help make the code more understandable. – jonrsharpe May 15 '20 at 17:25
  • @jonrsharpe yeah I'm sorry I didn't include it as I'm not happy with my code. – Clarke May 15 '20 at 17:26
  • 1
    What does "circular priority queue" even mean? – Matt Timmermans May 15 '20 at 21:52
  • It is not at all clear what you're trying to build. Are you just trying to build a priority queue that has a fixed capacity? What benefit does "circular" give you? – Jim Mischel May 15 '20 at 22:10
  • @MattTimmermans When I build a priority queue normally with a rear and a front, think of the moment when the queue is full. But if I remove an item from the front, their is another slot for another item. But still the rear is at the end of the array. So still it says the queue is full. that's why needed a circular priority queue. It will use any opening slot for a new item. – Clarke May 16 '20 at 06:42
  • @JimMischel Yes I just want a priority queue that has a fixed capacity but not just that. If I build it with rear pointing to the end and front pointing to the first element think of the moment when the array gets full and we remove an item. So their is another slot for a new item. So I need a circular priority queue to add an item to the newly opened slot. It cannot be done because the new slot is at the begining and the rear is at the end. – Clarke May 16 '20 at 06:47
  • OIC, you are implementing a priority queue by keeping it sorted, which leads to this question about circularity. That's a very inefficient way to implement a priority queue. A priority queue is most often implemented with a binary heap array, which is much more efficient, and also keeps all the data packed in the front of the array: https://en.wikipedia.org/wiki/Binary_heap – Matt Timmermans May 16 '20 at 12:29
  • @MattTimmermans Thank you so much, all I searched for this has something called `heap` I still don't know it. So I will learn it. Then I will implement it. I'm glad you got what I was trying to do. – Clarke May 16 '20 at 14:12
  • If you keep the array sorted in reverse order, then your highest priority item is always the last item in the array. Your `remove` could pull from the end. That eliminates the need for your "circular" functionality. Yes, the Binary heap is the better way to go. But then, Python already has heapq and PriorityQueue built in. – Jim Mischel May 16 '20 at 14:31
  • @JimMischel I think I'll go through heaps to understand it. Your suggestion is good, but everytime when inserting an item, we'd have to copy the whole the array in to a new one and then sort it and then again make it a queue. – Clarke May 16 '20 at 17:05
  • No, you wouldn't have to copy the array and sort it. Right now you're doing an insert operation in a circular queue. I'm just suggesting you do an insert operation in a linear list, in reverse order. Your current implementation makes sure that your top priority item is at `self.arr[self.front]`. I'm just suggesting that you have the list sorted such that the top priority item is at `self.arr[self.nelements-1]`. No copy/sort required. – Jim Mischel May 17 '20 at 05:12
  • An easier way to do a priority queue in a linear list is to just add the element at the end of the array. For `remove` you iterate over the entire list to find the top priority item, save it, and then replace the item in that position with the last item in the list. That's a lot easier than keeping the list sorted. The algorithmic complexity is the same. If you keep the list sorted, it's O(n) to insert, and O(1) to remove. This way, it's O(1) to insert, and O(n) to remove. But removal involves moving only 1 item. But, yes, a heap is a better solution overall. – Jim Mischel May 17 '20 at 05:15

1 Answers1

1

So, think of the interface and implementation separately.

The interface to a circular priority queue will make you think that the structure is a circular queue. It has a "highest" priority head and the next one is slightly lower, and then you get to the end, and the next one is the head again.

The methods you write need to act that way.

But the implementation doesn't actually need to be any kind of queue, list, array or linear structure.

For the implementation, you are trying to maintain a set of nodes that are always sorted by priority. For that, it would be better to use some kind of balanced tree (for example a red-black tree).

You hide that detail below your interface -- when you get to the end, you just reset yourself to the beginning -- your interfaces makes it look circular.

Lou Franco
  • 87,846
  • 14
  • 132
  • 192