Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/hadoop/6.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_Linked List_Mergesort - Fatal编程技术网

C 链表合并排序的复杂性

C 链表合并排序的复杂性,c,linked-list,mergesort,C,Linked List,Mergesort,我有使用链表的mergesort的代码,它工作得很好,我的问题是这个算法的复杂性是什么?它是O(nlog(n))?它是否稳定?我很感兴趣,因为我知道mergesort是稳定的,那么使用链表呢?如果我们有一些元素彼此相等,这个代码会保留元素的顺序吗?非常感谢 #include<stdio.h> #include <stdlib.h> struct node { int number; struct node *next; }; struct node *a

我有使用链表的mergesort的代码,它工作得很好,我的问题是这个算法的复杂性是什么?它是O(nlog(n))?它是否稳定?我很感兴趣,因为我知道mergesort是稳定的,那么使用链表呢?如果我们有一些元素彼此相等,这个代码会保留元素的顺序吗?非常感谢

#include<stdio.h>
#include <stdlib.h>
struct node
{
    int number;
    struct node *next;

};
struct node *addnode(int number,struct node *next);
struct node*mergesort(struct node *head);
struct node *merge(struct node *one,struct node *two);

int main(void){
    struct node *head;
    struct node *current;
    struct node *next;
    int test[]={8,3,1,4,2,5,7,0,11,14,6};
    int n=sizeof(test)/sizeof(test[0]);
    int i;
    head=NULL;
     for (i=0;i<n;i++)
         head=addnode(test[i],head);
     i=0;
     head=mergesort(head);
    printf("before----after sort \n");
    for (current=head;current!=NULL;current=current->next)
        printf("%4d\t%4d\n",test[i++],current->number);

    /* free list */
    for (current=head;current!=NULL;current=current->next)
        next=current->next;free(current);
return 0;
}

struct node *addnode(int number,struct node* next){
    struct node *tnode;
    tnode=(struct node*)malloc(sizeof(*tnode));
    if(tnode!=NULL){
        tnode->number=number;
        tnode->next=next;
            }

     return tnode;
     }
struct node *mergesort(struct node *head){

    struct node *head_one;
    struct node *head_two;
    if((head==NULL) ||(head->next==NULL))
         return head;
    head_one=head;
    head_two=head->next;
    while( (head_two!=NULL) &&(head_two->next!=NULL)){
        head=head->next;
        head_two=head->next->next;
        }
    head_two=head->next;
    head->next=NULL;
    return merge(mergesort(head_one),mergesort(head_two));
    }
struct node *merge(struct node*head_one,struct node*head_two){

    struct node *head_three;
    if(head_one==NULL)
         return head_two;
    if(head_two==NULL)
         return head_one;
    if(head_one->number<head_two->number){

head_three=head_one;
head_three->next=merge(head_one->next,head_two);
    }
    else
    {

        head_three=head_two;
        head_three->next=merge(head_one,head_two->next);


    }

    return head_three;
    }
#包括
#包括
结构节点
{
整数;
结构节点*下一步;
};
结构节点*addnode(整数,结构节点*next);
结构节点*合并排序(结构节点*头);
结构节点*合并(结构节点*一,结构节点*二);
内部主(空){
结构节点*头部;
结构节点*当前;
结构节点*下一步;
int测试[]={8,3,1,4,2,5,7,0,11,14,6};
int n=sizeof(test)/sizeof(test[0]);
int i;
head=NULL;
对于(i=0;不精确)
printf(“%4d\t%4d\n”,测试[i++],当前->编号);
/*免费名单*/
对于(当前=头部;当前!=NULL;当前=当前->下一步)
下一个=当前->下一个;自由(当前);
返回0;
}
结构节点*添加节点(整数,结构节点*下一个){
结构节点*tnode;
tnode=(结构节点*)malloc(sizeof(*tnode));
if(tnode!=NULL){
tnode->number=编号;
tnode->next=next;
}
返回tnode;
}
结构节点*合并排序(结构节点*头){
结构节点*首节点;
结构节点*头2;
如果((head==NULL)| |(head->next==NULL))
回流头;
头1=头;
head_two=head->next;
while((head\u two!=NULL)和&(head\u two->next!=NULL)){
头部=头部->下一步;
头二=头->下一步->下一步;
}
head_two=head->next;
head->next=NULL;
返回merge(mergesort(head_-one)、mergesort(head_-two));
}
结构节点*合并(结构节点*头一,结构节点*头二){
结构节点*head_三;
if(head_one==NULL)
返回头2;
if(head_two==NULL)
返回头1;
如果(标题->数字编号){
头三=头一;
头三->下一个=合并(头一->下一个,头二);
}
其他的
{
头三=头二;
头三->下一步=合并(头一、头二->下一步);
}
返回头三;
}
如何不对链表实施合并排序

  • 不要递归地将列表一分为二-随机访问不是免费的
  • 不要分成大小为
    1
    n-1
    的子列表,如下所示
如何实现链表的合并排序

不要使用二分法,而是通过维护已排序子列表的堆栈来构建列表。也就是说,首先将大小为
1
的列表推到堆栈中,然后向下合并,直到到达更大的列表;如果你能算出背后的数学,你实际上不需要存储列表大小


当合并函数为时,排序算法将是稳定的。一个稳定的版本将从头开始构建合并列表,方法是始终从列表中获取单个元素,如果相等,则使用第一个列表。一个不稳定但性能更好的版本将以块的形式添加到合并列表中,避免在每个元素之后进行不必要的重新链接。

您的代码中有一个输入错误。修正后,它确实是稳定的,并且具有
O(n logn)
复杂性。尽管可以肯定,您确实应该将
合并
重新实现为循环,而不是递归。C没有尾部调用优化(对吧?),所以这会把事情搞砸:

struct node *mergesort(struct node *head){

    struct node *head_one;
    struct node *head_two;
    if((head==NULL) ||(head->next==NULL))
         return head;
    head_one=head;
    head_two=head->next;
    while( (head_two!=NULL) &&(head_two->next!=NULL)){
        head=head->next;
        // head_two=head->next->next;      // -- the typo, corrected:
        head_two=head_two->next->next;
        }
    head_two=head->next;
    head->next=NULL;
    return merge(mergesort(head_one),mergesort(head_two));
    }
当我们进行此操作时,请将您的工作流程从

    return merge(mergesort(head_one),mergesort(head_two));

这样在堆栈上会容易得多(使用更少)

一般来说,这就是所谓的自上而下的合并排序。您也可以采用自下而上的方式,首先对两个元素的连续块进行排序,然后将它们合并为(因此,现在已排序)4个元素的块,然后将这些成对的元素合并为8个元素的块,等等,直到只剩下一个块-排序列表


为了获得额外的想象力(和效率),不要从两个块开始,而是从将列表分割成单调的序列开始,即递增序列和递减序列-在进行时反向重新链接后一个序列-从而根据其固有顺序分割原始列表,因此,有可能会有更少的初始块合并;然后像以前一样重复地合并这些成对的数据,直到最后只剩下一个。

合并排序意味着拆分和合并。下面片段中的拆分不是完美的(它会导致均匀分布的运行长度上的二次行为,请参见Christoph的注释)),但它可以做到这一点:

#include <stdio.h>
#include <string.h>

struct llist {
        struct llist *next;
        char *payload;
        };

int llist_cmp(struct llist *l, struct llist *r);
struct llist * llist_split(struct llist **hnd
                        , int (*cmp)(struct llist *l, struct llist *r) );
struct llist * llist_merge(struct llist *one, struct llist *two
                        , int (*cmp)(struct llist *l, struct llist *r) );
struct llist * llist_sort(struct llist *ptr
                        , int (*cmp)(struct llist *l, struct llist *r) );

struct llist * llist_split(struct llist **hnd, int (*cmp)(struct llist *l, struct llist *r) )
{
struct llist *this, *save, **tail;

for (save=NULL, tail = &save; this = *hnd; ) {
        if (! this->next) break;
        if ( cmp( this, this->next) <= 0) { hnd = &this->next; continue; }
        *tail = this->next;
        this->next = this->next->next;
        tail = &(*tail)->next;
        *tail = NULL;
        }
return save;
}

struct llist * llist_merge(struct llist *one, struct llist *two, int (*cmp)(struct llist *l, struct llist *r) )
{
struct llist *result, **tail;

for (result=NULL, tail = &result; one && two; tail = &(*tail)->next ) {
        if (cmp(one,two) <=0) { *tail = one; one=one->next; }
        else { *tail = two; two=two->next; }
        }
*tail = one ? one: two;
return result;
}
struct llist * llist_sort(struct llist *ptr, int (*cmp)(struct llist *l, struct llist *r) )
{
struct llist *save;

save=llist_split(&ptr, cmp);
if (!save) return ptr;

save = llist_sort(save, cmp);

return llist_merge(ptr, save, cmp);
}

int llist_cmp(struct llist *l, struct llist *r)

{
if (!l) return 1;
if (!r) return -1;
return strcmp(l->payload,r->payload);
}


struct llist lists[] =
{{ lists+1, "one" }
,{ lists+2, "two" }
,{ lists+3, "three" }
,{ lists+4, "four" }
,{ lists+5, "five" }
,{ lists+6, "six" }
,{ lists+7, "seven" }
,{ lists+8, "eight" }
,{ lists+9, "nine" }
,{ NULL, "ten" }
        };

