繁体   English   中英

我如何按 C 中的字符对结构进行排序?

[英]How i can sort struct by characters in C?

我使用了按数字对结构进行排序的策略,但是这种策略不起作用。

#include <stdio.h>
#define MAX 1000

typedef struct person_{
    char name[100];
    int age;
}person;

void scan_person(person *ptr);
void print_ind(person p);

int name_index_min(person *ptr, int N, int st);

void swap(person *x, person *y);

void sort_name_as(person *ptr, int N);
void sort_name_ds(person *ptr, int N);

int main () {
    person individulas[MAX];
    int n_ind;

    puts("Enter Number of people:");
    scanf("%d",&n_ind);
    for (int i = 0; i < n_ind; i++)
        scan_person(individulas + i);

    printf("\n");

    sort_name_as(individulas,n_ind);
    for (int i = 0; i < n_ind; i++)
        print_ind(individulas[i]); 

    puts("\n");

    sort_name_ds(individulas,n_ind);
    for (int i = 0; i < n_ind; i++)
        print_ind(individulas[i]);   

    printf("\n"); 
      return 0;
}   

void scan_person(person *ptr){

    printf("\nEnter Name & Surename :");
    scanf("\n%99[^\n]", ptr->name);

    printf("Enter Age :");
    scanf ("%d%*c", &(ptr->age));
    printf("\n");
}
void print_ind(person p){
    printf("%s %d  ", p.name, p.age);
}
int name_index_min(person *ptr, int N, int st){

    int min = st;
    for (int i = st+1; i < N; i++)
        if(ptr[i].name < ptr[min].name)
            min = i;
    return min;
}
int name_index_max(person *ptr, int N, int st){

    int max = st;
    for (int i = st+1; i < N; i++)
        if(ptr[i].name > ptr[max].name)
            max = i;
    return max;
}

void swap(person *x, person *y){
    person temp = *x;
    *x = *y;
    *y = temp;
}

void sort_name_as(person *ptr, int N){
    int aux;
    for (int i = 0; i < N-1; i++){
        aux = name_index_min(ptr, N, i);
        if (aux != i)
            swap(ptr + i, ptr + aux);
    }
}

void sort_name_ds(person *ptr, int N){
    int aux;
    for (int i = 0; i < N-1; i++){
        aux = name_index_max(ptr, N, i);
        if (aux != i)
            swap(ptr + i, ptr + aux);
    }
}

这是示例:

输入:

输入人数:3

输入姓名和姓名:Jeffrey L. Davis
进入年龄:80

输入姓名和姓名:Yaseen Nur al Din Khoury
进入年龄:80

输入姓名和姓名:Joeri Ong
进入年龄:80

Output:

Joeri Ong 80 Jeffrey L. Davis 80 Yaseen Nur al Din Khoury 80 //ascendig order

Yaseen Nur al Din Khoury 80 Jeffrey L. Davis 80 Joeri Ong 80 //descendig order

每当您在 C 中遇到排序问题时,您应该立即考虑qsort 它是一款高效灵活的分拣function,可以处理任何需要分拣的object类型。 通常让新的 C 程序员害怕的是,您必须编写一个compare() function 来告诉qsort如何比较和排序指向数组中元素的两个指针 比较 function 的原型是:

int compare (const void *a, const void *b)

所有ab指针都是指向当前正在比较的数组中的两个元素的指针。 您唯一的工作是将它们转换为正确的类型,然后告诉qsort您希望如何比较它们。 先看你的第一个function先按age升序比较,然后如果年龄相等,再比较名字,让所有同年龄的患者按字母顺序排序,先从原型开始:

int compasc (const void *a, const void *b)      /* qsort compare ascending by age */
{

不知道你的数组元素是什么类型(这里是stuct person ),所以ab的类型是指向struct person的指针。 您的工作只是将指针ab转换为类型person* ,例如

    const person *pa = a, *pb = b;

因此,您可以在 function 中使用person*指针papb来代替void *指针ab 如果年龄不同,比较年龄并返回,例如

    if (pa->age != pb->age)
        return (pa->age > pb->age) - (pa->age < pb->age);

否则,年龄相等,因此您可以按name进行比较,例如

    return (strcmp (pa->name, pb->name));
}

这就是您比较 function 所需要的。 完整的将是:

int compasc (const void *a, const void *b)      /* qsort compare ascending by age */
{
    const person *pa = a, *pb = b;

    if (pa->age != pb->age)
        return (pa->age > pb->age) - (pa->age < pb->age);

    return (strcmp (pa->name, pb->name));
}

按年龄比较降序操作与age比较不同,这将导致按年龄降序排序。 无论如何,如果年龄相同,则按姓名按字母顺序排序。

您很好地定义了要在数组中使用的最大struct person数的常量,但是您也可以为name的大小声明一个常量,例如

#define MAXNM  100
#define MAXP  1000

typedef struct person {
    char name[MAXNM];
    int age;
} person;

注意: '_'已从person_中删除,因为 POSIX 对保留以下划线开头/结尾的名称很挑剔——并且您的结构标记typdef名称不需要不同)

main()中,使用面向行的输入 function (如fgets()或 POSIX getline() ),您可以更好地读取用户输入的一行。 这可以确保在stdin中没有多余的未读字符,这些字符可能会在您下次尝试阅读时对您造成影响。 所以只需声明一个简单的字符数组buf用作缓冲区来保存所有输入行。 然后,您可以使用sscanf()从行中获取所需的内容来处理任何转换。 要读取和存储数组中的所有数据,您可以执行以下操作:

