使用 qsort 对结构进行排序

Sorting Structures using qsort

我必须使用快速排序按年龄等于或大于 65 岁的人口百分比对各州进行排序。我不知道如何在函数中使用它。

我似乎无法更改比较功能。我还必须创建一个名为输出文件的新文件。我使用选择排序对文件进行排序。

struct state {
    char state_name[150];
    int population_2020;
    int population_2010;
    double ages_under_5;
    double ages_under_18;
    double ages_65_or_greater;
};

void sort_states(struct state list[], int n) 
{
    int i, j, p;
    struct state temp;

    for (i = 0; i < n; i++) {
        p = i;
        for (j = i + 1; j < n; j++) {
            if (list[p].ages_65_or_greater < list[j].ages_65_or_greater) {
                p = j;
            }
        }
        temp = list[p];
        list[p] = list[i];
        list[i] = temp;
    }
}

int main()
{
    char input_file_open[100]; /* initializing the variables */
    char output_file_name[110];

    printf("Enter the file name: \n");
    scanf("%s", input_file_open);

    FILE *input_file = fopen(input_file_open, "r"); 
    FILE *output_file;

    struct state list[100];
    int i, n = 0;

    do {
        fscanf(input_file, "%[^,], %d, %d, %lf, %lf, %lf\n",
               list[n].state_name, &list[n].population_2020,
               &list[n].population_2010, &list[n].ages_under_5,
               &list[n].ages_under_18, &list[n].ages_65_or_greater);
        n++;
    } while (!feof(input_file));

    fclose(input_file);

    for (i = 0; i < n; i++) {
        qsort(input_file, n, sizeof(int), sort_states);
    }

    return 0;
}

您必须为您的结构定义一个比较函数:

int state_compare_by_age_65_or_gt(const void *s1, const void *s2)
{
    const struct state *ss1 = s1;
    const struct state *ss2 = s2;
    
    if (ss1->ages_65_or_greater < ss2->ages_65_or_greater)
        return -1;
    else if (ss1->ages_65_or_greater > ss2->ages_65_or_greater)
        return 1;
    else
        return 0;
}

以及打印状态的功能(用于测试目的,但您也可以将其用于 non-testing 目的):

void state_print(const struct state *st)
{
    printf("%s\t%d\t%d\t%.2lf\t%.2lf\t%.2lf",
        st->state_name,
        st->population_2020,
        st->population_2010,
        st->ages_under_5,
        st->ages_under_18,
        st->ages_65_or_greater
    );
}

现在您可以将它与 qsort() 一起使用了:

int main(void)
{
    struct state states[] = {
        {"state1", 100, 200, 2.0, 3.0, 13.0},
        {"state2", 100, 200, 2.0, 4.0, 10.0},
        {"state3", 100, 200, 2.0, 5.0, 12.0},
        {"state4", 100, 200, 2.0, 6.0, 11.0},
        {"state5", 100, 200, 2.0, 7.0, 36.0},
        {"state6", 100, 200, 10.0, 8.0, 140.0},
    };

    qsort(states, 6, sizeof(struct state), state_compare_by_age_65_or_gt);

    for (int i = 0; i < 6; i++) {
        state_print(&states[i]);
        puts("");
    }
}

输出:

state2  100 200 2.00    4.00    10.00
state4  100 200 2.00    6.00    11.00
state3  100 200 2.00    5.00    12.00
state1  100 200 2.00    3.00    13.00
state5  100 200 2.00    7.00    36.00
state6  100 200 10.00   8.00    140.00

或者,您可以使用结构指针数组进行优化排序。

  1. 输入文件(借用上面的答案)
state1, 111, 211, 2.0, 3.0, 13.0
state2, 222, 322, 2.0, 4.0, 10.0
state3, 333, 433, 2.0, 5.0, 12.0
state4, 444, 544, 2.0, 6.0, 11.0
state5, 555, 655, 2.0, 7.0, 36.0
state6, 666, 755, 10.0, 8.0, 140.0
  1. qsort 使用结构指针:
#include <stdio.h>
#include <stdlib.h>

#define str(x)          # x
#define xstr(x)         str(x)

#define MAX_NAME_LEN    127

typedef struct {
    char name [MAX_NAME_LEN +1];
    int pop_2020;
    int pop_2010;
    double age_lt5;     // less than 5
    double age_lt18;
    double age_gte65;    // greater or equal
} state_dtls;

int qsort_cmp (const void *p, const void *q) {
    state_dtls *x = *(state_dtls **) p;
    state_dtls *y = *(state_dtls **) q;
    return (x->age_gte65 < y->age_gte65);
}

#define RECORD_STEP_SZ 2

int main() {
    char in_file[MAX_NAME_LEN + 1]; /* intializing the variables */
    char out_file[MAX_NAME_LEN + 1];

    printf ("Enter Input file name: ");
    scanf (" %" xstr(MAX_NAME_LEN) "s", in_file);

    printf ("Enter Output file name: ");
    scanf (" %" xstr(MAX_NAME_LEN) "s", out_file);

    FILE *ipFile = fopen (in_file, "r");
    if (!ipFile) {
        perror ("Error Opening Input File"); return 1;
    }
    int rec_step = 0;
    state_dtls** SPA = malloc (sizeof (state_dtls*) * RECORD_STEP_SZ * (++rec_step)); // state-details pointers array
    if (!SPA) {
        perror ("Error malloc SPA"); return 3;
    }
    int records = 0;
    for (int ri = 0; 1; ++ri) {
        state_dtls* sd = malloc (sizeof (state_dtls));
        if (!sd) {
            perror ("Error malloc state-dtls"); return 4;
        }
        if ((rec_step * RECORD_STEP_SZ) == ri) { // need more space for pointers
            SPA = realloc (SPA, sizeof (state_dtls*) * RECORD_STEP_SZ * (++rec_step));
            if (!SPA) {
                perror ("Error malloc SPA2"); return 5;
            }
        }
        if (6 != fscanf (ipFile, "%[^,], %d, %d, %lf, %lf, %lf\n",
            sd->name, &sd->pop_2020, &sd->pop_2010,
            &sd->age_lt5, &sd->age_lt18, &sd->age_gte65)) {
                printf ("Error reading record [%d]\n", ri +1);
                records = ri;
                free (sd);
                break; // break the loop // EOF
            }
        SPA[ri] = sd;
    }
    fclose (ipFile);

    qsort (SPA, records, sizeof (state_dtls*), qsort_cmp);

    // write to output file
    FILE *opFile = fopen (out_file, "w");
    if (!opFile) {
        perror ("Error Opening output File"); return 2;
    }
    for (int ri = 0; ri < records; ++ri) {
        fprintf (opFile, "%s, %d, %d, %lf, %lf, %lf\n",
                 SPA[ri]->name, SPA[ri]->pop_2020, SPA[ri]->pop_2010,
                 SPA[ri]->age_lt5, SPA[ri]->age_lt18, SPA[ri]->age_gte65);
        free (SPA[ri]); // free memory resources as well
    }
    free (SPA);
    fclose (opFile);

    return 0;
}
  1. 具有降序 age_gte65 参数的输出文件:
state6, 666, 755, 10.000000, 8.000000, 140.000000
state5, 555, 655, 2.000000, 7.000000, 36.000000
state1, 111, 211, 2.000000, 3.000000, 13.000000
state3, 333, 433, 2.000000, 5.000000, 12.000000
state4, 444, 544, 2.000000, 6.000000, 11.000000
state2, 222, 322, 2.000000, 4.000000, 10.000000