int main()
{
struct llist *root,*tmp;

root = lists;

fprintf(stdout, "## %s\n", "initial:" );
for (tmp=root; tmp; tmp=tmp->next) {
        fprintf(stdout, "%s\n", tmp->payload);
        }

fprintf(stdout, "## %s\n", "sorting..." );
root = llist_sort(root, llist_cmp);
for (tmp=root; tmp; tmp=tmp->next) {
        fprintf(stdout, "%s\n", tmp->payload);
        }
fprintf(stdout, "## %s\n", "done." );

return 0;
}
#包括
#包括
结构主义者{
struct-llist*next;
字符*有效载荷;
};
int-llist_-cmp(struct-llist*l,struct-llist*r);
结构llist*llist\u拆分(结构llist**hnd
,int(*cmp)(结构llist*l,结构llist*r));
struct-llist*llist\u合并(struct-llist*1,struct-llist*2
,int(*cmp)(结构llist*l,结构llist*r));
struct-llist*llist_排序(struct-llist*ptr
,int(*cmp)(结构llist*l,结构llist*r));
结构llist*llist_拆分(结构llist**hnd,int(*cmp)(结构llist*l,结构llist*r))
{
struct-llist*this,*save,**tail;
for(save=NULL,tail=&save;this=*hnd;){
如果(!this->next)中断;
if(cmp(this,this->next)next;continue;}
*tail=这个->下一个;
本->下一步=本->下一步->下一步;
尾部=&(*尾部)->下一步;
*tail=NULL;
}
返回保存;
}
struct-llist*llist_-merge(struct-llist*one,struct-llist*two,int(*cmp)(struct-llist*l,struct-llist*r))
{
结构llist*结果,**尾部;
for(result=NULL,tail=&result;one&&two;tail=&(*tail)->next){
if(cmp(一,二)next;}
否则{*tail=two;two=two->next;}
}
*尾巴=一?一:二;
返回结果;
}
struct-llist*llist_排序(struct-llist*ptr,int(*cmp)(struct-llist*l,
#include <stdio.h>
#include <string.h>

struct llist {
        struct llist *next;
        char *payload;
        };

int llist_cmp(struct llist *l, struct llist *r);
struct llist * llist_split(struct llist **hnd
                        , int (*cmp)(struct llist *l, struct llist *r) );
struct llist * llist_merge(struct llist *one, struct llist *two
                        , int (*cmp)(struct llist *l, struct llist *r) );
struct llist * llist_sort(struct llist *ptr
                        , int (*cmp)(struct llist *l, struct llist *r) );

struct llist * llist_split(struct llist **hnd, int (*cmp)(struct llist *l, struct llist *r) )
{
struct llist *this, *save, **tail;

for (save=NULL, tail = &save; this = *hnd; ) {
        if (! this->next) break;
        if ( cmp( this, this->next) <= 0) { hnd = &this->next; continue; }
        *tail = this->next;
        this->next = this->next->next;
        tail = &(*tail)->next;
        *tail = NULL;
        }
return save;
}

struct llist * llist_merge(struct llist *one, struct llist *two, int (*cmp)(struct llist *l, struct llist *r) )
{
struct llist *result, **tail;

for (result=NULL, tail = &result; one && two; tail = &(*tail)->next ) {
        if (cmp(one,two) <=0) { *tail = one; one=one->next; }
        else { *tail = two; two=two->next; }
        }
*tail = one ? one: two;
return result;
}
struct llist * llist_sort(struct llist *ptr, int (*cmp)(struct llist *l, struct llist *r) )
{
struct llist *save;

save=llist_split(&ptr, cmp);
if (!save) return ptr;

save = llist_sort(save, cmp);

return llist_merge(ptr, save, cmp);
}

int llist_cmp(struct llist *l, struct llist *r)

{
if (!l) return 1;
if (!r) return -1;
return strcmp(l->payload,r->payload);
}


struct llist lists[] =
{{ lists+1, "one" }
,{ lists+2, "two" }
,{ lists+3, "three" }
,{ lists+4, "four" }
,{ lists+5, "five" }
,{ lists+6, "six" }
,{ lists+7, "seven" }
,{ lists+8, "eight" }
,{ lists+9, "nine" }
,{ NULL, "ten" }
        };

int main()
{
struct llist *root,*tmp;

root = lists;

fprintf(stdout, "## %s\n", "initial:" );
for (tmp=root; tmp; tmp=tmp->next) {
        fprintf(stdout, "%s\n", tmp->payload);
        }

fprintf(stdout, "## %s\n", "sorting..." );
root = llist_sort(root, llist_cmp);
for (tmp=root; tmp; tmp=tmp->next) {
        fprintf(stdout, "%s\n", tmp->payload);
        }
fprintf(stdout, "## %s\n", "done." );

return 0;
}