【问题标题】:linked list insertion sort in cc中的链表插入排序
【发布时间】:2012-12-29 12:27:52
【问题描述】:

程序应该对节点进行插入升序排序,首先它应该检查名称,如果名称相等,它应该对 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);
}

student.txt的内容示例:

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

【问题讨论】:

  • 不要害怕使用更具描述性的变量名称。编译器不会抱怨,但阅读您的代码的人可能会抱怨。
  • 您是否有机会从您的student.txt 文件中为我们节省一些输入和粘贴示例(比如 10 行)?谢谢。

标签: c sorting linked-list


【解决方案1】:

您的排序问题是operator precedence之一

&lt;&gt; 的优先级高于=,这意味着它会先被评估,然后才会发生分配。

所以你的字符串在这两个地方比较:

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

错了。 sc 分别获得 strcmp((*head)-&gt;name,p-&gt;name)&gt; 0strcmp(q-&gt;name,p-&gt;name)&lt;0 的值(注意这将始终是 10,永远不会是 -1

如果您只是这样调整代码:

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

你会看到它工作。故事的寓意:不要吝啬你的括号或括号,添加更多内容不会花费你任何成本,它使代码更清晰,并且可以让你免于调试这样的麻烦。

【讨论】:

  • +1 大声笑。用于发现问题。我找到了它,但完全间隔将它放在我的答案中。我也是“到底是什么……”的思维定势并将代码简化为希望更简单的算法。漂亮的眼睛,顺便说一句。
  • @Mike 我想我可能已经使用了很多括号,虽然不是在正确的地方,谢谢纠正
【解决方案2】:

head 是一个指针,因此要在函数中更改它,您需要将指针传递给它。指向指针的指针。

这样声明:

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

这样称呼它:

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

然后在函数中更改引用它的任何地方以取消引用指针。

【讨论】:

  • @maziarparsaeian 也不正确。您的头指针已经通过地址传递。 (&amp;(&amp; 让我头晕目眩)。
【解决方案3】:

首先,解决这个问题:

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

这是一个相等比较;不是任务。我相信您正试图在缓冲区末尾抛出换行符。如果是这种情况,您可能需要确保它一个换行符开始抛出(例如,输入文件的最后一行可能不会以一个结尾。无论如何,这仍然是坏了,需要修复。

接下来,您的排序循环有问题。我在下面包括一个希望更容易阅读和理解的内容,并消除了逻辑缺陷(以及相当多的其他课外活动):

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

使用以下输入文件进行测试:

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

结果:

1  Brook  3.500000

5  Brook  2.700000

2  James  3.510000

4  James  3.870000

3  Katie  3.520000

强烈建议您在尝试解决这些问题时在调试器中单步执行代码以及如果您想了解代码的工作原理。

最后,不要雪上加霜,你永远不会释放你的列表。即它在程序退出时泄漏内存,这仅次于在“坏”级别执行期间泄漏内存。走那张清单,释放那段记忆。养成一个好习惯。


EDIT OP 请求释放链表:

目前,在main() 的末尾加上return 语句就足够了。有时您应该考虑编写一个函数来为您执行此操作:

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

【讨论】:

  • +1 建议更简洁的代码。您没有确定最初的问题是什么,但更简洁的代码(像这样)无论如何都会修复它。
  • @WhozCraig 可以请你建议我应该在哪里释放代码中的指针?
  • @maziarparsaeian 当然。
  • @WhozCraig 你的意思是在我的主要功能中打印节点后我使用提到的功能来释放列表?
  • @WhozCraig 如果我保留节点并再次操作它们以解决其他问题怎么办?
猜你喜欢
  • 2013-04-04
  • 1970-01-01
  • 2016-08-26
  • 1970-01-01
  • 2020-12-11
  • 1970-01-01
  • 1970-01-01
  • 2020-06-13
  • 1970-01-01
相关资源
最近更新 更多