1、两两合并
前面我们做过合并两个有序链表,那么这里合并K个有序链表,是否可以联想到合并两个呢?答案是可以的!两两合并。
思路:
1、将lists[0] 和 lists[1]合并,返回给lists[0],此时lists[0]就是0,1合并后的链表。
2、将lists[0] 和 lists[2]合并,返回给lists[0],此时lists[0]就是0,1,2合并后的链表。
........
最后、将lists[0]和lists[K-1]合并,返回给lists[0],那么此时lists[0]就是最终合并后的链表。
则最终代码:
cpp
//两两合并
struct ListNode* merge(struct ListNode* head1, struct ListNode* head2) {
struct ListNode* dummy = (struct ListNode*)malloc(sizeof(struct ListNode));
dummy->val = 0, dummy->next = NULL;
struct ListNode *tmp = dummy, *h1 = head1, *h2 = head2;
while (h1 && h2) {
if (h1->val <= h2->val) {
tmp->next = h1;
h1 = h1->next;
} else {
tmp->next = h2;
h2 = h2->next;
}
tmp = tmp->next;
}
if (h1) {
tmp->next = h1;
}
if (h2) {
tmp->next = h2;
}
return dummy->next;
}
struct ListNode* mergeKLists(struct ListNode** lists, int listsSize) {
if(lists == NULL)//判空
return NULL;
if(listsSize == 0)//判断是否有K == 0的情况
return NULL;
for(int i = 1;i<listsSize;i++)
{
lists[0] = merge(lists[0],lists[i]);
}
return lists[0];
}
2、整合排序
前面我们也写过,将一个乱序的链表排序,那么这里是否可以先将所有链表连接成为一个新链表,再对这个新链表排序呢?答案是可以!
连接链表代码如下:
cpp
struct ListNode* dummyhead = malloc(sizeof(struct ListNode));
dummyhead->val = 0,dummyhead->next = NULL;
struct ListNode* curr = dummyhead;
for(int i = 0;i<listsSize;i++)
{
curr->next = lists[i];
while(curr->next)
{
curr = curr->next;
}
}
struct ListNode* head = dummyhead->next;
用head来代表这个新链表的头。之后我们将前面写的链表排序代码copy一下即可。总代码如下:
cpp
struct ListNode* mergeKLists(struct ListNode** lists, int listsSize) {
struct ListNode* dummyhead = malloc(sizeof(struct ListNode));
dummyhead->val = 0,dummyhead->next = NULL;
struct ListNode* curr = dummyhead;
for(int i = 0;i<listsSize;i++)
{
curr->next = lists[i];
while(curr->next)
{
curr = curr->next;
}
}
struct ListNode* head = dummyhead->next;
int len = 0; //长度
for (struct ListNode* cur = head; cur != NULL; cur = cur->next)
len++;
struct ListNode* dummy = malloc(sizeof(struct ListNode));
dummy->val = 0, dummy->next = head;
//自底向上归并排序
for (int sublen = 1; sublen < len; sublen *= 2) {
struct ListNode *pre = dummy, *cur = dummy->next; //每次从新的头开始记录
while (cur) {
struct ListNode* head1 = cur; //第一个头就是cur
for (int i = 1; i < sublen && cur->next != NULL;
i++) //找1子区间的尾,并且2子区间不为空
{
cur = cur->next;
}
//如果for是在cur->next == NULL结束的,那2子区间头就是空
struct ListNode* head2 = cur->next; // 2子区间的头
cur->next = NULL; //将1子区间分离出来
cur = head2;
//再找2子区间的尾
for (int i = 1; i < sublen && cur != NULL; i++) {
cur = cur->next;
}
struct ListNode* next = NULL; //记录下一组的头
//如果cur为空,说明已经到了整个链表的最后
if (cur != NULL) // cur不为空
{
next = cur->next; //记录下一组的头,可空可不空
cur->next = NULL; //分离2子区间
}
struct ListNode* Merged = merge(head1, head2); //记录每次合并后的头
pre->next = Merged;
while (pre->next) //走到合并后的1,2区间的尾,pre来链接每一组
{
pre = pre->next;
}
cur = next; //进入下一组
}
}
return dummy->next;
}