C 使用qsort算法对链表进行排序

C 使用qsort算法对链表进行排序,c,linked-list,C,Linked List,我还在学习链表是如何工作的,我正在努力使用qsort算法和节点进行排序。 这就是我到目前为止所做的 所以我在代码中的某个地方遇到了崩溃,我不知道这个qsort算法是否以这种方式处理链表 代码更新 void swapString(char **str1, char **str2) { char *temp = *str2; *str2 = *str1; *str1 = temp; } TCD *partition(TCD *Start, TCD *End, int (*

我还在学习链表是如何工作的,我正在努力使用qsort算法和节点进行排序。 这就是我到目前为止所做的

所以我在代码中的某个地方遇到了崩溃,我不知道这个qsort算法是否以这种方式处理链表

代码更新

void swapString(char **str1, char **str2)
{
    char *temp = *str2; 
    *str2 = *str1;
    *str1 = temp;
}

TCD *partition(TCD *Start, TCD *End, int (*cmp)(const void *, const void*))
{
    TCD *partitionIdx = Start;
    TCD *i ;
   
    for (i = Start; i != End; i=i->Next)
    { 
        if (cmp(i->Titel, End->Titel) < 0)
        {
            swapString(&i->Titel, &partitionIdx->Titel);
     
            partitionIdx->Prev = partitionIdx;
            partitionIdx = partitionIdx->Next;
        }
    }

    swapString(&partitionIdx->Titel, &End->Titel);
    
    return partitionIdx; 
}

void Quicksort(TCD *Start, TCD *End, int (*cmp)(const void *, const void *))
{
    if (Start !=NULL && End != Start && End!= Start->Next)
    {
        TCD *partitionIdx = partition(Start, End, cmp);
       
        Quicksort(Start, partitionIdx->Prev, cmp);
        Quicksort(partitionIdx->Next, End, cmp);
    }
}

您的代码有几个问题:

  • partitiondx->Prev=partitiondx没有意义。它使节点指向自身。这不可能是正确的。链表的目的是让节点指向下一个节点和上一个节点,但决不指向自身

  • 函数
    分区
    正在崩溃,因为它的参数
    开始
    有时会指向链接列表中
    结束
    参数以外的位置。这是因为您调用函数
    Quicksort
    ,但没有确保其
    Start
    参数不指向
    End
    参数之外的位置

  • if
    条件
    if(Start!=NULL&&End!=Start&&End!=Start->Next)
    没有意义。子表达式
    End!=开始->下一步
    测试分区的大小是否为2。如果是这种情况,则不处理分区。但是,必须对大小为2的分区进行排序,因此必须对其进行处理。只有当大小为1时,才不应处理它

  • 我已经修改了您的算法代码,解决了上面提到的问题,现在似乎可以工作了。此外,我还添加了一些函数来测试算法。代码如下:

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <assert.h>
    
    typedef struct F
    {
        char *Titel;
        struct F *Next;
        struct F *Prev;
    } TCD;
    
    void swapString( char **str1, char **str2 )
    {
        char *temp = *str2;
        *str2 = *str1;
        *str1 = temp;
    }
    
    TCD *partition( TCD *Start, TCD *End, int( *cmp )(const void *, const void*) )
    {
        TCD *partitionIdx = Start;
        TCD *i;
    
        for ( i = Start; i != End; i = i->Next )
        {
            if ( cmp( i->Titel, End->Titel ) < 0 )
            {
                swapString( &i->Titel, &partitionIdx->Titel );
    
                //NOTE: I disabled the following line from the original code, as it was doing nonsense. It was causing a node to point to itself.
                //partitionIdx->Prev = partitionIdx;
    
                partitionIdx = partitionIdx->Next;
            }
        }
    
        swapString( &partitionIdx->Titel, &End->Titel );
    
        return partitionIdx;
    }
    
    void Quicksort( TCD *Start, TCD *End, int( *cmp )(const void *, const void *) )
    {
        //NOTE: In the following if condition, I disabled part of the original code, because a partition of two elements must be sorted
        if ( Start != NULL && End != Start /*&& End != Start->Next*/ )
        {
            TCD *partitionIdx = partition( Start, End, cmp );
    
            if ( Start != partitionIdx )
                Quicksort( Start, partitionIdx->Prev, cmp );
            if ( partitionIdx != End )
                Quicksort( partitionIdx->Next, End, cmp );
        }
    }
    
    // NOTE:
    // The following functions are not part of the algorithm, but are only
    // used to test the algorithm.
    
    void AddToList( TCD **head, TCD **tail, char *str )
    {
        TCD *p;
    
        //allocate new node and fill it with the data
        p = malloc( sizeof(*p) );
        assert( p != NULL );
        p->Titel = str;
        p->Next = NULL;
        p->Prev = *tail;
    
        //attach new node to list by updating head or next pointer
        if ( *head == NULL )
            *head = p;
        else
            (*tail)->Next = p;
    
        //update tail pointer too
        *tail = p;
    
    }
    
    void PrintList( FILE *stream, TCD *head )
    {
        TCD *p;
    
        for ( p = head; p != NULL; p = p->Next )
        {
            fprintf( stream, "%s\n", p->Titel );
        }
    
        fprintf( stream, "\n" );
    }
    
    void FreeList( TCD *head )
    {
        TCD *p = head;
    
        while ( p != NULL )
        {
            TCD *tmp = p;
    
            p = p->Next;
    
            free( tmp );
        }
    }
    
    int main( void )
    {
        TCD *head = NULL, *tail = NULL;
    
        //create linked list with a bit of unsorted test data
        AddToList( &head, &tail, "string8" );
        AddToList( &head, &tail, "string4" );
        AddToList( &head, &tail, "string2" );
        AddToList( &head, &tail, "string7" );
        AddToList( &head, &tail, "string3" );
        AddToList( &head, &tail, "string5" );
        AddToList( &head, &tail, "string1" );
        AddToList( &head, &tail, "string6" );
    
        //print list before sorting
        fprintf( stderr, "List before sort:\n" );
        PrintList( stderr, head );
    
        //do the actual sorting
        Quicksort( head, tail, strcmp );
    
        //print list after sorting
        fprintf( stderr, "List after sort:\n" );
        PrintList( stderr, head );
    
        //free the linked list
        FreeList( head );
    
        return 0;
    }
    
    #包括
    #包括
    #包括
    #包括
    类型定义结构F
    {
    煤焦效价;
    结构F*Next;
    结构F*Prev;
    }经颅多普勒;
    无效交换(字符**str1,字符**str2)
    {
    char*temp=*str2;
    *str2=*str1;
    *str1=温度;
    }
    TCD*分区(TCD*开始,TCD*结束,整数(*cmp)(常量无效*,常量无效*)
    {
    TCD*partitionIdx=开始;
    TCD*i;
    for(i=Start;i!=End;i=i->Next)
    {
    如果(cmp(i->滴度,结束->滴度)<0)
    {
    交换交换(&i->Titel,&partitionDX->Titel);
    //注意:我从原始代码中禁用了以下行,因为它没有意义。它导致一个节点指向自身。
    //partitionIdx->Prev=partitionIdx;
    partitionIdx=partitionIdx->Next;
    }
    }
    交换交换(&partitiondx->Titel,&End->Titel);
    返回分区dx;
    }
    无效快速排序(TCD*开始,TCD*结束,整数(*cmp)(常量无效*,常量无效*)
    {
    //注意:在下面的if条件中,我禁用了部分原始代码,因为必须对两个元素的分区进行排序
    如果(开始!=NULL&&End!=Start/*&&End!=Start->Next*/)
    {
    TCD*partitionDX=分区(开始、结束、cmp);
    如果(开始!=分区dx)
    快速排序(开始,分区dx->Prev,cmp);
    如果(分区dx!=结束)
    快速排序(partitionIdx->Next,End,cmp);
    }
    }
    //注:
    //以下函数不是算法的一部分,只是
    //用于测试算法。
    无效添加列表(TCD**head,TCD**tail,char*str)
    {
    经颅多普勒;
    //分配新节点并用数据填充它
    p=malloc(sizeof(*p));
    断言(p!=NULL);
    p->Titel=str;
    p->Next=NULL;
    p->Prev=*尾部;
    //通过更新头或下一个指针将新节点附加到列表
    如果(*head==NULL)
    *水头=p;
    其他的
    (*tail)->Next=p;
    //也更新尾部指针
    *尾=p;
    }
    无效打印列表(文件*流,TCD*头)
    {
    经颅多普勒;
    for(p=head;p!=NULL;p=p->Next)
    {
    fprintf(流,“%s\n”,p->Titel);
    }
    fprintf(流“\n”);
    }
    无效自由列表(TCD*头)
    {
    TCD*p=头;
    while(p!=NULL)
    {
    TCD*tmp=p;
    p=p->Next;
    免费(tmp);
    }
    }
    内部主(空)
    {
    TCD*head=NULL,*tail=NULL;
    //创建带有少量未排序测试数据的链表
    AddToList(&head,&tail,“string8”);
    附加列表(头、尾、弦4);
    AddToList(头、尾和“string2”);
    附加列表(头、尾、弦7);
    AddToList(头、尾和“string3”);
    AddToList(头、尾和“string5”);
    AddToList(头、尾和string1);
    AddToList(头、尾和“string6”);
    //排序前打印列表
    fprintf(stderr,“排序前的列表:\n”);
    打印列表(标准,标题);
    //进行实际排序
    快速排序(头、尾、strcmp);
    //排序后打印列表
    fprintf(stderr,“排序后的列表:\n”);
    打印列表(标准,标题);
    //释放链接列表
    自由名单(标题);
    返回0;
    }
    
    非常感谢@Andreas。我写的一些无意义代码的原因是,我想用qsort算法和普通数组将代码翻译成带有链表的qsort,而不用花很多心思。@Gaston:如果你想用链表进行排序,你可以尝试一下,因为该算法对于链表更有效。注释不用于扩展讨论;这段对话已经结束。
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <assert.h>
    
    typedef struct F
    {
        char *Titel;
        struct F *Next;
        struct F *Prev;
    } TCD;
    
    void swapString( char **str1, char **str2 )
    {
        char *temp = *str2;
        *str2 = *str1;
        *str1 = temp;
    }
    
    TCD *partition( TCD *Start, TCD *End, int( *cmp )(const void *, const void*) )
    {
        TCD *partitionIdx = Start;
        TCD *i;
    
        for ( i = Start; i != End; i = i->Next )
        {
            if ( cmp( i->Titel, End->Titel ) < 0 )
            {
                swapString( &i->Titel, &partitionIdx->Titel );
    
                //NOTE: I disabled the following line from the original code, as it was doing nonsense. It was causing a node to point to itself.
                //partitionIdx->Prev = partitionIdx;
    
                partitionIdx = partitionIdx->Next;
            }
        }
    
        swapString( &partitionIdx->Titel, &End->Titel );
    
        return partitionIdx;
    }
    
    void Quicksort( TCD *Start, TCD *End, int( *cmp )(const void *, const void *) )
    {
        //NOTE: In the following if condition, I disabled part of the original code, because a partition of two elements must be sorted
        if ( Start != NULL && End != Start /*&& End != Start->Next*/ )
        {
            TCD *partitionIdx = partition( Start, End, cmp );
    
            if ( Start != partitionIdx )
                Quicksort( Start, partitionIdx->Prev, cmp );
            if ( partitionIdx != End )
                Quicksort( partitionIdx->Next, End, cmp );
        }
    }
    
    // NOTE:
    // The following functions are not part of the algorithm, but are only
    // used to test the algorithm.
    
    void AddToList( TCD **head, TCD **tail, char *str )
    {
        TCD *p;
    
        //allocate new node and fill it with the data
        p = malloc( sizeof(*p) );
        assert( p != NULL );
        p->Titel = str;
        p->Next = NULL;
        p->Prev = *tail;
    
        //attach new node to list by updating head or next pointer
        if ( *head == NULL )
            *head = p;
        else
            (*tail)->Next = p;
    
        //update tail pointer too
        *tail = p;
    
    }
    
    void PrintList( FILE *stream, TCD *head )
    {
        TCD *p;
    
        for ( p = head; p != NULL; p = p->Next )
        {
            fprintf( stream, "%s\n", p->Titel );
        }
    
        fprintf( stream, "\n" );
    }
    
    void FreeList( TCD *head )
    {
        TCD *p = head;
    
        while ( p != NULL )
        {
            TCD *tmp = p;
    
            p = p->Next;
    
            free( tmp );
        }
    }
    
    int main( void )
    {
        TCD *head = NULL, *tail = NULL;
    
        //create linked list with a bit of unsorted test data
        AddToList( &head, &tail, "string8" );
        AddToList( &head, &tail, "string4" );
        AddToList( &head, &tail, "string2" );
        AddToList( &head, &tail, "string7" );
        AddToList( &head, &tail, "string3" );
        AddToList( &head, &tail, "string5" );
        AddToList( &head, &tail, "string1" );
        AddToList( &head, &tail, "string6" );
    
        //print list before sorting
        fprintf( stderr, "List before sort:\n" );
        PrintList( stderr, head );
    
        //do the actual sorting
        Quicksort( head, tail, strcmp );
    
        //print list after sorting
        fprintf( stderr, "List after sort:\n" );
        PrintList( stderr, head );
    
        //free the linked list
        FreeList( head );
    
        return 0;
    }