鉴于已经排序的2个单链表,合并列表。
例:
list1:1 2 3 5 7
list2:0 4 6 7 10
---> 0 1 2 3 4 5 6 7 7 10
尽管解决方案非常简单,并且在使用或不使用递归的情况下有几种不同的问题实现(如此http://www.geeksforgeeks.org/merge-two-sorted-linked-lists/,请参阅方法3),
我想知道这个实现的最大复杂性是什么:
例如:如果已添加4,则继续上一个示例我可以安全地从4开始下一个比较:
list1:0 1 2 3 4 5 7
list2:6 7 10
现在比较6与4而不是1 2 3 4 ....
如果我将一个元素与第一个列表中的所有元素进行比较,那么它将是O(m * n),其中m =#list2和n = #list1,但考虑到这个“优化”,复杂性是多少吗
实现:
// Insert a new node in a sorted list
int sortedInsert(struct ListNode **head, struct ListNode* newNode) {
int headUpdated = 0;
struct ListNode *current;
// The list is empty or the new element has to be added as first element
if (*head == NULL || (*head)->data >= newNode->data) {
newNode->next = *head;
*head = newNode;
headUpdated = 1;
}
else {
// Locate the node before the point of insertion
current = *head;
while (current->next != NULL && current->next->data < newNode->data)
current = current->next;
newNode->next = current->next;
current->next = newNode;
}
return headUpdated;
}
struct ListNode *mergeLists(struct ListNode *head1, struct ListNode *head2) {
if (head1 == NULL)
return head2;
if (head2 == NULL)
return head1;
// Store the node in the first list where to start the comparisons
struct ListNode *first = head1;
while (head2) {
struct ListNode *head2Next = head2->next;
printf("Adding %d starting comparison from %d\n", head2->data, first->data);
if (sortedInsert(&first, head2))
head1 = first;
first = head2;
head2 = head2Next;
}
return head1;
}
答案 0 :(得分:3)
实际上,您在此处使用的合并算法是 O(m + n)
,而不是O(m * n)
。
由于你有一个指向最后一个插入节点的指针,并开始寻找插入下一个节点的位置,所以
的总数current = current->next
sortedInsert
中的操作最多为m + n - 1
(结果长度减去1)。插入操作的数量(重新链接next
指针)是n
(第二个列表的长度)。每次比较
current->next->data < newNode->data
下一个操作是插入或current = current->next
,因此比较次数最多为
m + 2*n - 1
我们假设结果列表以第一个列表中的m_0
个元素开头,然后是第二个列表中的n_1
个元素,然后是第一个m_1
来自n_2
的元素第二个,......,n_r
来自第二个,然后最后m_r
来自第一个。 m_0
和m_r
可能为0,其他所有数字都是正数。
将n_1
块的第一个元素与m_0
块的每个元素和m_1
块的第一个元素进行比较。该块的所有其他元素将与其在第二个列表中的前一个元素进行比较,并与m_1
块的第一个元素进行比较[除非r = 1
和m_1 = 0
,在这种情况下,比较较少]
这使m_0 + 1 + (n_1 - 1)*2 = m_0 + 2*n_1 - 1
比较(或更少)。
对于后来的n_k
块,将第一个元素与n_(k-1)
块的最后一个元素,m_(k-1)
块的所有元素以及{{的第一个元素进行比较1}}阻止[如果存在]。该块的其他元素都与它们在列表2中的前一个元素进行了比较,并且m_k
块的第一个元素[如果存在],使得
m_k
比较(或更少)。由于所有比较都涉及第二个列表中的至少一个元素,因此比较总数最多为
1 + m_(k-1) + 1 + (n_k - 1)*2 = m_(k-1) + 2*n_k
我们可以通过初始化来稍微改善它
m_0 + 2*n_1 - 1 + m_1 + 2*n_2 + m_2 + 2*n_3 + ... + m_(r-1) + 2*n_r <= m + 2*n - 1.
并删除
struct ListNode *first = head1;
从循环中进行测试。