在链接列表上自下而上合并排序

时间:2015-11-13 07:09:49

标签: c algorithm sorting merge

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

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

  1. 将单个列表插入队列
  2. 将前两个列表出列并合并
  3. 排队合并列表(合并项目到最后)
  4. 重复步骤1-3,直到它们按顺序排列
  5. 但是,我正在努力实现以下目标:

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

    因此,我的问题是:

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

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

2 个答案:

答案 0 :(得分:2)

  1. 如何实现?有点过于宽泛的问题,我很害怕。
  2. Mergesort 稳定,前提是当您在两个子列表中遇到相同的项目时,您可以从左侧'中取出它们。 (早些时候)第一个子列表。
  3. 使用链接列表,您可以使用O(1)空格;只需按顺序取消链接子列表,并在合并后将它们附加到新的临时列表,然后在下一次迭代中使用具有较长子列表的新列表。你只需要保留额外的头部'并且'尾巴'临时列表的指针。
  4. 是的,有:取消链接最长的可能增加的运行而不是1,2,4 ...项目子列表。这与最坏情况下的原始算法一样好(以相反顺序输入使得在第一次迭代中运行一项),但是如果存在一个,则它充分利用现有的部分顺序(对于完全排序的输入它只扫描列表一次)。

答案 1 :(得分: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为power i节点。

然后将数组合并到一个列表中,同样只需要一个循环并调用mergelists()。看看你是否可以弄清楚这一部分。