k路归并排序

时间:2021-12-22 19:34:50

题目:给定k个已序链表,要求尽可能快的将这k个链表合并为一个有序链表。

方案1:

将这k个链表标号为1,2,...,k,对于这k个链表,我们首先合并链表1和链表2,得到一个有序的链表L12,然后将L12和链表3进行合并...直到k个链表均合并完成,最终便能够得到有序的链表L1k,即为这k个链表合并后的有序链表。对于这种思路,可以写出如下的C++代码:

LinkList mergeList(LinkList l1, LinkList l2)
{
if(l1 == NULL) return l2;
if(l2 == NULL) return l1;
LinkList ret = (l1->data > l2->data)?l2:l1;
LinkList p1 = l1, p2 = l2;
while(p1 != NULL && p2 != NULL)
{
if(p1->data > p2->data)
{
LinkList t = p2->next;
p2->next = p1;
p2 = t;
}
else
{
LinkList t = p1->next;
p1->next = p2;
p1 = t;
}
}

return ret;
}

LinkList mergeSortLinkList(LinkList *p, int k)
{
if(p == NULL || k == 0) return NULL;
LinkList finalList=p[0]; //合并后的最终链表
for(int i = 1; i < k; i++)
{
finaleList = mergeList(finaleList, p[i]);
}
return finalList;
}


方案2:

利用一个大小为k的最小堆作为辅助。步骤如下:

1.将k个链表的第一个元素建立一个大小为k的最小堆,复杂度为O(k);

2.从堆中提取最小的那个节点min插入最终链表尾部,复杂度为O(lgk);

3.若min->next不为空,则将其插入堆中,并重新调整堆,复杂度为O(lgk);

4.若堆不为空,则循环进入第2步,否则合并完成

由于对于这k个链表中的每一个元素,要使其插入最终链表的正确位置,都需要经历一个插入堆和从堆中删除的操作。所以整个算法的复杂度为O(n*2lgk)+O(k)=O(nlgk).根据这种思路则不难实现其代码了。