Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/58.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 链表上自底向上的合并排序_C_Algorithm_Sorting_Merge - Fatal编程技术网

C 链表上自底向上的合并排序

C 链表上自底向上的合并排序,c,algorithm,sorting,merge,C,Algorithm,Sorting,Merge,自底向上的合并排序处理大小为1的每个元素的列表,并反复地前后合并子列表,直到它们按顺序排序。这使得使用自下而上的合并排序对链表进行排序非常有吸引力,因为它们已经“分离” 我试图用C语言实现自底向上的合并排序,并意识到有多种方法可以实现自底向上的合并排序;特别是,我正在使用这种方法: 将单个列表插入队列 将前两个列表出列并合并它们 将合并的列表排队(合并的项目转到末尾) 重复步骤1-3,直到它们按顺序排列 然而,我正在努力实现以下目标: 合并链接列表而不使用额外的O(n)空间(如果可能) 因此

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

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

  • 将单个列表插入队列
  • 将前两个列表出列并合并它们
  • 将合并的列表排队(合并的项目转到末尾)
  • 重复步骤1-3,直到它们按顺序排列
  • 然而,我正在努力实现以下目标:

    • 合并链接列表而不使用额外的O(n)空间(如果可能)
    因此,我的问题是:

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

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

  • 有一个聪明的方法,它使用一个固定大小的数组(通常是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;
        }
    
    //将数组[]初始化为所有空值
    while(plist!=NULL){
    pmerge=plist;
    plist=plist->next;
    pmerge->next=NULL;
    对于(i=0;i<数组大小;i++){
    if(数组[i]==NULL)
    打破
    pmerge=mergelists(数组[i],pmerge);
    数组[i]=NULL;
    }
    如果(i==数组大小)i--;
    数组[i]=pmerge;
    }
    
    列表的大小随着i的增加而加倍,数组[i]要么为NULL,要么指向一个包含2个幂i节点的列表


    然后数组被合并到一个列表中,同样只需一个循环和对mergelists()的调用。看看你是否能理解这一部分。

    我对(4)的工作原理很感兴趣。当您不知道列表A的长度时,如何在第二关中找到列表B?@sp2danny:通过将
    item->data
    item->next->data
    进行比较,与合并中使用的函数相同。谢谢您的回答@CiaPan,我只是想知道你的描述是否是自然合并排序的修改版本?如果我错了,请更正。@sp2danny(编辑失败后重复),方法是将
    item->data
    item->next->data
    与合并中使用的相同函数进行比较。只需扫描列表,比较每两个连续项,找到第一个子列表的结尾,然后取消链接(拆分列表)。然后重复此操作以获取第二个子列表。合并商店。重复此操作以取消第三和第四个子列表的链接。合并,存储。依此类推,直到输入耗尽。重复,直到只有一个子列表。@Arial是的,它是。见维基百科。