I am trying to find out how (using a quicksort algorithm) to sort an struct array by 2 criterias. For example say I had a struct of:
struct employee{
char
I think you should sort your array by gender first, one for male, one for female. Then use the quicksort function to sort within those two arrays.
You can use strcmp to sort the original array into two arrays: one for male, one for female.
Just use the built-in qsort
, and pass it a comparator function that compares gender first, and consults ID number only in case of "ties" in the first comparison.
It's not hard. You just need a function (or block of code seeing you want it "hard coded") to compare your structs. In the sample code you've given you are comparing the current object using arr[l].id <= arr[p].id
. That is you are only considering id to work out where your element fits. You just need to compare using the other fields at this point. It would be much tidier with a function (I gave you such a function in your earlier question).
You are also only shifting the id fields when you swap - leaving the name and gender unchanged in your data items. You should move the whole struct.
int compare_employee (struct employee * a, struct employee * b) {
int diff = strcmp(a->gender, b->gender);
if (diff) // if gender different
return -diff; // sort descending, please double check this and reverse in case I am wrong
return a->id - b->id; // else sort by id
}
Will output a negative number if a < b
, positive if a > b
, zero if they are equal.
Use it eigther in your own quicksort or as a qsort
comparator.
You can certainly inline the comparison function, and a swapper for that matter. This code below is pretty basic and relies on valid pointers, but you'l get the idea. I also took the liberty of trimming down your quicksort, fixing what was off along the way (I hope).
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// employee record
struct employee
{
char gender[12];
char name[12];
int id;
};
// swap employee records
void swap_employee(struct employee *left, struct employee *right)
{
struct employee tmp = *right;
*right = *left;
*left = tmp;
}
// compare employee records
int compare_employee(const struct employee* left,
const struct employee* right)
{
int gender = strcmp(left->gender, right->gender);
return (gender ? gender : (left->id - right->id));
}
// quicksort for employees
static void quicksort_(struct employee *arr, int left, int right)
{
struct employee p = arr[(left+right)/2]; // as good as any
int l = left, r = right; // movable indicies
while (l <= r)
{
while (compare_employee(arr+l, &p) < 0)
++l;
while (compare_employee(arr+r, &p) > 0)
--r;
if (l <= r)
{
swap_employee(arr+l, arr+r);
++l; --r;
}
}
if (left < r)
quicksort_(arr, left, r);
if (l < right)
quicksort_(arr, l, right);
}
// exposed API
void quicksort(struct employee *arr, int count)
{
if (arr && (count>0))
quicksort_(arr, 0, count-1);
}
/* sample usage */
int main(int argc, char *argv[])
{
struct employee arr[]=
{
{"male","Matt",1234},
{"female","Jessica",2345},
{"male","Josh",1235},
{"female","Betsy",2344},
{"male","Roger",1233}
};
quicksort(arr, sizeof(arr)/sizeof(arr[0]));
for (int i=0;i<sizeof(arr)/sizeof(arr[0]);++i)
printf("%s, %s, %d\n", arr[i].gender,arr[i].name, arr[i].id);
return EXIT_SUCCESS;
}
Results
female, Betsy, 2344
female, Jessica, 2345
male, Roger, 1233
male, Matt, 1234
male, Josh, 1235