简体   繁体   English

c中的链表插入排序

[英]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. 程序应该对节点进行插入升序排序,首先它应该检查名称,如果名称相等,它应该对id进行排序,我不知道什么是不能正确排序的问题。

# 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 : 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. head是一个指针,所以为了在函数中更改它,你需要传递一个指针。 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: 编辑 OP请求释放链表:

For now, at the end of main() before the return statement will suffice. 现在,在return语句结束之前的main()就足够了。 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 ) sc得到strcmp((*head)->name,p->name)> 0strcmp(q->name,p->name)<0 (注意这将始终为10 ,永远不会-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. 故事的道德:不要试图用你的parens或括号来吝啬,它不会花费你更多的东西,它会使代码更清晰,它可以节省你这样的调试头痛。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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