如何合并k个排序列表?

时间:2018-10-15 16:39:11

标签: python arrays list sorting merge

def merge(list1, list2):
    results = []
    while list1 and list2:
        if list1[0] < list2[0]:
            results.append(list1.pop(0))
        else:
            results.append(list2.pop(0))
    results.extend(list1)
    results.extend(list2)
    return results

这是将2个已排序列表合并为1的标准算法。但是,如何将多个已排序列表合并为1?

l = [[8, 10, 12], [4, 5, 9], [2, 11]]  
merge(l)  
>>> [2, 4, 5, 8, 9, 10, 11, 12]

6 个答案:

答案 0 :(得分:2)

您可以将自己的mergereduce结合使用:

from functools import reduce

l = [[8, 10, 12], [4, 5, 9], [2, 11]]

merged = reduce(merge, l)
print(merged)
# [2, 4, 5, 8, 9, 10, 11, 12]

这是运行时间 O(kn)。您可以合并(唯一)对,直到剩下最后一个列表,这将使列表增加到 O(n log k)(因为要合并的列表数每次都会减少一半)。

答案 1 :(得分:1)

您可以使用sorted()对其进行排序:

from itertools import chain

l = [[8, 10, 12], [4, 5, 9], [2, 11]]

sorted(chain(*l))

给出结果:

[2, 4, 5, 8, 9, 10, 11, 12]

答案 2 :(得分:1)

您可以使用direct k-way mergeheap来实现queues

import heapq
from collections import deque


def k_merge(*lists):
    queues = [queue for queue in map(deque, lists)]

    heap = []
    for i, lst in enumerate(queues):
        heap.append((lst.popleft(), i))

    heapq.heapify(heap)

    result = []
    while heap:
        value, index = heapq.heappop(heap)
        result.append(value)

        if queues[index]:
            heapq.heappush(heap, (queues[index].popleft(), index))

    return result


print(k_merge(*[[8, 10, 12], [4, 5, 9], [2, 11]]))

输出

[2, 4, 5, 8, 9, 10, 11, 12]

如果您有k个列表和n个元素,则此方法为O(nlogk)

答案 3 :(得分:0)

使用列表理解进行平整,然后进行排序

print(sorted([j for i in l for j in i]))
# [2, 4, 5, 8, 9, 10, 11, 12]

答案 4 :(得分:0)

from Queue import PriorityQueue

class Solution(object):
    def mergeKLists(self, lists):
        """
        :type lists: List[ListNode]
        :rtype: ListNode
        """
        head = point = ListNode(0)
        q = PriorityQueue()
        for l in lists:
            if l:
                q.put((l.val, l))
        while not q.empty():
            val, node = q.get()
            point.next = ListNode(val)
            point = point.next
            node = node.next
            if node:
                q.put((node.val, node))
        return head.next

使用优先级队列可以优化比较过程

  1. 时间复杂度:O(n log(k)),其中k是链表的数量:

    • 每次弹出并插入优先级队列时,比较成本将降低为O(log k)。但是找到具有最小值的节点只会花费O(1)时间。
  2. 空间复杂度:

    • O(n)创建一个新的链表需要O(n)空间
    • O(k)上面的代码适用于就地方法,这会占用O(1)空间。
    • 并且优先级队列(通常使用堆来实现)占用O(k)空间(在大多数情况下,它远远小于N)

答案 5 :(得分:0)

一种简单有效的方法是heapq.merge

>>> lists = [[8, 10, 12], [4, 5, 9], [2, 11]]
>>> list(heapq.merge(*lists))
[2, 4, 5, 8, 9, 10, 11, 12]

看一眼 CPython's implementation,它看起来类似于 direct k-way merge answer,所以我会猜测 heapq.merge 也是 O(n log(k)),尽管docstring 不保证这一点。