Сортировка структуры с разными членами

Я пытаюсь сделать проект... Проект должен читать из CSV-файла, в котором есть контакты. В контактах есть несколько полей, которые я читаю в массив структур типа contact. Пример: array.contactFirstName, массив contactLastName и т. д. Вот некоторая часть кода:

void string_InsertionSort(contact *array, int size, char *sortField){
    waitForKey();
    int i,j;
    contact key;
    if (strcmp(sortField, "First name") == 0){

        for (i = 1; i < size; i++){
            key=array[i];   
            j = i-1;                
            while ( (j >= 0) && strcmp(array[j].contactFirstName, array[j].contactFirstName) > 0){

                    array[j + 1] = array[j];
                    j--;    
                }
                array[j + 1] = key; 
            }

    }else if (strcmp(sortField, "Last name") == 0){

        for (i = 1; i < size; i++){
            key=array[i];
            j= i-1;
            while ( (j >= 0) && strcmp(array[j].contactLastName, array[j].contactLastName) > 0){
                array[j + 1] = array[j];
                j--;
            }
            array[j + 1] = key; 
        }

    }else{

        printf(" debuggggg");
    }
}

Я реализую несколько алгоритмов сортировки для сортировки контактов в нескольких различных функциях.

У меня проблема в том, что в функции string_InsertionSort я передаю массив контактов, размер массива и поле сортировки, которое я хочу заказать. Внутри функции я сравниваю поле сортировки с полями, которые у меня есть, и, если оно верное, я выполняю сортировку.

Проблема в том, что у меня 15 разных полей, поэтому мне приходится повторять весь код для разных полей. Есть другой способ? Если да, то может ли кто-нибудь привести меня в пример? (вид доступа к члену структуры извне)


person César Penha    schedule 13.05.2017    source источник
comment
Ответ, вероятно, таков: используйте указатель на функцию, чтобы передать функцию сравнения в качестве аргумента общей функции сортировки.   -  person wildplasser    schedule 13.05.2017


Ответы (1)


Обычно это решается путем передачи указателя на функцию для сравнения, как в qsort.

 void
 qsort(void *base, size_t nel, size_t width,
     int (*compar)(const void *, const void *));

int (*compar)(const void *, const void *) означает передачу указателя на функцию, который принимает два указателя void и возвращает целое число. Это позволяет использовать универсальные функции сортировки, которые могут сортировать все, что вам угодно, но вы должны написать сравнение.

В вашем коде функция сортировки по имени может выглядеть примерно так:

int cmp_contact_names( const void *_a, const void *_b ) {
    // Copy the void pointers to their correct types.
    // Easier to work with than casting multiple times.
    const contact *a = _a;
    const contact *b = _b;

    // Sort by last name, then by first name.
    return strcmp( a->contactLastName, b->contactLastName ) ||
           strcmp( a->contactFirstName, b->contactFirstName );
}

Затем это передается в qsort. Список для сортировки, количество элементов в списке, размер каждого элемента и функция сравнения, используемая для сортировки.

qsort(contacts, num_contacts, sizeof(contact*), cmp_contact_names);

Используйте шаблон сортировки вставками после этого или еще лучше после qsort_r.

Если это не упражнение, нет смысла писать собственную сортировку вставками, используйте существующую из библиотеки. Или используйте лучшую сортировку, сортировка вставками не очень эффективна. В любом случае, ручная сортировка, вероятно, не превзойдет сортировку из хорошей библиотеки, она просто добавляет больше кода для поддержки.

person Schwern    schedule 13.05.2017