【问题标题】:Bottom up merge sort on Linked List链表上的自下而上合并排序
【发布时间】:2016-02-14 17:26:20
【问题描述】:

自下而上的归并排序处理每个大小为 1 的元素的列表,并迭代地来回合并子列表,直到它们按排序顺序。这使得使用自下而上的合并排序对链表进行排序非常有吸引力,因为它们已经“分离”了。

我正在尝试用 C 语言实现自下而上的归并排序,并意识到有多种方法可以实现自下而上的归并排序;特别是,我正在使用这种方法:

  1. 将单个列表插入队列
  2. 出列前两个列表并合并它们
  3. 将合并列表排入队列(合并项目到最后)
  4. 重复步骤 1-3,直到它们按顺序排列

但是,我正在努力实现以下内容:

  • 合并链表而不使用额外的 O(n) 空间(如果可能)

因此,我的问题是:

  • 如何在 C 语言中正确实现? (特别是:重复出队和入队过程直到完全排序的处理)如何知道整个队列是否按排序顺序?我正在考虑跟踪列表中的 *head 指针。
  • 在这种情况下归并排序稳定吗?为什么?
  • 自底向上归并排序的运行时间仍然是O(nlogn)。但是,这种自下而上的归并排序是否使用 O(n) 空间?假设我们实现的链表已经是一个队列。
  • 额外问题:有没有更好的替代方案来在链表上实现自下而上的归并排序?

我想这是在链表上使用自下而上合并排序的优势之一,因为它比在数组上使用自下而上合并排序更节省空间。如果我错了,请纠正我。

【问题讨论】:

    标签: c algorithm sorting merge


    【解决方案1】:

    有一个聪明的方法,它使用一个固定大小的数组(26 或 32 是常见的大小)指向节点的指针数组,一些指向节点的工作本地指针,以及一个标准的 mergelists() 函数,它合并两个已经排序的列表,并且需要处理空列表以使主代码更简单。节点被合并到数组中,然后数组被合并到一个排序列表中。这个逻辑的第一部分是:

        // initialize array[] to all NULLs
        while(plist != NULL){
            pmerge = plist;
            plist = plist->next;
            pmerge->next = NULL;
            for(i = 0; i < array size; i++){
                if(array[i] == NULL)
                    break;
                pmerge = mergelists(array[i], pmerge);
                array[i] = NULL;
            }
            if(i == array size)i--;
            array[i] = pmerge;
        }
    

    列表的大小随着 i 的增加而翻倍,array[i] 要么为 NULL,要么指向一个具有 2 次方 i 节点的列表。

    然后数组被合并到一个列表中,同样只需要一个循环和一个对mergelists()的调用。看看你能不能弄清楚这部分。

    【讨论】:

      【解决方案2】:
      1. 如何实现它?恐怕这个问题有点太笼统了。
      2. 合并排序稳定的,前提是当您在两个子列表中遇到相同的项目时,首先从“左侧”(较早的)子列表中取出它们。
      3. 使用链表可以使用 O(1) 空间;只需按顺序取消链接子列表,并在合并后将它们附加到新的临时列表中,然后在具有更长子列表的下一次迭代中使用新列表。您只需为临时列表保留额外的“头”和“尾”指针。
      4. 是的,有:取消链接最长可能增加的运行而不是 1、2、4... 项子列表。这与最坏情况下的原始算法一样好(以相反的顺序输入使一个项目在第一次迭代中运行),但是如果有一个,它会充分利用现有的偏序(对于完全排序的输入,它只需扫描列表一次)。

      【讨论】:

      • 我对 (4) 的工作方式很感兴趣。当您不知道列表 A 有多长时,如何在第 2 步中找到列表 B?
      • @sp2danny:通过将item-&gt;dataitem-&gt;next-&gt;data 与用于合并的相同功能进行比较。
      • 感谢您的回答! @CiaPan,我只是想知道您的(4)描述是否是自然合并排序的修改版本?如果我错了,请纠正我。
      • @sp2danny(编辑失败后重复)通过将item-&gt;dataitem-&gt;next-&gt;data 与用于合并的相同功能进行比较。只需扫描比较每两个连续项目的列表以找到第一个子列表的末尾,然后取消链接(拆分列表)。然后重复以获取第二个子列表。合并。店铺。重复以取消链接第三个和第四个子列表。合并,存储。以此类推,直到输入用尽。重复直到只有一个子列表。
      • @Arial 是的。参见维基百科Merge sort # Natural merge sort
      猜你喜欢
      • 2016-09-19
      • 2020-09-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-06-29
      相关资源
      最近更新 更多