================================ 1.4 查找最大或最å°çš„ N ä¸ªå…ƒç´ ================================ ---------- 问题 ---------- æ€Žæ ·ä»Žä¸€ä¸ªé›†åˆä¸èŽ·å¾—æœ€å¤§æˆ–è€…æœ€å°çš„ N ä¸ªå…ƒç´ åˆ—è¡¨ï¼Ÿ ---------- 解决方案 ---------- heapq æ¨¡å—æœ‰ä¸¤ä¸ªå‡½æ•°ï¼š``nlargest()`` å’Œ ``nsmallest()`` å¯ä»¥å®Œç¾Žè§£å†³è¿™ä¸ªé—®é¢˜ã€‚ .. code-block:: python import heapq nums = [1, 8, 2, 23, 7, -4, 18, 23, 42, 37, 2] print(heapq.nlargest(3, nums)) # Prints [42, 37, 23] print(heapq.nsmallest(3, nums)) # Prints [-4, 1, 2] 两个函数都能接å—一个关键å—傿•°ï¼Œç”¨äºŽæ›´å¤æ‚的数æ®ç»“æž„ä¸ï¼š .. code-block:: python portfolio = [ {'name': 'IBM', 'shares': 100, 'price': 91.1}, {'name': 'AAPL', 'shares': 50, 'price': 543.22}, {'name': 'FB', 'shares': 200, 'price': 21.09}, {'name': 'HPQ', 'shares': 35, 'price': 31.75}, {'name': 'YHOO', 'shares': 45, 'price': 16.35}, {'name': 'ACME', 'shares': 75, 'price': 115.65} ] cheap = heapq.nsmallest(3, portfolio, key=lambda s: s['price']) expensive = heapq.nlargest(3, portfolio, key=lambda s: s['price']) 译者注:上é¢ä»£ç 在对æ¯ä¸ªå…ƒç´ 进行对比的时候,会以 ``price`` 的值进行比较。 ---------- 讨论 ---------- å¦‚æžœä½ æƒ³åœ¨ä¸€ä¸ªé›†åˆä¸æŸ¥æ‰¾æœ€å°æˆ–最大的 N ä¸ªå…ƒç´ ï¼Œå¹¶ä¸” N å°äºŽé›†åˆå…ƒç´ æ•°é‡ï¼Œé‚£ä¹ˆè¿™äº›å‡½æ•°æä¾›äº†å¾ˆå¥½çš„æ€§èƒ½ã€‚ å› ä¸ºåœ¨åº•å±‚å®žçŽ°é‡Œé¢ï¼Œé¦–å…ˆä¼šå…ˆå°†é›†åˆæ•°æ®è¿›è¡Œå †æŽ’åºåŽæ”¾å…¥ä¸€ä¸ªåˆ—表ä¸ï¼š .. code-block:: python >>> nums = [1, 8, 2, 23, 7, -4, 18, 23, 42, 37, 2] >>> import heapq >>> heap = list(nums) >>> heapq.heapify(heap) >>> heap [-4, 2, 1, 23, 7, 2, 18, 23, 42, 37, 8] >>> å †æ•°æ®ç»“构最é‡è¦çš„ç‰¹å¾æ˜¯ ``heap[0]`` 永远是最å°çš„å…ƒç´ ã€‚å¹¶ä¸”å‰©ä½™çš„å…ƒç´ å¯ä»¥å¾ˆå®¹æ˜“的通过调用 ``heapq.heappop()`` 方法得到, è¯¥æ–¹æ³•ä¼šå…ˆå°†ç¬¬ä¸€ä¸ªå…ƒç´ å¼¹å‡ºæ¥ï¼Œç„¶åŽç”¨ä¸‹ä¸€ä¸ªæœ€å°çš„å…ƒç´ æ¥å–ä»£è¢«å¼¹å‡ºå…ƒç´ ï¼ˆè¿™ç§æ“ä½œæ—¶é—´å¤æ‚度仅仅是 O(log N),N æ˜¯å †å¤§å°ï¼‰ã€‚ æ¯”å¦‚ï¼Œå¦‚æžœæƒ³è¦æŸ¥æ‰¾æœ€å°çš„ 3 ä¸ªå…ƒç´ ï¼Œä½ å¯ä»¥è¿™æ ·åšï¼š .. code-block:: python >>> heapq.heappop(heap) -4 >>> heapq.heappop(heap) 1 >>> heapq.heappop(heap) 2 å½“è¦æŸ¥æ‰¾çš„å…ƒç´ ä¸ªæ•°ç›¸å¯¹æ¯”è¾ƒå°çš„æ—¶å€™ï¼Œå‡½æ•° ``nlargest()`` å’Œ ``nsmallest()`` 是很åˆé€‚的。 å¦‚æžœä½ ä»…ä»…æƒ³æŸ¥æ‰¾å”¯ä¸€çš„æœ€å°æˆ–最大(N=1ï¼‰çš„å…ƒç´ çš„è¯ï¼Œé‚£ä¹ˆä½¿ç”¨ ``min()`` å’Œ ``max()`` 函数会更快些。 类似的,如果 N 的大å°å’Œé›†åˆå¤§å°æŽ¥è¿‘的时候,通常先排åºè¿™ä¸ªé›†åˆç„¶åŽå†ä½¿ç”¨åˆ‡ç‰‡æ“作会更快点 ( ``sorted(items)[:N]`` 或者是 ``sorted(items)[-N:]`` )。 需è¦åœ¨æ£ç¡®åœºåˆä½¿ç”¨å‡½æ•° ``nlargest()`` å’Œ ``nsmallest()`` æ‰èƒ½å‘挥它们的优势 (如果 N 快接近集åˆå¤§å°äº†ï¼Œé‚£ä¹ˆä½¿ç”¨æŽ’åºæ“作会更好些)。 å°½ç®¡ä½ æ²¡æœ‰å¿…è¦ä¸€å®šä½¿ç”¨è¿™é‡Œçš„æ–¹æ³•ï¼Œä½†æ˜¯å †æ•°æ®ç»“构的实现很有趣,值得深入å¦ä¹ 。 基本上åªè¦æ˜¯æ•°æ®ç»“构和算法书ç±é‡Œé¢éƒ½ä¼šæœ‰æåŠåˆ°ã€‚ ``heapq`` 模å—的官方文档里é¢ä¹Ÿè¯¦ç»†çš„介ç»äº†å †æ•°æ®ç»“构底层的实现细节。