Lisp 合并2个排序列表
我被要求对以下问题提出尽可能多的解决方案: 编写一个函数,该函数包含两个数字列表(均假定为 以升序排列),并将它们合并到一个列表中(也以升序排列) 升序) 我的第一个解决方案是Lisp 合并2个排序列表,lisp,Lisp,我被要求对以下问题提出尽可能多的解决方案: 编写一个函数,该函数包含两个数字列表(均假定为 以升序排列),并将它们合并到一个列表中(也以升序排列) 升序) 我的第一个解决方案是将列表1附加到列表2上,然后重新排序 然后我找到了一个内置的合并 然后我决定自己实际实现一个解决方案,我提出了一个尾部递归函数,目前它只适用于列表的子集 问题本身似乎是我终于有了阅读Knuth的理由,但唉,Uni和图书馆因为下雪而关闭了 所以我转向你们,对于这个问题,有什么有趣的、有效的或反模式的方法 另外,我不是在寻找
将列表1
附加到列表2
上,然后重新排序
然后我找到了一个内置的合并
然后我决定自己实际实现一个解决方案,我提出了一个尾部递归函数,目前它只适用于列表的子集
问题本身似乎是我终于有了阅读Knuth的理由,但唉,Uni和图书馆因为下雪而关闭了
所以我转向你们,对于这个问题,有什么有趣的、有效的或反模式的方法
另外,我不是在寻找实现,除非这是证明这个想法的最佳方式。我只是想看看人们是如何处理这类问题的。合并两个排序列表在算法上很简单
从每个列表的第一个元素开始,进行比较,将较低的元素写入输出,并将列表推进到找到较低元素的位置。继续,直到你到达一个列表的末尾,然后把另一个列表的剩余部分放出来
这只需要在每个列表上循环一次,每个输出元素最多进行一次比较
编辑:对于两个列表,这是最有效的。当您有大量列表要合并时,它会变得(有点)棘手。您正在寻找创建列表(通过合并两个列表)的函数的递归定义
可以预期,该函数将通过根据某种原则提取head元素,然后从其余元素递归构造list tail来创建一个列表
由于需要返回一个已排序的列表,因此列表头始终是列表中最小的元素。所以,您所需要做的就是找到一个算法,从两个排序的列表中提取最小的元素(这应该相当容易,因为它们已经排序) 如果列表可以加倍为,则可以将list2
的所有元素插入b-tree(list1)
并转换回列表。可以编写一个函数is-sorted-p
,确定列表是否仍按升序排列。然后将两个列表连接起来,并随机洗牌结果,直到它通过谓词
…你没有说任何关于性能的事。如果你正好有两个,那就相对容易了
两个列表都是空的吗?如果是,则结果为空列表
一个列表是空的,另一个不是?结果是非空列表
找到最小的列表头(“car”),结果就是该列表头,与该列表和另一个列表的尾部的自调用结果相关联
这可以通过使用一些辅助参数(可能还有一个自定义的“反转和反转”辅助函数)转换为尾部递归过程。有几种方法可以解决这个问题
因为有两个链表,而且它们都是以最简单的方式在高层进行排序的
忽略基本情况
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_排序重新运行插入的位置
避免每次从一开始就发生插入。因为在最坏的情况下,如果第二个链表元素全部插入到第一个链表的末尾,这可能需要O(m*n)时间复杂度。如果它们可以加倍,将大型链表转换为BBT会比合并更便宜吗?链表通常不如树加倍,但数组做得很简单。。。。再说一次,插入数组并不像插入列表那么简单。@彼得:是的,向平衡树中添加元素是一个O(logn)操作,而列表的插入(合并)是O(n),但同样地,O(n)对于一个小的n是非常好的,而且大多数时候n是小的,而列表实现为(几乎)平衡的二叉树,没有必要来回转换。列表合并变成树合并。通过将一棵树的元素逐个插入另一棵树来合并树是O(n*log(n+m))
。列表合并是O(n+m)
。因此,如果一个比另一个短得多,那么选择较短的一个可能会胜过使用简单的列表。我有点不安,因为它有一个名字。我很不安,这是这里的第二级答案。:-)嘿,OP要求“尽可能多的解决方案”,所以这绝对是一个有效的答案:-)我认为书面回答并不那么好,即使如此:也不能保证它会成功。与其随机洗牌列表,它应该尝试所有可能的顺序,顺序!