【问题标题】:Sorting Linked List Alphabetically while new nodes are being scanned in (C)在 (C) 中扫描新节点时按字母顺序对链表进行排序
【发布时间】:2020-04-08 11:20:51
【问题描述】:

我已经为这个项目工作了一周,它将于今晚午夜完成。我是一名计算机科学专业的大一学生,对编程很陌生,所以我看不出这段代码有什么问题。该代码应该将事件标题、事件时间和事件日期读入链接列表,并使用事件标题按字母顺序排序。

这是来自文件的输入:

生日 12 30 2018 年 10 月 1 日 婚礼 06 30 2018 年 6 月 15 日 研讨会 05 00 2019 年 2 月 15 日 生日 04 00 2018 年 6 月 15 日 周年纪念日 08 30 2019 年 12 月 9 日

由于某种原因,它从未将婚礼事件连接到链表,并且在打印整个链表时,有一个空白节点作为头节点。我一直在研究这个问题,即使在跟踪代码时我也无法弄清楚出了什么问题。

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

//struct for event time
typedef struct{

  int hour;
  int minute;

} event_time_t;

//struct for event date
typedef struct{

  int month;
  int day;
  int year;

} event_date_t;

//struct for all event info
struct event{

  char event_title[20];
  event_time_t event_time;
  event_date_t event_date;
  struct event *next;

};

typedef struct event event_t;

void add_events (event_t **head_ptr);
void print_event(event_t *head_ptr);
void print_slected_event (event_t *head_ptr, int month, int day, int year);

int main () {

  event_t *head_ptr = malloc(sizeof(event_t));

  add_events(&head_ptr);

  print_event(head_ptr);

  print_slected_event(head_ptr,6,15,2018);

  return 0;
}

void add_events (event_t **head_ptr){

  event_t *temp;
  event_t *temp_head = *head_ptr;
  event_t *new_node;

  scanf(" %s",temp_head->event_title);
  scanf("%d",&temp_head->event_time.hour);
  scanf("%d",&temp_head->event_time.minute);
  scanf("%d",&temp_head->event_date.month);
  scanf("%d",&temp_head->event_date.day);
  scanf("%d",&temp_head->event_date.year);
  temp_head->next = NULL;

  while(!feof(stdin)){

    new_node = malloc(sizeof(event_t));

    scanf(" %s",new_node->event_title);
    scanf("%d",&new_node->event_time.hour);
    scanf("%d",&new_node->event_time.minute);
    scanf("%d",&new_node->event_date.month);
    scanf("%d",&new_node->event_date.day);
    scanf("%d",&new_node->event_date.year);



    if(temp_head->next == NULL){

      temp_head->next = new_node;

    }

    else if(strcmp(temp_head->event_title,new_node->event_title)>0){

      new_node->next = temp_head;
      temp_head = new_node;
      *head_ptr = temp_head;

    }

    else{

      temp = temp_head;

      while(temp->next!=NULL){

        if(strcmp(temp->event_title,new_node->event_title)==0){

          break;
        }
        if(strcmp(temp->event_title,new_node->event_title)<0){

          break;

        }

        temp = temp->next;
      }


        new_node->next = temp->next;
        temp->next = new_node;


    }


  }

}

void print_event(event_t *head_ptr){

  event_t *temp;
  temp = malloc(sizeof(event_t));
  temp = head_ptr;

  printf("Scedule of Events:\n");
  while(temp->next!=NULL){

    printf("\t%-13s at: %02d:%02d ",temp->event_title,temp->event_time.hour,temp->event_time.minute);
    printf("on: %02d/%02d/%d\n",temp->event_date.month,temp->event_date.day,temp->event_date.year);

    temp = temp->next;
  }
}

void print_slected_event (event_t *head_ptr, int month, int day, int year){

  event_t *temp;
  temp = malloc(sizeof(event_t));
  temp = head_ptr;

  printf("Date: %02d/%02d/%d\n",month,day,year);
  printf("Events:\n");
  while(temp->next!=NULL){

    if(temp->event_date.month == month){
      if(temp->event_date.day == day){
        if(temp->event_date.year == year){

          printf("\t%-13s at: %02d:%02d\n",temp->event_title,temp->event_time.hour,temp->event_time.minute);

        }
      }
    }

    temp = temp->next;
  }
}

