題目鏈接: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;
}