Да, есть альтернатива.В стандартной библиотеке C уже есть функция с именем qsort
(которая, вероятно, является аббревиатурой быстрой сортировки, но это может быть и любой другой алгоритм сортировки).Чтобы использовать эту функцию, вы передаете ей массив, количество элементов в массиве, размер каждого элемента и функцию сравнения.
Вам просто нужно написать функцию сравнения для каждого типа данных, как показанов примере на этой странице.
Если вы хотите объединить 4 функции сравнения в одну функцию, вам нужно передать некоторую контекстную информацию в функцию сравнения.В этом случае вы не можете больше использовать qsort
, но должны использовать qsort_s
.Тогда ваша функция сравнения может выглядеть так:
#define compare(a, b) (((a) > (b)) - ((b) > (a)))
#define compare_ptr(type) (compare(*(type *)(p1), *(type *)(p2)))
static int compare_by_type(const void *p1, const void *p2, void *ctx) {
int type = *(int *) ctx;
switch (type) {
case 1: return compare_ptr(short);
case 2: return compare_ptr(int);
case 3: return compare_ptr(float);
case 4: return compare_ptr(double);
default: return 0;
}
}
#undef compare
#undef compare_ptr
int main(void) {
int iarray[] = {1, 6, 4, 9, 55, 999, -33333};
int sort_type = 1;
qsort_s(iarray, 7, sizeof(int), compare_by_type, &type);
}
Это довольно продвинутый материал:
- передача указателей на функции вокруг
- выполнение указателей с указателями на произвольные типы
- с использованием макросов, которые принимают имена типов в качестве макропараметра
- , смешивающие логическую арифметику с целочисленной арифметикой
Но, в конце концов, добавить дополнительные типы в список тривиально, пока они поддерживают оператор <
.
Обратите внимание, что float
и double
даже не относятся к этой категории, поскольку их оператор <
возвращает false
, как только один изчисло - NaN
, что означает не число, и является результатом выражений, таких как 0.0 / 0.0
.Как только у вас есть такое значение в массиве, поведение становится неопределенным.Функция сортировки может даже застрять в бесконечном цикле.Чтобы исправить это, измените определение макроса compare
:
#define compare(a, b) (((a) > (b)) - !((b) <= (a)))
Теперь это выглядит еще сложнее, но работает для NaN
.Например:
compare(NaN, 5)
= (NaN > 5) - !(5 <= NaN)
= false - !(5 <= NaN)
= false - !(false)
= false - true
= 0 - 1
= -1
Это означает, что NaN будет отсортирован в начало массива.
compare(NaN, NaN)
= (NaN > NaN) - !(NaN <= NaN)
= false - true
= -1
Черт.Сравнение двух NaN должно было привести к 0, что означает, что они равны.Таким образом, в этом особом случае необходимо внести поправку:
#define compare(a, b) (((a) > (b)) - ((b) > (a)) - ((a) != (a) || (b) != (b)))
Поскольку NaN
- единственное значение, которое сравнивает неравномерно с самим собой, этот дополнительный код не влияет на целочисленную арифметику и должен быть оптимизирован путемкомпилятор.