简体   繁体   中英

Sorting array of structs by second field in C

My professor recommended us to use qsort() to sort an array of structs. However, I have to come to find out that it is not stable. I know there are other posts about this topic, but none seem to give an easy fix to stabilize my sort. Is there a way that I could use qsort() for a second data field?

Here is my code:

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

struct Map * collect_values(int n, int *arr);
void sort_values(struct Map *ptr, int n);
void print(struct Map *print_struct, int n);

struct Map{
    int value, position;
};

int compare(const void *aptr, const void *bptr){
    int a = ((struct Map*)aptr)->value, b = ((struct 
Map*)bptr)->value;
return (a > b) - (a < b);
}

int main(){
    int size, i;
    scanf("%d", &size);
    int *arr = (int*) malloc(size*sizeof(int));
    struct Map *p = collect_values(size,arr);
    qsort(p,size,sizeof(struct Map),compare);
    print(p,size);
    free(p);
    free(arr);
    return 0;
}

struct Map * collect_values(int n, int *arr){
    int i, position = 0;
    struct Map *array = calloc(n,sizeof(*array));
    for(i = 0; i < n; i++){
        scanf("%d",&arr[i]);
        array[i].value = arr[i];
        array[i].position = position;
        position++;
    }
    return array;

}

void print(struct Map * print_struct, int n){
    int i;
    for (i = 0; i < n; i++){
        printf("%d : %d\n", print_struct[i].value, 
print_struct[i].position);
    }
}

The output now is:

-3 : 3
1 : 9
3 : 2
4 : 8
4 : 1
5 : 5
5 : 4
7 : 6
25 : 0
88 : 7

How can I maintain the order of the duplicates? I spent a lot of time trying to figure out qsort() and so I'd like to keep it if possible.

EDIT I wasn't clear on the output I'm trying to get. Before sorting, the array of structs contains a value and the index of that value. So, the original array of structs looked like this:

 25 : 0
  4 : 1
  3 : 2
 -3 : 3
  5 : 4
  5 : 5
  7 : 6
 88 : 7
  4 : 8
  1 : 9

After sorting, my code printed the above. However, what I was hoping for was this:

-3 : 3
1 : 9
3 : 2
4 : 1
4 : 8
5 : 4
5 : 5
7 : 6
25 : 0
88 : 7

Where if the values in the first field are equal, then they need to be sorted by values in the second field, which will never be equal because they are the indexes.

Since the struct has a position member that represents the initial array ordering, you can easily emulate a stable sort. In the comparison function, if the two value members are equal, then return an ordering based on the position members, like this:

int compare(const void *ptr1, const void *ptr2)
{
    const struct Map *aptr = ptr1;
    const struct Map *bptr = ptr2;

    if (aptr->value == bptr->value)
        return (aptr->position > bptr->position) - (aptr->position < bptr->position);
    else
        return (aptr->value > bptr->value) - (aptr->value < bptr->value);
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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