合并 K 个已排序链表的 C++ 程序 – 第 1 组
给定 K 个大小为 N 的已排序链表,将它们合并并打印排序后的输出。
例子:
Input: k = 3, n = 4
list1 = 1->3->5->7->NULL
list2 = 2->4->6->8->NULL
list3 = 0->9->10->11->NULL
Output: 0->1->2->3->4->5->6->7->8->9->10->11
Merged lists in a sorted order
where every element is greater
than the previous element.
Input: k = 3, n = 3
list1 = 1->3->7->NULL
list2 = 2->4->8->NULL
list3 = 9->10->11->NULL
Output: 1->2->3->4->7->8->9->10->11
Merged lists in a sorted order
where every element is greater
than the previous element.
方法1(简单):
方法:
一个简单的解决方案是将结果初始化为第一个列表。现在遍历从第二个列表开始的所有列表。将当前遍历列表的每个节点以排序的方式插入到结果中。
C++
// C++ program to merge k sorted
// linked lists of size n each
#include
using namespace std;
// A Linked List node
struct Node
{
int data;
Node* next;
};
/* Function to print nodes in a
given linked list */
void printList(Node* node)
{
while (node != NULL)
{
printf("%d ", node->data);
node = node->next;
}
}
// The main function that takes an
// array of lists arr[0..last] and
// generates the sorted output
Node* mergeKLists(Node* arr[],
int last)
{
// Traverse form second list to last
for (int i = 1; i <= last; i++)
{
while (true)
{
// Head of both the lists,
// 0 and ith list.
Node *head_0 = arr[0],
*head_i = arr[i];
// Break if list ended
if (head_i == NULL)
break;
// Smaller than first element
if (head_0->data >= head_i->data)
{
arr[i] = head_i->next;
head_i->next = head_0;
arr[0] = head_i;
}
else
// Traverse the first list
while (head_0->next != NULL)
{
// Smaller than next element
if (head_0->next->data >=
head_i->data)
{
arr[i] = head_i->next;
head_i->next = head_0->next;
head_0->next = head_i;
break;
}
// go to next node
head_0 = head_0->next;
// if last node
if (head_0->next == NULL)
{
arr[i] = head_i->next;
head_i->next = NULL;
head_0->next = head_i;
head_0->next->next = NULL;
break;
}
}
}
}
return arr[0];
}
// Utility function to create
// a new node.
Node* newNode(int data)
{
struct Node* temp = new Node;
temp->data = data;
temp->next = NULL;
return temp;
}
// Driver code
int main()
{
// Number of linked lists
int k = 3;
// Number of elements in each list
int n = 4;
// an array of pointers storing the
// head nodes of the linked lists
Node* arr[k];
arr[0] = newNode(1);
arr[0]->next = newNode(3);
arr[0]->next->next = newNode(5);
arr[0]->next->next->next = newNode(7);
arr[1] = newNode(2);
arr[1]->next = newNode(4);
arr[1]->next->next = newNode(6);
arr[1]->next->next->next = newNode(8);
arr[2] = newNode(0);
arr[2]->next = newNode(9);
arr[2]->next->next = newNode(10);
arr[2]->next->next->next = newNode(11);
// Merge all lists
Node* head = mergeKLists(arr, k - 1);
printList(head);
return 0;
}
C++
// C++ program to merge k sorted
// linked lists of size n each
#include
using namespace std;
// A Linked List node
struct Node
{
int data;
Node* next;
};
/* Function to print nodes in a
given linked list */
void printList(Node* node)
{
while (node != NULL)
{
printf("%d ", node->data);
node = node->next;
}
}
/* Takes two lists sorted in increasing order,
and merge their nodes together to make one
big sorted list. Below function takes O(n)
extra space for recursive calls, */
Node* SortedMerge(Node* a, Node* b)
{
Node* result = NULL;
// Base cases
if (a == NULL)
return (b);
else if (b == NULL)
return (a);
// Pick either a or b, and recur
if (a->data <= b->data)
{
result = a;
result->next = SortedMerge(a->next, b);
}
else
{
result = b;
result->next = SortedMerge(a, b->next);
}
return result;
}
// The main function that takes an
// array of lists arr[0..last] and
// generates the sorted output
Node* mergeKLists(Node* arr[], int last)
{
// Repeat until only one list is left
while (last != 0)
{
int i = 0, j = last;
// (i, j) forms a pair
while (i < j)
{
// merge List i with List j and
// store merged list in List i
arr[i] = SortedMerge(arr[i], arr[j]);
// consider next pair
i++, j--;
// If all pairs are merged, update
// last
if (i >= j)
last = j;
}
}
return arr[0];
}
// Utility function to create
// a new node.
Node* newNode(int data)
{
struct Node* temp = new Node;
temp->data = data;
temp->next = NULL;
return temp;
}
// Driver code
int main()
{
// Number of linked lists
int k = 3;
// Number of elements in
// each list
int n = 4;
// An array of pointers storing
// the head nodes of the linked lists
Node* arr[k];
arr[0] = newNode(1);
arr[0]->next = newNode(3);
arr[0]->next->next = newNode(5);
arr[0]->next->next->next = newNode(7);
arr[1] = newNode(2);
arr[1]->next = newNode(4);
arr[1]->next->next = newNode(6);
arr[1]->next->next->next = newNode(8);
arr[2] = newNode(0);
arr[2]->next = newNode(9);
arr[2]->next->next = newNode(10);
arr[2]->next->next->next = newNode(11);
// Merge all lists
Node* head = mergeKLists(arr, k - 1);
printList(head);
return 0;
}
输出:
0 1 2 3 4 5 6 7 8 9 10 11
复杂性分析:
- 时间复杂度: O(nk 2 )
- 辅助空间: O(1)。
因为不需要额外的空间。
方法2:最小堆。
更好的解决方案是使用基于 Min Heap 的解决方案,这里讨论了数组。该解决方案的时间复杂度为O(nk Log k)
方法三:分而治之。
在这篇文章中,讨论了分而治之的方法。这种方法不需要额外的堆空间并且工作在 O(nk Log k)
众所周知,两个链表的合并可以在 O(n) 时间和 O(n) 空间内完成。
- 这个想法是配对 K 个列表并使用 O(n) 空间在线性时间内合并每一对。
- 在第一个循环之后,剩下 K/2 个列表,每个列表的大小为 2*N。在第二个循环之后,留下 K/4 个列表,每个列表的大小为 4*N,依此类推。
- 重复这个过程,直到我们只剩下一个列表。
下面是上述思想的实现。
C++
// C++ program to merge k sorted
// linked lists of size n each
#include
using namespace std;
// A Linked List node
struct Node
{
int data;
Node* next;
};
/* Function to print nodes in a
given linked list */
void printList(Node* node)
{
while (node != NULL)
{
printf("%d ", node->data);
node = node->next;
}
}
/* Takes two lists sorted in increasing order,
and merge their nodes together to make one
big sorted list. Below function takes O(n)
extra space for recursive calls, */
Node* SortedMerge(Node* a, Node* b)
{
Node* result = NULL;
// Base cases
if (a == NULL)
return (b);
else if (b == NULL)
return (a);
// Pick either a or b, and recur
if (a->data <= b->data)
{
result = a;
result->next = SortedMerge(a->next, b);
}
else
{
result = b;
result->next = SortedMerge(a, b->next);
}
return result;
}
// The main function that takes an
// array of lists arr[0..last] and
// generates the sorted output
Node* mergeKLists(Node* arr[], int last)
{
// Repeat until only one list is left
while (last != 0)
{
int i = 0, j = last;
// (i, j) forms a pair
while (i < j)
{
// merge List i with List j and
// store merged list in List i
arr[i] = SortedMerge(arr[i], arr[j]);
// consider next pair
i++, j--;
// If all pairs are merged, update
// last
if (i >= j)
last = j;
}
}
return arr[0];
}
// Utility function to create
// a new node.
Node* newNode(int data)
{
struct Node* temp = new Node;
temp->data = data;
temp->next = NULL;
return temp;
}
// Driver code
int main()
{
// Number of linked lists
int k = 3;
// Number of elements in
// each list
int n = 4;
// An array of pointers storing
// the head nodes of the linked lists
Node* arr[k];
arr[0] = newNode(1);
arr[0]->next = newNode(3);
arr[0]->next->next = newNode(5);
arr[0]->next->next->next = newNode(7);
arr[1] = newNode(2);
arr[1]->next = newNode(4);
arr[1]->next->next = newNode(6);
arr[1]->next->next->next = newNode(8);
arr[2] = newNode(0);
arr[2]->next = newNode(9);
arr[2]->next->next = newNode(10);
arr[2]->next->next->next = newNode(11);
// Merge all lists
Node* head = mergeKLists(arr, k - 1);
printList(head);
return 0;
}
输出:
0 1 2 3 4 5 6 7 8 9 10 11
复杂性分析:
假设 N(n*k) 是节点的总数,n 是每个链表的大小,k 是链表的总数。
- 时间复杂度: O(N*log k) 或 O(n*k*log k)
作为函数mergeKLists() 中的外部 while 循环运行 log k 次,并且每次它处理 n*k 个元素。 - 辅助空间: O(N) 或 O(n*k)
因为在 SortedMerge() 中使用了递归并合并最后 2 个大小为 N/2 的链表,所以将进行 N 次递归调用。
请参阅有关 Merge K 排序链表的完整文章 |设置 1 了解更多详情!