首页 文章

对结构中的多个项进行qsort

提问于
浏览
4

我的任务是用户输入包含月份,日期和年份的n行,格式为“1月12日99” .

我必须按时间顺序排序日期列表,首先使用qsort逐年,然后按天,然后按月 .

我的问题是我不知道如何对多个索引进行qsort . 我已经完成了今年的工作,但是在那之后我不知道如何在当天进行调整,因为它肯定会在白天对它进行排序,但这些年将再次混乱?

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

typedef int (*compfn)(const void*, const void*);

struct date
{
    char month[9]; //Maximum of 9 characters in a month
    int day; //The day of the month (e.g. 18)
    int year; //The year of the date    
};

int sortDates(struct date *elem1, struct date *elem2)
{

    if (elem1 -> year < elem2 -> year)
    {
        return -1;
    }
    else 

    if (elem1->year > elem2->year)
        {
        return 1;
    }
    else
        return 0;

}


main()
{
    int n;
    int i;

    scanf("%d", &n);

    struct date *list;

    list = (struct date *)malloc((n * sizeof(struct date)));

    for(i = 0; i < n; i++)
    {
        scanf("%s %d %d", list[i].month, &list[i].day, &list[i].year);
    }

    qsort(list, sizeof(list), sizeof(struct date), (compfn)sortDates);

    for(i = 0; i < n; i++)
    {
        printf("%s %d %d\n", list[i].month, list[i].day, list[i].year);
    }
}

EDIT: 所以我有排序工作,我正在努力将一个整数转换回打印排序列表时的月份字符串表示 . 这是代码,我得到"array subscript is not an integer"错误 .

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

typedef int (*compfn)(const void*, const void*);

struct date
{
    int month;
    int day; //The day of the month (e.g. 18)
    int year; //The year of the date    
};

char* months[]= {
   "January", "February",
   "March", "April",
   "May", "June",
   "July", "August",
   "September", "October",
   "November", "December"};


int getMonth(char tempMonth[])
{
    int i = 0;
    for(i = 0; i<12; i++)
    {
            if(tempMonth == months[i]) return i;
    }
    return 0;
}

char getStringMonth(struct date month)
{
    return months[month];
}

int sortDates(struct date *elem1, struct date *elem2)
{
    if (elem1 -> year < elem2 -> year)
    {
        return -1;
    }
    else 

    if (elem1->year > elem2->year)
        {
        return 1;
    }


    if ( elem1->month < elem2->month )
    {
            return -1;
    }
    else 

    if ( elem1->month > elem2->month )
        {
        return 1; 
    }


    if ( elem1->day < elem2->day )
    {list
            return -1;
    }
        else 

    if ( elem1->day > elem2->day )
        {
        return 1;
    } 
        else

    return 0;
}

main()
{
    int n;
    int i;
    char tempMonth[255]; //Used to store the month until checked

    scanf("%d", &n);list

    struct date *list;

    list = (struct date *)malloc((n * sizeof(struct date)));

    for(i = 0; i < n; i++)
    {
        scanf("%s %d %d", tempMonth, &list[i].day, &list[i].year);
        list[i].month = getMonth(tempMonth);
    }

    qsort(list, sizeof(list), sizeof(struct date), (compfn)sortDates);

    for(i = 0; i < n; i++)
    {
        printf("%s %d %d", getStringMonth(list[i].month), list[i].day, list[i].year);
    }

}

5 回答

  • 1

    记住 free 你的记忆 .

    在下面的代码中,我假设月份存储为数字,但我在您的结构中看到情况并非如此 . 我将输入的月份从字符串转换为数字,以简化排序过程 .

    int sortDates(struct date* elem1, struct date* elem2)
    {
    
        if ( elem1->year < elem2->year)
            return -1;
        else if ( elem1->year > elem2->year )
            return 1;
    
    
        /* here you are sure the years are equal, so go on comparing the months */
    
        if ( elem1->month < elem2->month )
            return -1;
        else if ( elem1->month > elem2->month )
            return 1; 
    
        /* here you are sure the months are equal, so go on comparing the days */
    
        if ( elem1->day < elem2->day )
            return -1;
        else if ( elem1->day > elem2->day )
            return 1; 
        else
            return 0; /* definitely! */
    
    }
    

    另外要注意这个声明: char month[9]; ,9月份确实是9个字符,但你需要一个终止符char '\0' 在C中关闭一个字符串 . 为了避免这种问题,我会声明一个包含所有月份的数组,以允许检查并将月份从字符串转换为数字:

    char* allMonths[]=
       "January", "February",
       "March", "April",
       "May", "June",
       "July", "August",
       "September", "October",
       "November", "December";
    
    char tmpMonth[255];
    scanf("%s %d %d", tmpMonth, &list[i].day, &list[i].year);
    /* convert tmpMonth to a number by finding it in the allMonths and throw error if not found */
    
  • 5

    当两年相等时,不要返回0,只需复制粘贴逻辑并将其应用到几个月 . 再过几天 . 就这样 .

    顺便说一句,如果你想按时间顺序排序,你必须先排序年份,然后是月份,然后是日期 . 不是几天而是几个月 .

    你应该将月份存储为数字,而不是字符串:按时间顺序排列会更容易 .

    最后,我将函数命名为 compareDates ,而不是 sortDates .

  • 2

    而不是在最后 else 上返回0,而是比较另一个字段:

    else {
        if (elem1->day < elem2->day) {
            return -1;
        }
        else if (elem1->day > elem2->day) {
            return 1;
        }
        else {
            //compare months
        }
    }
    

    基本思路是:

    • 检查年份,如果它们的返回结果不一样(和你一样)

    • 如果年份相同,请检查天数,如果它们的返回结果不同

    • 如果天数也相同,请检查月份 .

  • 1

    你所拥有的一年(主要关键)是好的 . 当年份相等时,您只需稍微调整即可使用月份(次要键),您可以根据需要将其扩展到多个级别的键 .

    伪代码仅用于家庭作业,我担心:

    def compare (date1, date2):
        if date1.year > date2.year:
            return 1
        if date1.year < date2.year:
            return -1
    
        # Years are equal here.
    
        if date1.month > date2.month
            return 1
        if date1.month < date2.month
            return -1
    
        # Years and months are equal here.
    
        if date1.day > date2.day
            return 1
        if date1.day < date2.day
            return -1
    
        # Years, months and days are all equal here.
    
        return 0
    

    通过执行这样的单个"layered"比较功能,您不必担心月份排序搞砸了多年的顺序,因为它在一年内按月排序 .

    而且,正如你所看到的,我不是以下的忠实粉丝:

    if condition:
        return something
    else:
        carry on
    

    成语 . else 完全没有必要,并且可以在不需要的情况下导致大量缩进 . 我更喜欢:

    if condition:
        return something
    
    carry on
    

    实际的排序方法最好将这些月份名称转换为数值,以便比较更好 . 这可能最好留给另一个问题,但你可能会把一些字符串数组合在一起:

    char *months[] = {"January", "February", ... "December"};
    

    for 循环将名称转换为 011 范围内的值 .

  • 0

    您应该更改您的比较函数 sortDates ,并根据年份相等的日期和日期和月份相等的月份做出决定 .

相关问题