对结构中的多个项目进行 qsort

Posted

技术标签:

【中文标题】对结构中的多个项目进行 qsort【英文标题】:qsort on more than one item in a struct 【发布时间】:2012-03-25 22:20:56 【问题描述】:

我的任务是让用户以“99 年 1 月 12 日”的形式输入包含月、日和年的 n 行。

我必须先使用 qsort 按年,然后按天,然后按月,按时间顺序对日期列表进行排序。

我的问题是我不确定如何对多个索引进行 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);
    

编辑:所以我的排序工作正常,我只是在打印排序列表时努力将整数转换回月份的字符串表示形式。这是代码,我收到“数组下标不是整数”错误。

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


【问题讨论】:

请不要那样做。如果您还有其他问题,请再问一个。 【参考方案1】:

记住freemalloc的记忆。

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

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个字符,但是你需要C中的终止符'\0'来关闭一个字符串。为了避免这种问题,我会声明一个包含所有月份的数组,以允许检查并将月份从字符串转换为数字:

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 */

【讨论】:

在输出月份时从整数返回字符串时遇到了一点问题。我已经编辑了我原来的问题。任何帮助,无论多小都会很棒 allMonths[month_number -1] 可以。 month_number 在 [1-12] 范围内,而数组索引从 0 开始。【参考方案2】:

不要在两年相等时返回 0,而是复制粘贴逻辑并将其应用于月份。然后又是几天。就是这样。

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

您应该将月份存储为数字,而不是字符串:这对于按时间排序会更容易。

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

【讨论】:

【参考方案3】:

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

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

基本思路是:

    检查年份,如果它们不是相同的返回结果(与您一样) 如果年份相同,则检查天数,如果不同则返回结果 如果天数也相同,请检查月份。

【讨论】:

【参考方案4】:

今年你所拥有的一切都很好(大调)。当年份相等时,您只需稍作调整即可使用月份(次要键),您可以将其扩展到任意多级键。

伪代码仅用于家庭作业,恐怕:

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

通过像这样进行单个“分层”比较功能,您不必担心月份排序会打乱年份的顺序,因为它按天排序 年内。

而且,如您所见,我不是以下内容的忠实粉丝:

if condition:
    return something
else:
    carry on

成语。 else 是完全没有必要的,并且会在不需要的地方导致大量缩进。我更喜欢:

if condition:
    return something

carry on

实际的排序方法最好将这些月份名称转换为数值,以便更好地进行比较。这可能最好留给另一个问题,但您可能可以将一些东西与一个字符串数组放在一起:

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

和一个for 循环将名称转换为011 范围内的值。

【讨论】:

【参考方案5】:

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

【讨论】:

以上是关于对结构中的多个项目进行 qsort的主要内容,如果未能解决你的问题,请参考以下文章

排序中的qsort和sort

使用 qsort 对结构指针数组进行排序

使用 qsort() 对指向包含字符串的结构的指针进行排序

Qsort 结构体数组

qsort函数sort函数

在c中怎样用qsort对结构体数组进行多级排序