简体   繁体   中英

linked list insertion sort in c

the program should do the insertion ascending sort for the nodes,first it should check the names and if the names are equal it should sort the ids,i do not know what is the issue that does not sort properly.

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

typedef struct nd{
int id;
char name[20];
float gpa;
struct nd *next;
}node;


typedef node *list;

//---------------------------------------------------------------

int insertlist(list *head,char *buffer)
{
list p,q,n;
int m,num,k,sc;
p=(list)malloc(sizeof(node));
num=sscanf(buffer,"%d %s %f",&(p->id),(p->name),(&p->gpa));
if(num!=3)
 {
  printf("info not complete\n");
  free(p);
  return 1;
 }
else
{

   if(!*head)
   {
    *head=p;
    p->next = NULL;
   }
//******** sorting tthe names and ids for equal names
   else if(sc=strcmp((*head)->name,p->name)> 0 || ((sc == 0) && ((*head)->id > p->id)))
      {//head is modified
        p->next=*head;
        *head=p;
      }

   else{
        n=*head;
        q=n->next;
        while(q && ((sc=strcmp(q->name,p->name)<0) || ((sc == 0) && (q->id < p->id))))
          {
           n=q;
           q=q->next;
          }
       n->next=p;
       p->next=q;
       }
}

return 0;
}

//------------------------------------------------------

int main()
{
int id,r;
list head,p;
FILE *fp;
char c,buffer[100],filename[10];
if ((fp=fopen("student.txt","r"))==NULL)
{
  printf("error opening %s",filename);
  exit(1);
}
else
 {
head=NULL;

while(fgets(buffer,100,fp)!=NULL)
   {
    buffer[strlen(buffer)-1]=='\0';
    r=insertlist(&head,buffer);
   }
fclose(fp);
 }

for(p=head;p!=NULL;p=p->next)
  printf("%d  %s  %f\n\n",p->id,p->name,p->gpa);
}

An example of the contents of student.txt :

121513 ala 45.00
121510 wang 21.00 
145852 frank 26.00 
151515 ala 25.00 

head is a pointer so in order to change it in a function you need to pass a pointer to it. A pointer to the pointer.

Declare like this:

int insertlist(list **head,char *buffer)

Call it like this:

r=insertlist(&(&head),buffer);

And then in the function change everywhere you reference it to de-reference the pointer.

First, fix this:

buffer[strlen(buffer)-1]=='\0';

That's an equality comparison; not an assignment. I believe you're attempting to throw out the newline at the end of the buffer. If that is the case you may want to make sure it has a newline to throw out to begin with (the last line of the input file, for example may not end in one. Regardless, this is still broken, and needs to be fixed.

Next, your sort loop has issues. I'm including one below that is hopefully easier to read, and therefore understand, with logic flaws removed (and quite a bit of other extracurricular activity as well):

int insertlist(list *head, char *buffer)
{
    list p=NULL, q=NULL;
    int sc=0;

    /* allocate new node */
    p = calloc(1, sizeof(*p));
    if(3 != sscanf(buffer,"%d %s %f",&(p->id),(p->name),(&p->gpa)))
    {
        printf("info not complete\n");
        free(p);
        return 1;
    }

    /* initially wire p->next to our list head. then, walk list, 
       advancing p->next. break on first "less" condition */
    p->next = *head;
    while (p->next)
    {
        /* broken out here for clarity; break on first "less" */
        sc = strcmp(p->name, p->next->name);
        if (sc < 0 || (sc == 0 && p->id < p->next->id))
            break;
        q = p->next;
        p->next = q->next;
    }

    /* non-null means we wire q->next to p */
    if (q) 
        q->next = p;

    /* else p is the new head; what head was prior is already in p->next */
    else
        *head = p;

    return 0;
}

Tested with the following input file:

0001 Brook 3.50
0002 James 3.51
0003 Katie 3.52
0004 James 3.87
0005 Brook 2.70

Results:

1  Brook  3.500000

5  Brook  2.700000

2  James  3.510000

4  James  3.870000

3  Katie  3.520000

I strongly suggest you single-step through the code in a debugger when trying to fix these problems and when you want to see how code works.

Finally, not to add insult to injury, you never free your list. Ie it leaks memory on program exit, which is second only to leaking memory during execution in levels of "bad". Walk that list and release that memory. It is a good habit to get into.


EDIT OP Request for freeing the linked list:

For now, at the end of main() before the return statement will suffice. At some time you should consider writing a function to do this for you:

while (head)
{
    list p=head;
    head=head->next;
    free(p);
}

Your sorting issue is one of operator precedence

< and > have a higher precedence than = , meaning it will be evaluated first, then an assignment will take place.

So your string compares in these two places:

else if(sc=strcmp((*head)->name,p->name)> 0 || ((sc == 0) && ((*head)->id > p->id)))
...
while(q && ((sc=strcmp(q->name,p->name)<0) || ((sc == 0) && (q->id < p->id))))

are wrong. sc is getting the value of strcmp((*head)->name,p->name)> 0 and strcmp(q->name,p->name)<0 respectively (note this is going to always be 1 or 0 , never -1 )

If you simply adjust your code as such:

else if((sc=strcmp((*head)->name,p->name))> 0 || ((sc == 0) && ((*head)->id > p->id)))
...
while(q && (((sc=strcmp(q->name,p->name))<0) || ((sc == 0) && (q->id < p->id))))

You'll see it working. Moral of the story: don't try to be stingy with your parens or brackets, it doesn't cost you anything to put more in, it makes the code clearer, and it saves you debugging headaches like this one.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM