Если у меня есть структура POINT в C с координатами x и y, то какой приемлемый способ сортировать ее по первому элементу пары и то вторым, если первые равны? Я нашел много ответов на этом в C++, но не в C..может вам помочь?Сортировка вектора пар по первому элементу, а затем по второму элементу пары в C
ответ
Есть несколько ответов уже, но их реализация кажется слишком сложным,)
struct pair
{
int x;
int y;
};
static inline int safe_cmp(int x, int y)
{
return (x > y) - (x < y);
}
int lex_cmp_pairs(const void *left, const void *right)
{
const struct pair *l = left;
const struct pair *r = right;
const int cmp_x = safe_cmp(l->x, r->x);
const int cmp_y = safe_cmp(l->y, r->y);
return (cmp_x == 0) ? cmp_y : cmp_x;
}
/* example usage: */
struct pair ps[] = { {3, 3}, {2, 5}, {1, 1}, {2, 2}, {1, 2}, {3, 1} };
qsort(ps, 6, sizeof(struct pair), lex_cmp_pairs);
Обратите внимание, что вы, вероятно, захотите использовать qsort_r
(расширение GNU), если вы собираетесь сортировать в потоковой среде.
Использование вычитания для сравнения - очень плохая практика. Попробуйте это с помощью вашей функции: создайте две структурные точки, установите оба x в 0, установите a.y = INT_MAX, b.y = -1. Теперь b больше, чем a в вашей функции. установите a.y в INT_MAX - 1, и он станет меньше. Эта функция сравнения не транзитивна. Кроме того, неопределенное поведение через целочисленное нижнее значение, если все становится слишком маленьким. – Art
Вы правы (+1 к вам для определения его) - исправлено путем введения безопасного сравнения (но все же без введения ненужного разветвления). –
@PatrykObara: 'qsort_r' используется для передачи контекста функции сравнения, не прибегая к глобальной переменной, которая лучше подходит для потокового приложения, хотя вы можете использовать глобальную переменную с локальным хранилищем протектора. Здесь нет необходимости, поскольку функция сравнения использует только данные входа. – chqrlie
Просто используйте qsort и соответствующую функцию сравнения, например.
// point type
typedef struct {
int x;
int y;
} Point;
// point compare function
int compare_points(const void *p1, const void *p2)
{
const Point *pt1 = p1;
const Point *pt2 = p2;
// do primary compare on x
if (pt1->x > pt2->x)
return 1;
if (pt1->x < pt2->x)
return -1;
// pt1->x == pt2->x - do secondary compare on y...
if (pt1->y > pt2->y)
return 1;
if (pt1->y < pt2->y)
return -1;
// pt1 == pt2
return 0;
}
// sort an array of points...
qsort(points, num_points, sizeof(Point), compare_points);
Спасибо, это именно то, что я искал :) –
Нет необходимости бросать из 'void *' в более конкретный тип указателя. Кроме того, полагаться на подписанное целочисленное недоиспользование обычно не рекомендуется. – unwind
@unwind: хорошая точка на приведениях - спасибо - ответ обновлен. Я сделаю логику сравнения немного более надежной в ближайшее время ... –
вы можете либо написать уникальный компаратор-функцию
int comparator(POINT* p1, POINT* p2) {
if (p1->x < p2->x) {
return -1;
}
if (p1->x > p2->x) {
return 1;
}
if (p1->y < p2->y) {
return -1;
}
if (p1->y > p2->y) {
return 1;
}
return 0;
}
и использовать его с любым нормальным рода-реализации,
или вы могли бы определить диапазоны ваши координаты (например, 0 < x < 100) с этим предположением можно объединить обе координаты в одной целое и использовать любой Int на основе сортировки-реализации
int createCombinedCoordinate(POINT* p1) {
return P1->x * 100 + p1->y;
}
Возможно, что-то, что вы нашли для [tag: C++], можно использовать с [tag: c]. Кстати, это слишком широкий вопрос для SO. – LPs
Просто используйте 'qsort' и соответствующую функцию сравнения - см. [Man qsort] (https://linux.die.net/man/3/qsort). –
Для C++ он использовал некоторые вещи, которые не в C и Im, а не как опытный программист, чтобы «преобразовать» его из C++ в C, чтобы вы могли мне помочь? –