1.5 实现优先级队列
问题:
实现一个队列,能够按照给定的优先级排序,并且每次pop操作时都可以返回优先级最高的那个元素.
解决方案
1.import heapq
2.class PriorityQueue:
3. def __init__(self):
4. self._queue=[]
5. self._index=0
6. def push(self,item,priority):
7. heapq.heappush(self._queue,(-priority,self._index,item))
8. self._index +=1
9. def pop(self):
10. return heapq.heappop(self._queue)[-1]
11.
12.
13.class Item:
14. def __init__(self,name):
15. self.name = name
16. def __repr__(self):
17. return 'Item({!r})'.format(self.name)
18.
19.q=PriorityQueue()
20.q.push(Item('foo'),3)
21.q.push(Item('bar'),4)
22.q.push(Item('spam'),3)
23.
24.print(q.pop())
25.print(q.pop())
26.print(q.pop())
讨论
- 这段代码的核心在于heapq中的push和pop操作. push和pop的复杂度为O(logN)总的来说,效率相对较高.
- heapq是一个最小堆. 也就是说,堆中的对象必须是可以比较大小的. 而Item的实例并不能比较大小. 所以我们可以构造一个元组(priority,item)但是这样做不到所有数据的唯一性. 因此,再加一个index
知识补充
heapq模块
- heap是一个二叉树结构,初始化为一个空列表. 其父节点永远比子节点小.heap[k] <= heap[2*k+1] and heap[k] <= heap[2*k+2] for all k, counting elements from zero.
- python中的heap是一个最小堆,也就是说,heap[0]永远是最小的那个元素.
- 常用函数:
- heapq.heappush(heap,item) push操作
- heapq.heappop(heap) pop操作,每次返回heap[0],如果heap空了,则抛出IndexError异常
- heapq.heappushpop(heap, item) push&pop
- heapq.heapify(x) 将一个list转化为heap
- heapq.heapreplace(heap, item) 与pushpop不同,这个是先pop再push. 如果遇到空的heap会出现IndexError的异常.
- heapq.merge(*iterables, key=None, reverse=False) 合并,不知道有啥用…
- heapq.nlargest(n, iterable, key=None)
- heapq.nsmallest(n, iterable, key=None)
比如实现一个简单的堆排序
1.def heapsort(iterable):
2. h=[]
3. for value in iterable:
4. heapq.heappush(h,value)
5. return[heapq.heappop(h) for i in range(len(h))]
repr和str函数
所有官方文档都在说,str函数是给人看的,repe函数是给编译器看的.
1. class Item:
2. def __init__(self,name):
3. self.name = name
4. def __str__(self):
5. return 'here is {0} __str__ function'.format(self.name)
6. def __repr__(self):
7. return 'here is {0} __repr__ function'.format(self.name)
8.>>> boo = Item('boo')
9.>>> boo
10.here is boo __repr__ function
11.>>> print(boo)
12.here is boo __str__ function
通过上面这段代码简单来看,在repr函数没有重载的时候,默认会显示<main.Item object at 0x03CC1D70>类似这个样子,是一个地址. 也就是说这两个函数都是用来显示关于这个类的信息的. 而print函数会调用str函数,解释器会调用repr函数.
format()函数
format函数用于做str的格式化书写.可以使用{}来做占位符以提供一个模板.
比如:
1.#1.使用数字占位符
2.>>> "User ID: {0}".format("root")
3.'User ID: root'
4.#2.使用类似变量的占位符
5.>>> 'User ID: {uid} Last seen: {last_login}'.format(uid='root',last_login = '5 Mar 2008 07:20')
6.'User ID: root Last seen: 5 Mar 2008 07:20'
7.#3.大括号的转义
8.format("Empty dict: {{}}")
9.#4.在字典中使用
10.>>> d2={'jim':25,'tom':27}
11.>>> "jim's age is {0[jim]}".format(d2)
12."jim's age is 25"
另外关于三个控制字符,Three conversion flags are currently supported: ‘!s’ which calls str() on the value, ‘!r’ which calls repr() and ‘!a’ which calls ascii().
>>> '{0},{1!r}'.format(boo,boo)
'here is boo __str__ function,here is boo __repr__ function'
更具体的用法查文档吧…