int main (void) {

    int n_ind = 0;
    person individuals[MAXP] = {{ .name = "" }};

    while (n_ind < MAXP) {
        char buf[MAXP] = "";                /* buffer to hold line of input */
        person tmp = { .name = "" };        /* temporary struct to fill */

        fputs ("\nenter name & surname: ", stdout);
        if (!fgets (buf, MAXNM, stdin))
            return 1;
        if (*buf == '\n')
            break;

        buf[strcspn (buf, "\n")] = 0;       /* trim trailing '\n' */
        strcpy (tmp.name, buf);

        fputs ("enter age: ", stdout);
        if (!fgets (buf, MAXP, stdin))
            return 1;
        if (sscanf (buf, "%d", &tmp.age) == 1)  /* validate age conversion */
            individuals[n_ind++] = tmp;         /* add tmp to array update n_ind */
    }

注意: fgets()还使您能够检查第一个字符是否是'\n' - 允许您在name提示符处单独使用Enter来指示用户已完成输入 - 您不需要'不需要让他们输入他们将输入的数量。您只需继续添加名称,直到用户在name提示下单独按Enter 键。)

现在使用qsort排序变得微不足道,只需传递您的数组、元素的数量、每个元素的大小以及您希望qsort使用的比较 function ,它会执行 rest,例如

    qsort (individuals, n_ind, sizeof *individuals, compasc);   /* sort ascending */

这就是按年龄升序排序 - 您的individuals数组现在按年龄排序,然后按名称排序。

将它与升序和降序排列在一起,您将拥有:

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

#define MAXNM  100
#define MAXP  1000

typedef struct person {
    char name[MAXNM];
    int age;
} person;

int compasc (const void *a, const void *b)      /* qsort compare ascending by age */
{
    const person *pa = a, *pb = b;

    if (pa->age != pb->age)
        return (pa->age > pb->age) - (pa->age < pb->age);

    return (strcmp (pa->name, pb->name));
}

int compdesc (const void *a, const void *b)     /* qsort compare descending by age */
{
    const person *pa = a, *pb = b;

    if (pa->age != pb->age)
        return (pa->age < pb->age) - (pa->age > pb->age);

    return (strcmp (pa->name, pb->name));
}

int main (void) {

    int n_ind = 0;
    person individuals[MAXP] = {{ .name = "" }};

    while (n_ind < MAXP) {
        char buf[MAXP] = "";                /* buffer to hold line of input */
        person tmp = { .name = "" };        /* temporary struct to fill */

        fputs ("\nenter name & surname: ", stdout);
        if (!fgets (buf, MAXNM, stdin))
            return 1;
        if (*buf == '\n')
            break;

        buf[strcspn (buf, "\n")] = 0;       /* trim trailing '\n' */
        strcpy (tmp.name, buf);

        fputs ("enter age: ", stdout);
        if (!fgets (buf, MAXP, stdin))
            return 1;
        if (sscanf (buf, "%d", &tmp.age) == 1)  /* validate age conversion */
            individuals[n_ind++] = tmp;         /* add tmp to array update n_ind */
    }

    qsort (individuals, n_ind, sizeof *individuals, compasc);   /* sort ascending */
    puts ("\nascending order by age:");

    for (int i = 0; i  < n_ind; i++)
        printf ("  %-24s    %2d\n", individuals[i].name, individuals[i].age);

    qsort (individuals, n_ind, sizeof *individuals, compdesc);  /* sort descending */
    puts ("\ndescending order by age:");

    for (int i = 0; i  < n_ind; i++)
        printf ("  %-24s    %2d\n", individuals[i].name, individuals[i].age);

}

示例使用/输出

按年龄排序,如果年龄相等,则按姓名排序:

$ ./bin/individualsbyage

enter name & surname: Jeffrey L Davis
enter age: 80

enter name & surname: Yaseen Nur al Din Khoury
enter age: 80

enter name & surname: Joeri Ong
enter age: 80

enter name & surname:

ascending order by age:
  Jeffrey L Davis             80
  Joeri Ong                   80
  Yaseen Nur al Din Khoury    80

descending order by age:
  Jeffrey L Davis             80
  Joeri Ong                   80
  Yaseen Nur al Din Khoury    80

现在一个简单的例子表明,如果年龄不同,则会获得正确的排序:

$ /bin/individualsbyage

enter name & surname: Jeffrey L Davis
enter age: 81

enter name & surname: Yaseen Nur al Din Khoury
enter age: 80

enter name & surname: Joeri Ong
enter age: 79

enter name & surname:

ascending order by age:
  Joeri Ong                   79
  Yaseen Nur al Din Khoury    80
  Jeffrey L Davis             81

descending order by age:
  Jeffrey L Davis             81
  Yaseen Nur al Din Khoury    80
  Joeri Ong                   79

qsort除了针对快速排序进行了优化之外的另一个好处是,它也已经被 100,000 人使用和测试,如果不是 1,000,000 人,并且经过验证。 (对于一种你碰巧在一夜之间拼凑起来的人来说不是这样)

如果您还有其他问题,请查看并告诉我。

您的方法的主要问题是您正在比较名称的 memory 地址,而不是 arrays 中包含的值。

当您按名称引用数组时,您实际上是在获取其地址。 我建议您使用strcmp在您的最小/最大搜索功能上比较name arrays。

快速查看您的代码发现这是其中唯一的问题。

此处提供了此方法的实现,其输入略有简化(使用ABC作为名称): https://onlinegdb.com/r1NkRiNKL

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM