python-基于位置列表的优先级队列

优先级队列
优先级队列是一个包含优先级元素的集合,这个集合允许插入任意的元素和删除优先级最高的元素。当一个元素被插入优先级队列中时,用户可以通过提供一个关键键来为该元素赋予一定的优先级。键值越小优先级越高

优先级队列的抽象数据类型实现
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)

操作未排序列表排序列表
LenO(1)O(1)
is_emptyO(1)O(1)
addO(1)O(n)
minO(n)O(1)
remove_minO(n)O(1)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值