Python学习笔记——数据结构和算法(一)
1、解压序列赋值给多个变量
任何的序列(或者是可迭代对象)可以通过一个简单的赋值语句解压并赋值给多个变量。 唯一的前提就是变量的数量必须跟序列元素的数量是一样的。
>>> data = [ 'ACME', 50, 91.1, (2012, 12, 21) ]
>>> name, shares, price, date = data >>> name, shares, price, (year, mon, day) = data >>> name 'ACME' >>> year 2012
如果一个可迭代对象的元素个数超过变量个数时,会抛出一个 ValueError 。可以用*来解决,这个仅支持python3。扩展的迭代解压语法是专门为解压不确定个数或任意个数元素的可迭代对象而设计的。解压出来的始终是列表,如果为空则为空列表。
>>> *trailing, current = [10, 8, 7, 1, 9, 5, 10, 3] >>> trailing [10, 8, 7, 1, 9, 5, 10] >>> current 3 >>> first, *middle, last = grades >>> record = ('ACME', 50, 123.45, (12, 18, 2012)) >>> name, *_, (*_, year) = record >>> name 'ACME' >>> year 2012
2、队列
collections.deque可以生成固定大小,或不限大小的队列。你可以在队列的两端执行添加和弹出元素的操作。在队列两端插入或删除元素时间复杂度都是 O(1)
,而在列表的开头插入或删除元素的时间复杂度为 O(N)
。
>>> q = deque(maxlen=2) >>> q.append(1) >>> q.append(2) >>> q deque([1, 2], maxlen=2) >>> q.append(3) >>> q deque([2, 3], maxlen=2) >>> q = deque() >>> q.append(1) >>> q.append(2) >>> q deque([1, 2]) >>> q.appendleft(3) >>> q deque([3, 1, 2]) >>> q.pop() 2 >>> q deque([3, 1]) >>> q.popleft() 3
3、查找最大和最小的N个元素
heapq模块有两个函数:nlargest()
和 nsmallest()
可以解决这个问题。它们的返回值是一个列表。支持关键字参数。
import heapq nums = [1, 8, 2, 23, 7, -4, 18, 23, 42, 37, 2] heapq.nlargest(3, nums) # [42, 37, 23] heapq.nsmallest(3, nums) # [-4, 1, 2] portfolio = [ {'name': 'IBM', 'shares': 100, 'price': 91.1}, {'name': 'AAPL', 'shares': 50, 'price': 543.22}, {'name': 'FB', 'shares': 200, 'price': 21.09}, ] cheap = heapq.nsmallest(3, portfolio, key=lambda s: s['price']) expensive = heapq.nlargest(3, portfolio, key=lambda s: s['price'])
注意:当要查找的元素个数相对比较小的时候,函数 nlargest()
和 nsmallest()
是很合适的; 如果你仅仅想查找唯一的最小或最大(N=1)的元素的话,那么使用 min()
和 max()
函数会更快些;如果N的大小和集合大小接近的时候,通常先排序这个集合然后再使用切片操作会更快点。
在底层实现里面,首先会先将集合数据进行堆排序后放入一个列表中:
>>> nums = [1, 8, 2, 23, 7, -4, 18, 23, 42, 37, 2] >>> import heapq >>> heapq.heapify(nums) >>> nums [-4, 2, 1, 23, 7, 2, 18, 23, 42, 37, 8] >>> heapq.heappop(nums) -4 >>> heapq.heappop(nums) 1 >>> heapq.heappop(nums) 2
堆数据结构最重要的特征是 heap[0]
永远是最小的元素。并且剩余的元素可以很容易的通过调用 heapq.heappop()
方法得到, 该方法会先将第一个元素弹出来,然后用下一个最小的元素来取代被弹出元素(这种操作时间复杂度仅仅是O(log N),N是堆大小)。
3、实现一个优先级队列
每次pop操作总是返回优先级最高的那个。
import heapq class PriorityQueue: def __init__(self): self._queue = [] self._index = 0 def push(self, item, priority): heapq.heappush(self._queue, (-priority, self._index, item)) self._index += 1 def pop(self): return heapq.heappop(self._queue)[-1]
使用方式
>>> q = PriorityQueue() >>> q.push('foo', 1) >>> q.push('bar', 5) >>> q.push('spam', 4) >>> q.push('grok', 1) >>> q.pop() 'bar' >>> q.pop() 'spam'
_queue中放的元素是tuple,tuple的大小是比较第一个元素大小,如果相同再比较下一个元素。tuple中加入_index是为了将priority相同的元素,按照push先后顺序区分开来,同时也避免如果item不支持比较大小会出现错误的情况。-priority将优先级取反,保证队列中最小的元素函数(priority最大)总是放在_queue[0]。 heapq.heappush()
和 heapq.heappop()
分别在队列 _queue
上插入和删除第一个元素, 操作后,_queue第一个元素总是最小的,从而保证队列_queue第一个元素拥有最高优先级。
参考:《Python Cookbook》3rd Edition
http://python3-cookbook.readthedocs.io/zh_CN/latest/index.html