2013-11-28 2 views
0

Я пытаюсь выполнить qsort свою запись, чтобы сортировать записи по имени в порядке возрастания. Если есть имя с тем же именем, он сортирует их оценки в порядкеC - Qsort: Сортировать имя в порядке возрастания и степени в убывающем порядке

убыванию Например: оригинальный текстовый файл

simpson bart 25 
simpson bart 35 
simpson lisa 90 
simpson bart 34 

Желаемый результат:

simpson bart 35 
simpson bart 34 
simpson bart 25 
simpson lisa 90 

Это то, что у меня есть:

int sort_nameasc_gradedes(const void *p, const void *q) 
{ 
    const record *pp = p; 
    const record *qq = q; 

    int n1 = strcmp(pp->name.first, qq->name.first); 
    int n2 = strcmp(pp->name.last, qq->name.last); 

    if (n2 == 0 && n1 != 0) { 
     return n1; 
    } else if (n2 != 0 && n1 == 0) { 
     return n2; 
    } else { 
     return (pp->score - qq->score); 
    } 
} 

Это не работает должным образом.

Заранее спасибо.

+0

Вы сортируют на три поля, но ваше описание только говорит о 2. – woolstar

+0

Хотя это вряд ли будет проблемой здесь, в общем, вы должны избегать использования ' return (pp-> score - qq-> score); 'поскольку он имеет неопределенное поведение, если значения достаточно велики, чтобы вызвать переполнение. –

ответ

1

Это должно быть то, что вы ищете.

int sort_nameasc_gradedes(const void *p, const void *q) 
{ 
    const record *pp = p; 
    const record *qq = q; 

    int n1 = strcmp(pp->name.first, qq->name.first); 
    int n2 = strcmp(pp->name.last, qq->name.last); 

    if (n1 != 0) { 
     return n1; 
    } else if (n2 != 0) { 
     return n2; 
    } else { 
     return (qq->score - pp->score); 
    } 
} 

Сначала подумайте, что вы сделали в первом и втором состояниях. Вы писали:

if (n2 == 0 && n1 != 0) { 
     return n1; 
} 

Что делать, если входы:

simpson bart 25 
taufique hussain 30 

Решение для такого вклада на основе имени, но в коде будет решено в последний else состоянии, и это сделало бы выход

taufique hussain 30 
simpson bart 25 

вместо

simpson bart 25 
taufique hussain 30 

Теперь перейдите к последнему состоянию. Если pp - simpson bart 25 и qq - simpson bart 30, что такое значение pp->score - qq->score? -5 право? Затем в отсортированном массиве следующий будет ответ:

simpson bart 25 
simpson bart 30 

Вместо нужного:

simpson bart 30 
simpson bart 25 
1

Вы хотите что-то более, как это:

int sort_nameasc_gradedes(const void *p, const void *q) 
{ 
    const record *pp = p; 
    const record *qq = q; 

    int n2 = strcmp(pp->name.last, qq->name.last); 

    if (n2 != 0) 
    { 
     return n2; 
    } 
    else 
    { 
     int n1 = strcmp(pp->name.first, qq->name.first); 

     if (n1 != 0) 
     { 
      return n1; 
     } 
     else 
     { 
      return qq->score - pp->score; 
     } 
    } 
} 
+0

Как насчет части «pp-> score - qq-> score»? Вы думали, что это правильно? Я думаю, что это должно быть «qq-> score - pp-> score» в соответствии с его требованием. – taufique

+0

Хорошо, я обновил приведенный выше пример. (Я собирался с тем, что было в коде OP, а не в требованиях) – Baldrick

2

Вам только нужно проверить полей по одному и возвращать, как только одна пара полей не равна. Поэтому сначала сравните name.last и сохраните результат strcmp; если он не равен нулю, верните его, иначе перейдите к следующему полю. Затем сравните name.first таким же образом ... вернувшись, если результат strcmp не был равен нулю. Наконец, сравните score.

Если score подписан и не будет находиться рядом с крайними значениями используемого типа данных, вы можете использовать вычитание в качестве теста, как и вы, но если без знака или если вычитание может быть завершено, вам понадобится другой тип теста.

Что-то вроде следующего может работать:

int sort_nameasc_gradedes(const void *p, const void *q) 
{ 
    const record *pp = p; 
    const record *qq = q; 
    int r; 

    if ((r = strcmp(pp->name.last, qq->name.last)) != 0) 
     return r; 
    if ((r = strcmp(pp->name.first, qq->name.first)) != 0) 
     return r; 
    /* return pp->score - qq->score; */ 
    return (pp->score < qq->score) ? 1 : ((pp->score > qq->score) ? -1 : 0); 
}