我被要求尽可能多地解决以下问题:
编写一个带有两个数字列表的函数(假设为 按升序排列)并将它们合并为一个列表(同样在 升序)。
我的第一个解决方案是append
list1
到list2
然后重新sort
。
然后我找到了内置的merge
。
然后我决定自己实际实现一个解决方案,并且我想出了一个尾递归函数,目前只适用于列表的子集。
问题本身似乎也许我终于有理由阅读Knuth了,但是由于下雪,Uni和图书馆已经关闭了。
所以我转向你,对这个问题有什么有趣的,有效的或反模式的方法?
P.S我不是在寻找实现,除非这是展示这个想法的最佳方式。我只是想看看人们是如何处理这类问题的。
答案 0 :(得分:6)
合并两个已排序的列表在算法上是微不足道的。
从每个列表的第一个元素开始,比较,写下较低的一个输出,然后前进找到下一个列表的列表。继续,直到你到达一个列表的末尾,然后把剩下的另一个列表。
这要求每个列表只有一个循环,最大值。每个输出元素一个比较。
编辑:这与两个列表一样高效。当你有大量要合并的列表时,它会变得更加棘手。
答案 1 :(得分:6)
您可以编写一个函数is-sorted-p
来确定列表是否仍然按升序排列。然后连接两个列表,并随机调整结果,直到它通过你的谓词。
......你没有谈论任何表现。
答案 2 :(得分:2)
如果你有两个,那就相对容易了。
这可以转换为尾递归过程,使用一些辅助参数(可能还有一个自定义的“反向和缺点”辅助函数)。
答案 3 :(得分:1)
有几种方法可以解决这个问题。
由于有两个链表,因此两者都是最高级别的最简单方式 无视基本案例。
list_t*
merge(list_t *head_1P, list_t *head_2P) {
if (head_1P == NULL) {
return head_2P;
} else if (head_2P == NULL) {
return head_1P;
}
list_t *temp = NULL;
list_t *new_headP = NULL;
while(head_2P != NULL) {
// Remove one element from
// the second list.
temp = head_2P;
head_2P = head_2P->next;
temp->next = NULL;
insert_sort(&head_1P, temp);
}
}
void
insert_sort(list_t **headP, list_t *temp) {
if (*headP == NULL || (*headP)->data > temp->data) {
temp->next = *headP;
*headP = temp;
return;
}
list_t *currentP = *headP;
while(currentP->next != NULL) {
if (currentP->next->data > temp->data) {
temp->next = currentP->next;
currentP->next = temp;
return;
}
currentP = currentP->next;
}
temp->next = currentP->next; // Assigning NULL.
currentP->next = temp;
}
为了进一步优化,我们可以使insert_sort重新插入插入位置 碰巧避免每次开始时发生的插入。因为在最坏的情况下,如果第二个链表元素全部插入第一个列表的末尾,则可能需要O(m * n)时间复杂度。
答案 4 :(得分:0)
您正在寻找一个创建列表的函数的递归定义(通过合并两个列表)。
可以预期函数将通过根据某种原理提取头元素来创建列表,然后从其余元素递归地构造列表尾部。
由于您需要返回已排序的列表,因此列表头始终是列表中的最小元素。因此,您需要做的就是找到一个算法,从两个排序列表中提取最小元素(这应该相当简单,因为它们已经排序)。
答案 5 :(得分:0)
如果您的列表可以加倍balanced binary trees,则可以将list2
的所有元素插入b-tree(list1)
并转换回列表。