#23 Merge k Sorted Lists

题目链接:https://leetcode.com/problems/merge-k-sorted-lists/


Merge k sorted linked lists and return it as one sorted list. Analyze and describe its complexity.


/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
void percolateUp(struct ListNode** lists, int i) {	//前i个元素已有堆序性,上滤第i+1个元素
	struct ListNode* tmp = lists[i];
	while (i > 0 && lists[(i - 1) / 2]->val > tmp->val) {	//将元素到根节点路径上所有比该元素大的节点都下移
		lists[i] = lists[(i - 1) / 2];
		i = (i - 1) / 2;
	}
	lists[i] = tmp;
}
int buildHeap(struct ListNode** lists, int k) {
	int i, size = 0;
	for (i = 0; i < k; ++i)		//依次将非空元素插入堆中
		if (lists[i]) {
			lists[size] = lists[i];
			percolateUp(lists, size);
			++size;
		}
	return size;
}
//只有堆顶元素不满堆序性,使其下滤;即不断将较小儿子移到空穴直到较小儿子也不小于堆顶元素
void percolateDown(struct ListNode** lists, int size) {
	struct ListNode* tmp = lists[0];
	int i = 0, smallChild = 2 * i + 1;	//先记录左儿子为较小儿子,如果右儿子更小,更新
	if (smallChild + 1 < size && lists[smallChild]->val > lists[smallChild + 1]->val)
		++smallChild;
	while (smallChild < size && lists[smallChild]->val < tmp->val) {
		lists[i] = lists[smallChild];
		i = smallChild;
		smallChild = 2 * i + 1;
		if (smallChild + 1 < size && lists[smallChild]->val > lists[smallChild + 1]->val)
			++smallChild;
	}
	lists[i] = tmp;
}
//堆实现优先队列,k个链表首元素建堆,每次弹出堆顶元素;
//删除堆顶元素后重构需要log(k)个操作,总时间复杂度n*log(k)
struct ListNode* mergeKLists(struct ListNode** lists, int listsSize) {
	if (lists == NULL || listsSize <= 0)
		return NULL;
	if (listsSize == 1)
		return lists[0];
	int size;
	struct ListNode* head = (struct ListNode *)malloc(sizeof(struct ListNode));	//哑节点
	struct ListNode* p = head;
	head->next = NULL;					//不可少,否则所有链表为空时无法返回NULL
	size = buildHeap(lists, listsSize);	//将lists按堆序排序,并返回初始堆大小,即非空链表数量
	while (size) {						//只要堆非空,每次弹出堆顶元素,更新堆
		p->next = lists[0];
		p = p->next;
		lists[0] = lists[0]->next;		//更新堆顶元素
		if (lists[0] == NULL) {			//如果堆顶元素为空,将尾部元素移至堆顶
			lists[0] = lists[size - 1];
			--size;
		}
		percolateDown(lists, size);		//下滤堆顶元素使其保持堆序性
	}
	p = head->next;
	free(head);
	return p;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值