k路归并排序

题目:给定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).根据这种思路则不难实现其代码了。


  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
归并排序是一种基于分治思想的排序算法,在K归并排序中,将数组分成K组,每一组进行归并排序,最后将K个有序数组合并成一个有序数组。以下是K归并排序的C语言实现: ```c #include <stdio.h> #include <stdlib.h> // 归并函数 void merge(int *arr, int start, int mid, int end) { int len1 = mid - start + 1; int len2 = end - mid; int *temp1 = (int*)malloc(sizeof(int)*len1); int *temp2 = (int*)malloc(sizeof(int)*len2); int i, j, k; for (i = 0; i < len1; i++) { temp1[i] = arr[start + i]; } for (j = 0; j < len2; j++) { temp2[j] = arr[mid + 1 + j]; } i = j = 0; k = start; while (i < len1 && j < len2) { if (temp1[i] <= temp2[j]) { arr[k++] = temp1[i++]; } else { arr[k++] = temp2[j++]; } } while (i < len1) { arr[k++] = temp1[i++]; } while (j < len2) { arr[k++] = temp2[j++]; } free(temp1); free(temp2); } // K归并函数 void merge_k(int *arr[], int n, int k, int *result) { int i, j, start, end, mid; int *pos = (int*)malloc(sizeof(int)*k); for (i = 0; i < k; i++) { pos[i] = 0; } for (i = 0; i < n; i++) { result[i] = arr[i][0]; } for (i = 0; i < n*k; i++) { int min = result[0], min_index = 0; for (j = 1; j < n; j++) { if (pos[j] < k && result[j*k+pos[j]] < min) { min = result[j*k+pos[j]]; min_index = j; } } if (min_index == 0) { start = 0; } else { start = min_index*k+pos[min_index]; } end = (min_index+1)*k-1; if (end >= n*k) { end = n*k-1; } mid = (start + end) / 2; merge(result, start, mid, end); pos[min_index]++; } free(pos); } int main() { int n, k, i, j; printf("请输入数组个数n和每个数组的元素个数k:"); scanf("%d %d", &n, &k); int **arr = (int**)malloc(sizeof(int*)*n); int *result = (int*)malloc(sizeof(int)*n*k); for (i = 0; i < n; i++) { arr[i] = (int*)malloc(sizeof(int)*k); printf("请输入第%d个数组:", i+1); for (j = 0; j < k; j++) { scanf("%d", &arr[i][j]); } } merge_k(arr, n, k, result); printf("排序后的结果为:"); for (i = 0; i < n*k; i++) { printf("%d ", result[i]); } printf("\n"); free(result); for (i = 0; i < n; i++) { free(arr[i]); } free(arr); return 0; } ``` 以上代码实现了K归并排序的基本思想,通过归并排序将K个数组分别排序后再进行合并。程序中通过一个pos数组来记录每个数组中已经处理的元素个数,每次选择K个数组中最小的元素进行合并,合并结束后更新pos数组。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值