【问题讨论】:

  • 仅供参考,while(!feof(stdin)) is wrong。最好你现在而不是以后知道。您的实际 IO 读取都没有经过任何验证,这是一个巨大错误。
  • 我的建议是重新设计。与其使用一个读取数据的函数,将其插入列表,然后对列表进行排序,不如将其拆分为多个责任有限的较小函数。遵循KISSsingle-responsibility 原则。因此,一个函数从文件中读取 一个 记录,一个函数将数据插入列表,一个函数对列表进行排序。
  • 而且仅供参考,您的 print 函数都不应该进行 any 分配。这两个函数的前三行会立即泄漏内存(准确地说,第二行和第三行一致)。
  • 打印时,不应测试temp-&gt;next 是否为空,而应测试temp。这会让你错过你的婚礼活动。 (打印和插入的不同之处在于打印只需要查看当前节点,插入必须查看两个连续的节点,以便更新它们的链接。)
  • @WhozCraig 好的,我做了一些阅读以找出为什么 !feof(stdin) 总是错误的,而且它非常有意义,所以我将其更改为 while(scanf(" %s",new_node-&gt;event_title)==1),它摆脱了那个随机的空头节点。我还摆脱了将内存分配给临时节点的打印功能。 @M Oehm 这更有意义,当我更改它时,它立即开始打印婚礼活动。非常感谢你们,自从课程被取消以来,链表一直很难,但由于阅读了你们的建议,我现在有了更好的理解。

标签: c pointers struct linked-list singly-linked-list


【解决方案1】:

在列表中插入节点的函数应与从文件中读取数据或用数据填充结构的代码分开。

我可以建议以下方法。

//struct for event time
typedef struct{

  int hour;
  int minute;

} event_time_t;

//struct for event date
typedef struct{

  int month;
  int day;
  int year;

} event_date_t;

//struct for all event info
typedef struct{
  char event_title[20];
  event_time_t event_time;
  event_date_t event_date;
} event_t;

//struct for node of the list
typedef struct node
{
    event_t event;
    struct node *next;
} node_t;

//struct for the list itself
typedef struct
{
    node_t *head;
} list_t;

在这种情况下,在列表中插入节点的函数可以如下所示

int add_event( list_t *list, event_t *event )
{
    node_t **current = &list->head;

    while ( *current != NULL && !( strcmp( event->event_title, ( *current )->event.event_title ) < 0 ) )
    {
        current = &( *current )->next;
    }

    node_t *new_node = malloc( sizeof( node_t ) );
    int success = new_node != NULL;

    if ( success )
    {
        new_node->event = *event;
        new_node->next = *current;

        *current = new_node;
    }

    return success;
}

在 main 中,您只需声明一个类似的列表

list_t list = { .head = NULL };

当您可以编写一个从文件读取数据、填充结构事件并调用函数add_event 传递指向列表的指针和指向填充结构的指针时。

这是一个简化的演示程序。

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

//struct for event time
typedef struct{

  int hour;
  int minute;

} event_time_t;

//struct for event date
typedef struct{

  int month;
  int day;
  int year;

} event_date_t;

//struct for all event info
typedef struct{
  char event_title[20];
  event_time_t event_time;
  event_date_t event_date;
} event_t;

//struct for node of the list
typedef struct node
{
    event_t event;
    struct node *next;
} node_t;

//struct for the list itself
typedef struct
{
    node_t *head;
} list_t;

int add_event( list_t *list, event_t *event )
{
    node_t **current = &list->head;

    while ( *current != NULL && !( strcmp( event->event_title, ( *current )->event.event_title ) < 0 ) )
    {
        current = &( *current )->next;
    }

    node_t *new_node = malloc( sizeof( node_t ) );
    int success = new_node != NULL;

    if ( success )
    {
        new_node->event = *event;
        new_node->next = *current;

        *current = new_node;
    }

    return success;
}

void print_list( const list_t *list )
{
    for ( const node_t *current = list->head; current != NULL; current = current->next )
    {
        printf( "%s -> ", current->event.event_title );
    }
    puts( "null" );
}

int main(void) 
{
    list_t list = { .head = NULL };

    event_t event = { "third", { 0 }, { 0 } };

    add_event( &list, &event );

    print_list( &list );

    strcpy( event.event_title, "first" );

    add_event( &list, &event );

    print_list( &list );

    strcpy( event.event_title, "second" );

    add_event( &list, &event );

    print_list( &list );

    return 0;
}

程序输出是

third -> null
first -> third -> null
first -> second -> third -> null

这是开发项目的起点。

【讨论】:

    猜你喜欢
    • 2015-12-08
    • 2015-01-13
    • 2012-03-31
    • 2019-05-14
    • 2014-06-04
    • 2016-10-12
    • 2013-05-02
    • 2014-02-08
    • 1970-01-01
    相关资源
    最近更新 更多