优先级队列
优先级队列是一个包含优先级元素的集合,这个集合允许插入任意的元素和删除优先级最高的元素。当一个元素被插入优先级队列中时,用户可以通过提供一个关键键来为该元素赋予一定的优先级。键值越小优先级越高
优先级队列的抽象数据类型实现
p.add(k,v):向优先级队列P中插入一个拥有键k和值v的元组
p.min()返回一个元组(k,v),代表优先级队列P中一个包含键和值的元组,该元组的键值是最小值,但没有移除该元组
p.remove_min():从优先级队列中移除一个拥有最小键值的元组并返回这个元组,如果队列为空返回错误
P.is_empty()如果优先级队列中不包括任何元组返回True
Len(T)返回优先级队列中的元组数目
优先级队列的基类
其中Item将键和值组成单独的对象
class PriorityQueueBase:
class _Item:
def __init__(self,k,v):#初始化
self._key=k#键
self._value=v#值
def __It__(self,other):#基于键值比较两个对象
return self._key<other._key
def is_empty(self):#判断优先级队列是否为空
return len(self)==0
优先级队列实现
无序指的是队列中的元素不会按键值大小排好序, 只是按照先后次序入队列这样可能会导致键值小的排在键值大的后面
以下队列实现基于一个位置列表(基于双向链表的位置列表)作为存储结构
双向链表以及位置列表
class Empty(Exception):
pass
class _DoublyLinkedBase:#双向链表
class _Node:
def __init__(self,element,prev,next):
self._element=element
self._prev=prev
self._next=next
def __init__(self):
self._header=self._Node(None,None,None)
self._tailer=self._Node(None,None,None)
self._header._next=self._tailer
self._tailer._prev=self._header
self._size=0
def __len__(self):
return self._size
def is_empty(self):
return self._size==0
def _insert_between(self,e,predecessor,successor):
newest=self._Node(e,predecessor,successor)
predecessor._next=newest
successor._prev=newest
self._size+=1
return newest
def _delete_node(self,node):
predecessor=node._prev
successor=node._next
predecessor._next=successor
successor._prev=predecessor
self._size-=1
element=node._element
node._prev=node._next=node._element=None
return element
class PositionalList(_DoublyLinkedBase):#基于双向链表实现的位置列表
class Position:
def __init__(self,container,node):
self._container=container
self._node=node
def element(self):
return self._node._element
def __eq__(self,other):
return type(other) is type(self) and other._node is self._node
def __ne__(self,other):
return not (self==other)
def _validate(self,p):
if not isinstance(p,self.Position):
raise TypeError('p must be proper Position type')
if p._container is not self:
raise ValueError('p does not belong to this container')
if p._node._next is None:
raise ValueError('p is no longer vaild')
return p._node
def _make_position(self,node):
if node is self._header or node is self._tailer:
return None
else:
return self.Position(self,node)
def first(self):
return self._make_position(self._header._next)
def last(self):
return self._make_position(self._tailer._prev)
def before(self,p):
node=self._validate(p)
return self._make_position(node._prev)
def after(self,p):
node=self._validate(p)
return self._make_position(node._next)
def travel(self):
cursor=self.first()
while cursor is not None:
print(cursor.element())
cursor=self.after(cursor)
def _insert_between(self,e,predecessor,successor):
node=super()._insert_between(e,predecessor,successor)
return self._make_position(node)
def add_first(self,e):
return self._insert_between(e,self._header,self._header._next)
def add_last(self,e):
return self._insert_between(e,self._tailer._prev,self._tailer)
def add_before(self,p,e):
original=self._validate(p)
return self._insert_between(e,original._prev,original)
def add_after(self,p,e):
original=self._validate(p)
return self._insert_between(e,original,original._next)
def delete(self,p):
original=self._validate(p)
return self._delete_node(original)
def replace(self,p,e):
original=self._validate(p)
old_value=original._element
original._element=e
return old_value
使用无序列表实现优先级队列
class UnsortedPriorityQueue(PriorityQueueBase):
def __init__(self):
self._data=PositionalList()
def _find_min(self):
if self.is_empty():
raise Empty('Priority queue is empty')
small=self._data.first()
walk=self._data.after(small)
while walk is not None:
if walk.element()<small.element():
small=walk
walk=self._data.after(walk)
return small
def __len__(self):
return len(self._data)
def add(self,key,value):
self._data.add_last(self._Item(key,value))
def min(self):
p=self._find_min()
item=p.element()
return (item._key,item._value)
def remove_min(self):
p=self._find_min()
item=self._data.delete(p)
return (item._key,item._value)
使用排序列表实现优先级队列
使用位置列表,列表中的元组以键值递增的顺序进行排序。这样可以保证列表的第一个元组是拥有最小键值的元组
class SortedPriorityQueue(PriorityQueueBase):
def __init__(self):
self._data=PositionalList()
def __len__(self):
return len(self._data)
def add(self,key,value):#插入的时候从后往前寻找第一个比该元素键值小的元素然后插入到它的后面
newest=self._Item(key,value)
walk=self._data.last()
while walk is not None and newest.__It__(walk.element()):
walk=self._data.before(walk)
if walk is None:
self._data.add_first(newest)
else:
self._data.add_after(walk,newest)
def min(self):
if self.is_empty():
raise Empty('Priority queue is empty')
p=self._data.first()
node=p.element()
return (node._key,node._value)
def remove_min(self):
if self.is_empty():
raise Empty('Priority queue is empty')
node=self._data.delete(self._data.first())
return (node._key, node._value)
两种方式实现优先级队列效率
基于无序列表的优先级队列: 插入的时候不用考虑顺序,直接插入到队列末尾即可,基于双向链表的存储结构 插入的时间复杂度是O(1)。而删除时需要找到键值最小的元素,当我们从头开始找时,最坏的情况下,键值最小的元素在队列末尾,所以时间复杂度是O(n) n是队列中的元素个数
基于排序列表的优先级队列:删除:因为队列已经排好序,所以队首元素键值最小,直接删除队首元素即可,基于双向链表的存储结构,删除队首元素时间复杂度为O(1),而插入元素时我们需要找到第一个比插入的元素键值小的元素,当从队尾开始往前寻找最坏的情况下已经在队列中的所有元素的键值都比该元素的键值大,需要查找n次所以时间复杂度是O(n) n是队列中的元素个数
大小为n的优先级队列的各方法在最坏情况下的运行时间。假设列表是双向链表实现的,其空间使用量为O(n)
操作 | 未排序列表 | 排序列表 |
---|---|---|
Len | O(1) | O(1) |
is_empty | O(1) | O(1) |
add | O(1) | O(n) |
min | O(n) | O(1) |
remove_min | O(n) | O(1) |