【问题标题】:why linked list are not sorted?为什么链表没有排序?
【发布时间】:2021-01-14 23:19:31
【问题描述】:

我尝试为字符串创建链表并根据他们的分数进行排序,但我的排序算法什么也没做。感谢您的任何建议和帮助。

void SortList(Linked_List *list) {
    Node *temp, *index = NULL;
    temp = list->head;
    int tmp;
    if (list->head == NULL) {
        return;
    } else {
        while (temp != NULL) {
            index = temp->next;
            while (index != NULL) {
                if (temp->score > index->score) {
                    tmp = temp->score;
                    temp->score = index->score;
                    index->score = tmp;
                }
                index = index->next;
            }
            temp = temp->next;
        }
    }
}

这是我的结构定义:

typedef struct Node {
    void *data;
    int score;
    struct Node *next;
} Node;

typedef struct {
    Node *head;
} Linked_List;

这是我的主要方法(我删除了前两个案例,因为它们与我的问题无关):

int main()
{
FILE *fp,*fp2,*fp3;
int bufferLength = 99;
char line[RSIZ][LSIZ];
char str[RSIZ][LSIZ];
int k,point=0;
Linked_List* char_list = create_empty_list();
char buffer[bufferLength];
char password[99];
int counter=0,len1=0,len2=0,choice,i=0,tot=0,j;
bool quit = false;

这里是swtich case方法:

while(!quit){
printf("\t\t\t3.LinkedList:\n");
printf("\t\t\tAny other to exit():\n");
scanf("%d",&choice);
    switch(choice){          
        case 3:
    fp3 = fopen("10-million-password-list-top/1000.txt","r");
    if(fp3==NULL){
        printf("Could not open the file\n");
    }
    while(fgets(str[k],LSIZ,fp3)){
        str[k][strlen(str[k])-1]= '\0';
        Linked_List* char_list = create_empty_list();
        char_list->head = insert_end(char_list, str[k]);

计算密码强度它比我删除的这个长它是这个问题的不必要细节。

        int j;
        for(j=0;str[k][j]!=0;j++){
        if(str[k][j]>=97 && str[k][j]<=122){ //lowercase
            point+=3;
        }
        else if(str[k][j]>=48 && str[k][j]<=57){ //digits
            point+=10;
        }}
        Scoring(char_list,point);
        point=0;
        k++;
    SortList(char_list);
    display(char_list);
    printf("\n");
    }break;
    default:
        quit=true;
        break;
}}
free_list(char_list);
fclose(fp2);    
return 0;
}

【问题讨论】:

  • 一个可疑点 - score 被交换,但不是 data。通常排序最好通过操作链表指针而不是数据/键值来完成。
  • 是什么让你认为它是“无所事事”?你似乎没有打电话给SortList这一事实与它有什么关系吗?
  • 当我显示链表时它仍然像排序前一样。

标签: c linked-list


【解决方案1】:

您正在交换节点中的 数据,而不是链接指针。

虽然您可以这样做,但通常只有链接指针会被交换。假设你的struct 有(另外),比如:int array[1000000]; 作为一个元素。您必须交换 那个,与仅更改指针相比,这将 非常 慢。

而且,您只需 一个 传递数据。因此,您可能会在列表的前面获得最低值,但所有其他值将保持未排序。

也就是说,对于具有 N 个元素和简单排序(具有 O(N^2) 复杂度)的列表,您需要 N 次遍历。

我不得不稍微重构一下你的代码。

我想出的算法是有一个临时的“目的地”列表[最初是空的]。

对于每次遍历,都会扫描原始列表中的最小/最低元素。

该元素从源列表中删除并附加到目标列表中。

最后将临时列表的头部地址复制到原始列表的head元素中。


无论如何,这是代码。我试图尽可能多地注释它。它编译干净,我已经检查过它的正确性。但是,我没有测试它,所以它可能有一些错误。但是,它应该可以帮助您入门。

#include <stdio.h>

typedef struct Node {
    void *data;
    int score;
    struct Node *next;
} Node;

typedef struct {
    Node *head;
} Linked_List;

void
SortList(Linked_List *srclist)
{
    Node *dsthead = NULL;
    Node *dstprev = NULL;

    // do N passes on the list
    while (1) {
        // get next element in source list -- stop when empty
        Node *srcbest = srclist->head;
        if (srcbest == NULL)
            break;

        // find smallest node in remaining list
        Node *bestprev = NULL;
        Node *curprev = NULL;
        for (Node *cursrc = srcbest;  cursrc != NULL;  cursrc = cursrc->next) {
            if (cursrc->score < srcbest->score) {
                srcbest = cursrc;
                bestprev = curprev;
            }
            curprev = cursrc;
        }

        // add selected node to tail of destination list
        if (dsthead == NULL)
            dsthead = srcbest;
        else
            dstprev->next = srcbest;
        dstprev = srcbest;

        // remove selected node from source list
        if (bestprev != NULL)
            bestprev->next = srcbest->next;
        else
            srclist->head = srcbest->next;

        // fix the tail of destination list
        dstprev->next = NULL;
    }

    // set new head of original list
    srclist->head = dsthead;
}

更新:

我也试过这个,但仍然没有排序给我相同的链表。

自从我的原始帖子以来,我创建了一个测试程序。该算法有效[如发布]。所以,你的代码中一定有其他东西。

该算法类似于插入排序。我添加了冒泡排序变体。

这是完整的工作代码:

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

typedef struct Node {
    void *data;
    int score;
    struct Node *next;
} Node;

typedef struct {
    Node *head;
    Node *tail;
    int count;
} Linked_List;

#define DOTEST(_fnc,_count) \
    dotest(_fnc,#_fnc,_count)

#ifdef DEBUG
#define dbgprt(_fmt...) \
    printf(_fmt)
#else
#define dbgprt(_fmt...) \
    do { } while (0)
#endif

enum {
    OPT_SWAPFLG = 1u << 0,
    OPT_SHORTEN = 1u << 1,
};

double tsczero;

double
tscgetf(void)
{
    struct timespec ts;
    double sec;

    clock_gettime(CLOCK_MONOTONIC,&ts);

    sec = ts.tv_nsec;
    sec /= 1e9;
    sec += ts.tv_sec;

    sec -= tsczero;

    return sec;
}

int
show(Node *cur)
{
    int score;

    if (cur != NULL)
        score = cur->score;
    else
        score = -1;

    return score;
}

// SortList -- insertion sort
void
SortList(Linked_List *srclist)
{
    Node *dsthead = NULL;
    Node *dstprev = NULL;

    // do N passes on the list
    while (1) {
        // get next element in source list -- stop when empty
        Node *srcbest = srclist->head;
        if (srcbest == NULL)
            break;

        // find smallest node in remaining list
        Node *bestprev = NULL;
        Node *curprev = NULL;
        for (Node *cursrc = srcbest;  cursrc != NULL;  cursrc = cursrc->next) {
            if (cursrc->score < srcbest->score) {
                srcbest = cursrc;
                bestprev = curprev;
            }
            curprev = cursrc;
        }

        // add selected node to tail of destination list
        if (dsthead == NULL)
            dsthead = srcbest;
        else
            dstprev->next = srcbest;
        dstprev = srcbest;

        // remove selected node from source list
        if (bestprev != NULL)
            bestprev->next = srcbest->next;
        else
            srclist->head = srcbest->next;

        // fix the tail of destination list
        dstprev->next = NULL;
    }

    // set new head of original list
    srclist->head = dsthead;
}

// SwapCom -- bubble sort
void
SwapCom(Linked_List *list,unsigned int opt)
{
    Node *dsthead = NULL;
    Node *dstprev = NULL;
    Node *tail = NULL;
    int swapflg = 1;

    // do N passes on the list -- stop early if list becomes sorted
    while (swapflg) {
        if (opt & OPT_SWAPFLG)
            swapflg = 0;

        Node *prev = list->head;
        if (prev == NULL)
            break;

        dbgprt("SwapList: START\n");

        Node *next;
        Node *pprev = NULL;
        for (Node *cur = prev->next;  cur != NULL;  cur = next) {
            next = cur->next;

            dbgprt("SwapCom: CUR head=%d pprev=%d prev=%d cur=%d next=%d\n",
                show(list->head),show(pprev),show(prev),show(cur),show(next));

            // last element is always in sort
            if (cur == tail) {
                dbgprt("SwapCom: SHORT\n");
                break;
            }

            // the two elements are already in order
            if (prev->score <= cur->score) {
                pprev = prev;
                prev = cur;
                continue;
            }

            // say we had to swap -- we require another pass
            dbgprt("SwapCom: SWAP\n");
            swapflg = 1;

            // adjust the head of the list
            if (prev == list->head)
                list->head = cur;

            // swap the link pointers
            cur->next = prev;
            prev->next = next;

            // adjust previous
            if (pprev != NULL)
                pprev->next = cur;

            //next = prev;

            pprev = cur;
            //prev = cur;
        }

        if (opt & OPT_SHORTEN)
            tail = prev;
    }
}

// SwapEarly -- bubble sort
void
SwapEarly(Linked_List *list)
{

    SwapCom(list,OPT_SWAPFLG);
}

// SwapShort -- bubble sort
void
SwapShort(Linked_List *list)
{

    SwapCom(list,OPT_SWAPFLG | OPT_SHORTEN);
}

void
split(Linked_List *list,Linked_List *listl,Linked_List *listr)
{
    int c2 = list->count / 2;
    int idx = 1;
    Node *rhs;

    // find the midpoint
    for (rhs = list->head;  rhs != NULL;  rhs = rhs->next, ++idx) {
        if (idx >= c2)
            break;
    }

    listl->head = list->head;
    listl->count = c2;

    listr->count = list->count - c2;
    listr->head = rhs->next;

    rhs->next = NULL;
}

void
merge(Linked_List *list,Linked_List *listl,Linked_List *listr)
{
    Node *lhs = listl->head;
    Node *rhs = listr->head;
    Node *prev;
    Node *cur;

    list->head = NULL;
    list->count = 0;
    prev = NULL;

    while ((lhs != NULL) && (rhs != NULL)) {
        if (lhs->score <= rhs->score) {
            cur = lhs;
            lhs = lhs->next;
            listl->count -= 1;
        }
        else {
            cur = rhs;
            rhs = rhs->next;
            listr->count -= 1;
        }

        if (prev != NULL)
            prev->next = cur;
        else
            list->head = cur;

        list->count += 1;
        prev = cur;
        prev->next = NULL;
    }

    if (lhs != NULL) {
        list->count += listl->count;
        prev->next = lhs;
    }

    if (rhs != NULL) {
        list->count += listr->count;
        prev->next = rhs;
    }
}

void
mergesort(Linked_List *list)
{
    Linked_List listl;
    Linked_List listr;

    if (list->count >= 2) {
        split(list,&listl,&listr);
        mergesort(&listl);
        mergesort(&listr);
        merge(list,&listl,&listr);
    }
}

// MergeSort -- merge sort
void
MergeSort(Linked_List *list)
{

    mergesort(list);
}

Linked_List *
newlist(int count)
{
    Linked_List *list = calloc(1,sizeof(*list));

    Node *prev = NULL;
    for (int idx = 1;  idx <= count;  ++idx) {
        Node *cur = calloc(1,sizeof(*cur));

        cur->score = count - idx;

        if (prev != NULL)
            prev->next = cur;
        else
            list->head = cur;

        list->tail = cur;
        list->count += 1;

        prev = cur;
    }

    return list;
}

void
freelist(Linked_List *list)
{

    Node *next;
    for (Node *cur = list->head;  cur != NULL;  cur = next) {
        next = cur->next;
        free(cur);
    }

    free(list);
}

int
chklist(Linked_List *list)
{
    Node *prev = list->head;
    Node *cur;
    int idx = 0;
    int err = 0;

    if (prev != NULL)
        cur = prev->next;
    else
        cur = NULL;

    for (;  cur != NULL;  cur = cur->next, ++idx) {
        if (prev->score > cur->score) {
            printf("chklist: ERROR index %d -- prev=%d cur=%d\n",idx,prev,cur);
            if (++err > 10)
                break;
        }
        prev = cur;
    }

    if (err)
        exit(1);

    // get the count
    idx += 1;

    return idx;
}

void
prtlist(Linked_List *list,const char *reason)
{
    int totlen = 0;

    totlen += printf("%s:",reason);

    for (Node *cur = list->head;  cur != NULL;  cur = cur->next) {
        totlen += printf(" %d",cur->score);
        if (totlen >= 70) {
            printf("\n");
            totlen = 0;
        }
    }

    if (totlen > 0)
        printf("\n");
}

void
dotest(void (*sort)(Linked_List *),const char *reason,int count)
{
    Linked_List *list;
    int prtflg = (count <= 100);

    printf("\n");
    printf("Testing %s for %d elements ...\n",reason,count);

    list = newlist(count);
    if (prtflg)
        prtlist(list,"Unsorted");

    double tscbeg = tscgetf();
    sort(list);
    double tscend = tscgetf();
    tscend -= tscbeg;

    if (prtflg)
        prtlist(list,"Sorted");

    int chk = chklist(list);
    if (chk != count) {
        printf("dotest: check count mismatch -- expected: %d actual: %d\n",
            count,chk);
        exit(1);
    }

    freelist(list);

    double rate;
#if 0
    rate = count;
    rate /= tscend;
#else
    rate = tscend;
    rate /= count;
#endif

    printf("ELAPSED: %.9f RATE: %.9f\n",tscend,rate);

    fflush(stdout);
}

int
main(void)
{
    int counts[] = { 10, 100, 1000, 10000, 100000, -1 };

    tsczero = tscgetf();

    for (int idx = 0;  ; ++idx) {
        int count = counts[idx];
        if (count < 0)
            break;

        printf("\n");
        for (int idx = 0;  idx <= 70;  ++idx)
            printf("-");
        printf("\n");

        DOTEST(SortList,count);
        DOTEST(SwapEarly,count);
        DOTEST(SwapShort,count);
        DOTEST(MergeSort,count);
    }

    return 0;
}

这是程序输出:

-----------------------------------------------------------------------

Testing SortList for 10 elements ...
Unsorted: 9 8 7 6 5 4 3 2 1 0
Sorted: 0 1 2 3 4 5 6 7 8 9
ELAPSED: 0.000000696 RATE: 0.000000070

Testing SwapEarly for 10 elements ...
Unsorted: 9 8 7 6 5 4 3 2 1 0
Sorted: 0 1 2 3 4 5 6 7 8 9
ELAPSED: 0.000001120 RATE: 0.000000112

Testing SwapShort for 10 elements ...
Unsorted: 9 8 7 6 5 4 3 2 1 0
Sorted: 0 1 2 3 4 5 6 7 8 9
ELAPSED: 0.000000696 RATE: 0.000000070

Testing MergeSort for 10 elements ...
Unsorted: 9 8 7 6 5 4 3 2 1 0
Sorted: 0 1 2 3 4 5 6 7 8 9
ELAPSED: 0.000000835 RATE: 0.000000083

-----------------------------------------------------------------------

Testing SortList for 100 elements ...
Unsorted: 99 98 97 96 95 94 93 92 91 90 89 88 87 86 85 84 83 82 81 80 79
 78 77 76 75 74 73 72 71 70 69 68 67 66 65 64 63 62 61 60 59 58 57 56 55
 54 53 52 51 50 49 48 47 46 45 44 43 42 41 40 39 38 37 36 35 34 33 32 31
 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6
 5 4 3 2 1 0
Sorted: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72
 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96
 97 98 99
ELAPSED: 0.000031237 RATE: 0.000000312

Testing SwapEarly for 100 elements ...
Unsorted: 99 98 97 96 95 94 93 92 91 90 89 88 87 86 85 84 83 82 81 80 79
 78 77 76 75 74 73 72 71 70 69 68 67 66 65 64 63 62 61 60 59 58 57 56 55
 54 53 52 51 50 49 48 47 46 45 44 43 42 41 40 39 38 37 36 35 34 33 32 31
 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6
 5 4 3 2 1 0
Sorted: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72
 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96
 97 98 99
ELAPSED: 0.000083257 RATE: 0.000000833

Testing SwapShort for 100 elements ...
Unsorted: 99 98 97 96 95 94 93 92 91 90 89 88 87 86 85 84 83 82 81 80 79
 78 77 76 75 74 73 72 71 70 69 68 67 66 65 64 63 62 61 60 59 58 57 56 55
 54 53 52 51 50 49 48 47 46 45 44 43 42 41 40 39 38 37 36 35 34 33 32 31
 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6
 5 4 3 2 1 0
Sorted: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72
 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96
 97 98 99
ELAPSED: 0.000045619 RATE: 0.000000456

Testing MergeSort for 100 elements ...
Unsorted: 99 98 97 96 95 94 93 92 91 90 89 88 87 86 85 84 83 82 81 80 79
 78 77 76 75 74 73 72 71 70 69 68 67 66 65 64 63 62 61 60 59 58 57 56 55
 54 53 52 51 50 49 48 47 46 45 44 43 42 41 40 39 38 37 36 35 34 33 32 31
 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6
 5 4 3 2 1 0
Sorted: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72
 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96
 97 98 99
ELAPSED: 0.000007023 RATE: 0.000000070

-----------------------------------------------------------------------

Testing SortList for 1000 elements ...
ELAPSED: 0.003071345 RATE: 0.000003071

Testing SwapEarly for 1000 elements ...
ELAPSED: 0.008256265 RATE: 0.000008256

Testing SwapShort for 1000 elements ...
ELAPSED: 0.004658966 RATE: 0.000004659

Testing MergeSort for 1000 elements ...
ELAPSED: 0.000110933 RATE: 0.000000111

-----------------------------------------------------------------------

Testing SortList for 10000 elements ...
ELAPSED: 0.312265008 RATE: 0.000031227

Testing SwapEarly for 10000 elements ...
ELAPSED: 0.829503246 RATE: 0.000082950

Testing SwapShort for 10000 elements ...
ELAPSED: 0.450563461 RATE: 0.000045056

Testing MergeSort for 10000 elements ...
ELAPSED: 0.001036259 RATE: 0.000000104

-----------------------------------------------------------------------

Testing SortList for 100000 elements ...
ELAPSED: 31.850022147 RATE: 0.000318500

Testing SwapEarly for 100000 elements ...
ELAPSED: 84.817288841 RATE: 0.000848173

Testing SwapShort for 100000 elements ...
ELAPSED: 46.089681707 RATE: 0.000460897

Testing MergeSort for 100000 elements ...
ELAPSED: 0.012533725 RATE: 0.000000125

更新 #2:

只是为了好玩,我编辑了第二个代码块以包含一个合并排序 [并更新了程序输出块]。

我也用你最后的排序算法进行了测试,但仍然没有排序。 – 查克

对于较小的数字,我的测试程序在排序后打印出列表。您可以目视检查之前和之后。

Chuck 显然您不知道如何测试列表是否已排序。向我们展示可让您确定列表是否已排序的代码。 ——库巴没有忘记莫妮卡

我的测试程序对列表是否排序进行了 [简单] 测试,如果列表排序,则会中止。

您可以将您的排序检查代码与我的chklist 代码进行比较。

但是...

在您最近更新中发布的代码中,从文件中逐行读取的代码已损坏。我已经注释并修复了这段代码:

// and this one is my main for reading from txt file:

fp3 = fopen("10-million-password-list-top/aa.txt", "r");
if (fp3 == NULL) {
    printf("Could not open the file\n");
}

#if 0
// NOTE/BUG: why have str be an array of pointers?
while (fgets(str[k], LSIZ, fp3)) {
    str[k][strlen(str[k]) - 1] = '\0';
// NOTE/BUG: this _destroys_ the list on each iteration
    Linked_List *char_list = create_empty_list();

// NOTE/BUG: insert_end _modifies_ list->head _directly_ -- no need to return
// the head value
    char_list->head = insert_end(char_list, str[k]);
}
#else
char linebuf[1000];
Linked_List *char_list = create_empty_list();
while (fgets(linebuf,sizeof(linebuf),fp3)) {
    linebuf[strlen(linebuf) - 1] = 0;
    insert_end(char_list,linebuf);
}
#endif

insert_end 代码也被损坏了

// NOTE/BUG: list->head is updated internally -- no need to return it
#if 0
Node *
insert_end(Linked_List *list, void *data)
#else
void
insert_end(Linked_List *list, const char *data)
#endif
{
    Node *new_node;
    Node *temp;

// NOTE/BUG: don't cast the return value of malloc
#if 0
    new_node = (Node *) malloc(sizeof(Node));
#else
    new_node = malloc(sizeof(*new_node));
#endif

// NOTE/BUG: this is _not_ the way to allocate space for the string
// NOTE/BUG: the next line blows away the value just obtained from malloc
#if 0
    new_node->data = malloc(sizeof(char *));
    new_node->data = (char *) data;
#else
    new_node->data = strdup(data);
#endif

    new_node->next = NULL;
    if (list->head == NULL) {
        list->head = new_node;
    }
    else {
        temp = list->head;
        while (temp->next != NULL) {
            temp = temp->next;
        }

        temp->next = new_node;
    }

#if 0
    return (list->head);
#endif
}

【讨论】:

  • 我也试过这个,但仍然没有排序给我相同的链表。
  • 我也用你最后的排序算法进行了测试,但仍然没有排序。
  • @Chuck 显然您不知道如何测试列表是否已排序。向我们展示可让您确定列表是否已排序的代码。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-11-29
  • 1970-01-01
  • 1970-01-01
  • 2020-09-11
  • 2021-12-31
相关资源
最近更新 更多