why linked list are not sorted?

回眸只為那壹抹淺笑 提交于 2021-02-10 05:32:25

问题


I try to make linked list for string and sort with their score but my sorting algorithm is doing nothing. Thank you for any advice and help.

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;
        }
    }
}

here are my structure definitions:

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

typedef struct {
    Node *head;
} Linked_List;

here is my main method(i removed first 2 cases because they are not related to my problem):

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;

and here is swtich case method:

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]);

calculating password strength it is longer than this one i removed it is unnecessary detail for this problem.

        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;
}

回答1:


You're swapping the data in the nodes, instead of the link pointers.

While you can do this, normally, only the link pointers get swapped. Suppose your struct had (in addition), something like: int array[1000000]; as an element. You'd have to swap that and that would be very slow compared to just changing pointers.

And, you only doing one pass on the data. So, you might get the lowest value at the front of the list, but all the others will remain unsorted.

That is, for a list with N elements, and simple sorts (with O(N^2) complexity), you need N passes.

I had to refactor your code a bit.

The algorithm I came up with is to have a temporary "destination" list [initially empty].

For each pass, the original list is scanned for the smallest/lowest element.

That element is removed from the source list and appended to the destination list.

At the end, the address of the head of the temp list is copied into the original list's head element.


Anyway, here is the code. I tried to annotate it as much as possible. It compiles cleanly and I've desk checked it for correctness. But, I didn't test it, so it may have some bugs. But, it should get you started.

#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;
}

UPDATE:

i tried this one also but still does not sort gives me same linked list.

Since my original post, I created a test program. The algorithm works [as posted]. So, there must be something else within your code.

The algorithm was similar to an insertion sort. I added a bubble sort variant.

Here's the full working code:

#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;
}

Here's the program output:

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

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

UPDATE #2:

Just for fun, I've edited the second code block to include a mergesort [and updated the program output block].

i tested with your last sorting algorithm too but still werent sorted. – Chuck

For smaller numbers, my test program prints out the list after sorting. You can visually inspect the before and after.

Chuck Obviously you don't know how to test whether a list is sorted. Show us the code that lets you determine whether the list is sorted or not. – Kuba hasn't forgotten Monica

My test program had a [simple] test for the list being in sort or not, and would have aborted if the list were not sorted.

You can compare your sort check code to my chklist code.

However ...

In the code you posted in your recent update, the code that reads in lines from the file is broken. I've annotated and fixed this code:

// 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

The insert_end code is also broken:

// 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
}


来源:https://stackoverflow.com/questions/65728316/why-linked-list-are-not-sorted

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!