合并2个排序列表

时间:2010-11-29 13:38:11

标签: lisp

我被要求尽可能多地解决以下问题:

  

编写一个带有两个数字列表的函数(假设为   按升序排列)并将它们合并为一个列表(同样在   升序)。

我的第一个解决方案是append list1list2然后重新sort

然后我找到了内置的merge

然后我决定自己实际实现一个解决方案,并且我想出了一个尾递归函数,目前只适用于列表的子集。

问题本身似乎也许我终于有理由阅读Knuth了,但是由于下雪,Uni和图书馆已经关闭了。

所以我转向你,对这个问题有什么有趣的,有效的或反模式的方法?


P.S我不是在寻找实现,除非这是展示这个想法的最佳方式。我只是想看看人们是如何处理这类问题的。

6 个答案:

答案 0 :(得分:6)

合并两个已排序的列表在算法上是微不足道的。

从每个列表的第一个元素开始,比较,写下较低的一个输出,然后前进找到下一个列表的列表。继续,直到你到达一个列表的末尾,然后把剩下的另一个列表。

这要求每个列表只有一个循环,最大值。每个输出元素一个比较。

编辑:这与两个列表一样高效。当你有大量要合并的列表时,它会变得更加棘手。

答案 1 :(得分:6)

您可以编写一个函数is-sorted-p来确定列表是否仍然按升序排列。然后连接两个列表,并随机调整结果,直到它通过你的谓词。

......你没有谈论任何表现。

答案 2 :(得分:2)

如果你有两个,那就相对容易了。

  1. 这两个清单都是空的吗?如果是,则结果为空列表
  2. 一个列表是空的而另一个不是吗?结果是非空列表。
  3. 找到最小的列表头(“car”),结果就是那个列表头,与该列表的尾部和另一个列表的自调用结果相对应。
  4. 这可以转换为尾递归过程,使用一些辅助参数(可能还有一个自定义的“反向和缺点”辅助函数)。

答案 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)并转换回列表。