Search code examples
cselection-sort

Getting wrong output while trying to sort information first by age and in case of same age then alphabetically


So I have to sort a list of people's information by their ages. In case there are people of the same ages, I have to sort them by their names alphabetically.

Here's my code:

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

struct people{
    char name[30];
    int age;
};

int main(){
    int n, i, j, min, tmp1;
    scanf("%d", &n);
    struct people person[n], temp;

    for(i = 0; i < n; i++){
        scanf("%s%d", person[i].name, &(person[i].age));
    }
    
    // SELECTIONN SORT
    for(i = 0; i < n - 1; i++){
        min = i;
        for(j = i + 1; j < n; j++){
            if (person[j].age < person[i].age ||
                strcmp(person[j].name,person[min].name) < 0 && person[j].age == person[min].age){
                min = j;
            }
        }
        if(min != i){
            temp.age = person[i].age;
            person[i].age = person[min].age;
            person[min].age = temp.age;

            strcpy(temp.name, person[i].name);
            strcpy(person[i].name, person[min].name);
            strcpy(person[min].name, temp.name);
        }
    }

    for(i = 0; i < n; i++){
        printf("%s %d\n", person[i].name, (person[i].age));
    }
}

In almost all of the cases I tried, the code works, however, on this certain input I get "Mary 15" before "Anna 15" and I have no idea why, here's the input:

5
Gilbert 35
Anna 35
Anna 15
Mary 15
Joseph 40

Solution

  • I think the compare you're doing isn't right.

    Change:

    person[j].age < person[i].age
    

    Into:

    person[j].age < person[min].age
    

    And, as I mentioned in my top comment, the swap can be simplified.

    And, we can split up the if to make it clearer with no loss of speed.


    Here is the corrected code. It is annotated:

    #include <stdio.h>
    #include <string.h>
    
    struct people {
        char name[30];
        int age;
    };
    
    int
    main(void)
    {
        int n, i, j, min, tmp1;
    #if 1
        int dif;
    #endif
    
        scanf("%d", &n);
    
        struct people person[n], temp;
        for (i = 0; i < n; i++) {
            scanf("%s%d", person[i].name, &(person[i].age));
        }
    
        // SELECTIONN SORT
        for (i = 0; i < n - 1; i++) {
            min = i;
            for (j = i + 1; j < n; j++) {
    #if 0
                if (person[j].age < person[i].age ||
                    strcmp(person[j].name, person[min].name) < 0 &&
                    person[j].age == person[min].age) {
                    min = j;
                }
    #else
                dif = person[j].age - person[min].age;
    
                // ages are out-of-sort
                if (dif < 0) {
                    min = j;
                    continue;
                }
    
                // ages are in-sort
                if (dif > 0)
                    continue;
    
                // compare names only if ages are the same
                dif = strcmp(person[j].name, person[min].name);
                if (dif < 0) {
                    min = j;
                    continue;
                }
    #endif
            }
    
            if (min != i) {
    // we can simplify this ...
    #if 0
                temp.age = person[i].age;
                person[i].age = person[min].age;
                person[min].age = temp.age;
    
                strcpy(temp.name, person[i].name);
                strcpy(person[i].name, person[min].name);
                strcpy(person[min].name, temp.name);
    #else
                temp = person[i];
                person[i] = person[min];
                person[min] = temp;
    #endif
            }
        }
    
        for (i = 0; i < n; i++) {
            printf("%s %d\n", person[i].name, (person[i].age));
        }
    }
    

    In the code above, I've used cpp conditionals to denote old vs. new code:

    #if 0
    // old code
    #else
    // new code
    #endif
    
    #if 1
    // new code
    #endif
    

    Note: this can be cleaned up by running the file through unifdef -k


    Here is the output of the corrected code:

    Anna 15
    Mary 15
    Anna 35
    Gilbert 35
    Joseph 40