python 堆和优先队列的使用

发布时间:2019-09-05 07:33:58编辑:auto阅读(1535)

    1.heapq

    python里面的堆是通过在列表中维护堆的性质实现的。这一点与C++中heap一系列的算法类似,底层是通过堆vector的维护获取堆的性质。
    python堆的部分API,其他API查阅文档python_heap_API
    heapq的源代码

    import heapq
    #向堆中插入元素,heapq会维护列表heap中的元素保持堆的性质
    heapq.heappush(heap, item)
    #heapq把列表x转换成堆
    heapq.heapify(x)
    #从可迭代的迭代器中返回最大的n个数,可以指定比较的key
    heapq.nlargest(n, iterable[, key])
    #从可迭代的迭代器中返回最小的n个数,可以指定比较的key
    heapq.nsmallest(n, iterable[, key])
    #从堆中删除元素,返回值是堆中最小或者最大的元素
    heapq.heappop(heap)

    1.1.内置类型

    从上述源代码可以看出来,heapq使用的内置的小于号,或者类的__lt__比较运算来进行比较。

    def heapq_int():
        heap = []
        #以堆的形式插入堆
        heapq.heappush(heap,10)
        heapq.heappush(heap,1)
        heapq.heappush(heap,10/2)
        [heapq.heappush(heap,i) for i in  range(10)]
        [heapq.heappush(heap,10 - i) for i in  range(10)]
        #最大的10个元素
        print heapq.nlargest(10,heap)
        #输出所有元素
        print [heapq.heappop(heap) for i in range(len(heap))]

    1.2.元组类型

    元素会默认调用内置比较函数cmp

    def heapq_tuple():
        heap = []
        #向推中插入元组
        heapq.heappush(heap,(10,'ten'))
        heapq.heappush(heap,(1,'one'))
        heapq.heappush(heap,(10/2,'five'))
        while heap:
            print heapq.heappop(heap),
        print

    1.2.类类型

    类类型,使用的是小于号_lt_,当然没有重写但是有其他的比较函数例如:_le_,_gt_,_cmp_,也是会调用的,和小于号等价的都可以调用(测试了gt),具体的这些操作之间的关系我也没有研究过。如果类里面没有重写_lt_,会调用其他的比较操作符,从源代码可以看出来,如果没有_lt_,那么会调用_ge_函数。
    所以可以重写上述的那些函数:

    class Skill(object):
        def __init__(self,priority,description):
            self.priority = priority
            self.description = description
        def __lt__(self,other):#operator < 
            return self.priority < other.priority
        def __ge__(self,other):#oprator >=
            return self.priority >= other.priority
        def __le__(self,other):#oprator <=
            return self.priority <= other.priority
        def __cmp__(self,other):
            #call global(builtin) function cmp for int
            return cmp(self.priority,other.priority)
        def __str__(self):
            return '(' + str(self.priority)+',\'' + self.description + '\')'
    
    def heapq_class():
        heap  = []
        heapq.heappush(heap,Skill(5,'proficient'))
        heapq.heappush(heap,Skill(10,'expert'))
        heapq.heappush(heap,Skill(1,'novice'))
        while heap:
            print heapq.heappop(heap),
        print 

    所以如果要用到自己定义的类型,可以重写上述函数,就可以使用heapq函数了。

    2.PriorityQueue

    PriorityQueue的python源代码PriorityQueue
    从源代码可以看出来,PriorityQueue使用的就是heapq来实现的,所以可以认为两者算法本质上是一样的。当然PriorityQueue考虑到了线程安全的问题。
    下面给出PriorityQueue的部分API和使用方法。
    参考Queue

    #向队列中添加元素
    Queue.put(item[, block[, timeout]])
    #从队列中获取元素
    Queue.get([block[, timeout]])
    #队列判空
    Queue.empty()
    #队列大小
    Queue.qsize()

    2.1.内置类型

    直接调用内置函数cmp进行比较

    try:
        import Queue as Q #python version < 3.0
    except ImportError:
        import queue as Q #python3.*
    def PriorityQueue_int():
        que = Q.PriorityQueue()
        que.put(10)
        que.put(1)
        que.put(5)
        while not que.empty():
            print que.get(),
        print

    2.2.元组类型

    def PriorityQueue_tuple():
        que = Q.PriorityQueue()
        que.put((10,'ten'))
        que.put((1,'one'))
        que.put((10/2,'five'))
        while not que.empty():
            print que.get(),
        print

    2.2.自定义类型

    class Skill(object):
        def __init__(self,priority,description):
            self.priority = priority
            self.description = description
        #下面两个方法重写一个就可以了
        def __lt__(self,other):#operator < 
            return self.priority < other.priority
        def __cmp__(self,other):
            #call global(builtin) function cmp for int
            return cmp(self.priority,other.priority)
        def __str__(self):
            return '(' + str(self.priority)+',\'' + self.description + '\')'
    
    def PriorityQueue_class():
        que = Q.PriorityQueue()
        skill5 = Skill(5,'proficient')
        skill6 = Skill(6,'proficient6')
        que.put(skill6)
        que.put(Skill(5,'proficient'))
        que.put(Skill(10,'expert'))
        que.put(Skill(1,'novice'))
        while not que.empty():
            print que.get(),
        print

    其他的一些方法的使用还是需要参考给出的文档的。
    最后一点,让我比较奇怪的是(可能我并没有找到),没有提供像排序函数那样,指定比较方法函数,这点和c++有点区别。
    这篇文档参考:参考文档

关键字