#c #arrays #sorting
#c #массивы #сортировка
Вопрос:
Я пытаюсь отсортировать массив, A
элементами которого являются индексы. Индексы ссылаются на другой массив, B
значение которого будет определять порядок A
. Итак, я хотел бы отсортировать A
таким образом, чтобы B[ A[i] ]
количество увеличивалось.
Например:
A = [0, 1, 4, 5, 7] B = [5, 3, 8, 2, 2, 7, 1, 6, 3, 9]
Сортировка A
будет
A' = [ 7, 4, 1, 0, 5 ]
Возможно ли это с помощью встроенной сортировки C, или мне придется написать свою собственную реализацию?
РЕДАКТИРОВАТЬ: Эти массивы являются локальными функциональными переменными.
Комментарии:
1. Были бы уродливые хаки, которые могли бы заставить это работать с qsort, но я думаю, вам лучше написать свою собственную версию..
2. @Pavan Я бы предпочел сражаться с зомби в пустыне, а не использовать мою собственную процедуру сортировки в производстве.
3. Это не уродливый взлом. Просто есть функция, которая сопоставляет значение массива с порядком сортировки. В этом случае функция может быть дополнена поиском по массиву, но вряд ли это необычное требование.
Ответ №1:
Если вы хотите использовать qsort
, лучше всего было бы повторно обернуть индексы в A и значения в B в структуру, а затем создать компаратор на основе нового массива, который содержит структуру. Например:
typedef struct
{
int index_from_A;
int value_from_B;
} index_value_wrapper;
index_value_wrapper index_wrapper_array[5];
for (int i=0; i < 5; i )
{
index_wrapper_array[i].index_from_A = A[i];
index_wrapper_array[i].value_from_B = B[A[i]];
}
int comparitor (const void* lhs, const void* rhs)
{
return (lhs.value_from_B - rhs.value_from_B);
}
Теперь вы можете запустить qsort
массив struct и оттуда извлечь нужную вам отсортированную последовательность для исходного массива A
, не прибегая к пользовательской функции сортировки.
Ответ №2:
Если он у вас есть, qsort_r предоставляет способ сделать это. Вы можете предоставить ему контекстную информацию в дополнительном параметре. Этот контекст передается функции сравнения. Вы можете получить доступ к этой дополнительной информации, чтобы извлечь желаемую информацию о сортировке.
Компилятор Microsoft имеет аналогичный: qsort_s
Ответ №3:
Я думаю, вы можете использовать qsort
и пользовательский компаратор
int comparator(const void *x, const void *y)
{
return ( b[*(int*)x] - b[*(int*)y] );
}
Комментарии:
1. Есть ли какой-либо способ передать ссылки на массив в компаратор?
2. @ajwood Я не уверен, что понимаю ваш вопрос
3. Ajwood, если ты имеешь в виду индексы массива, то нет — элементы массива перемещаются по мере выполнения сортировки
4. @cnicutar: Ваш ответ был бы идеальным… но эти массивы являются локальными переменными в функции, поэтому компаратор не может проверить значения
B
5. @ajwood: Из того, что я вижу в приведенном выше коде,
b
должен быть некоторый тип глобально доступного массива.
Ответ №4:
Создайте другой массив C типа struct { int a_value; int b_value}
, инициализируйте каждый элемент значениями каждого индекса a и значением, полученным из b. Отсортируйте это, пройдитесь по отсортированному C, скопировав a_values обратно в A.
Виола. Нет, это большая скрипка. Вуаля!
Ответ №5:
Используйте ваше правило в качестве функции сравнения с qsort (при условии, что B длиннее, чем A):
#include <stdio.h>
#include <stdlib.h>
int A[] = {0, 1, 4, 5, 7};
int B[]= {5, 3, 8, 2, 2, 7, 1, 6, 3, 9};
int my_cmp(const void *a_, const void *b_,void *arg_)
{
const int *a = a_, *b = b_;
if(B[*a] == B[*b])
return 0;
else if (B[*a] < B[*b])
return -1;
else
return 1;
}
int main(int argc,char *arga[])
{
int i;
qsort(A,sizeof A/sizeof A[0] ,sizeof A[0],my_cmp);
puts("Sorted A");
for(i = 0 ; i < sizeof A/sizeof A[0]; i ) {
printf("A[%d] : %d B[A[%d]] : %dn",i,A[i],i,B[A[i]]);
}
return 0;
}
Это дает:
$ ./a.out
Sorted A
A[0] : 4 B[A[0]] : 2
A[1] : 1 B[A[1]] : 3
A[2] : 0 B[A[2]] : 5
A[3] : 7 B[A[3]] : 6
A[4] : 5 B[A[4]] : 7
На многих платформах также доступен qsort_r (в Linux вам придется #define _GNU_SOURCE
перед включением <stdlib.h>
использовать его. Используя это, вы бы изменили функцию сравнения на, например
int my_cmp(const void *a_, const void *b_,void *arg_)
{
const int *a = a_, *b = b_, *arg = arg_;
if(arg[*a] == arg[*b])
return 0;
else if (arg[*a] < arg[*b])
return -1;
else
return 1;
}
И вызовите qsort_r как
qsort_r(A,sizeof A/sizeof A[0] ,sizeof A[0],my_cmp,B);
Комментарии:
1. Это работает хорошо, пока оно не является многопоточным. Если он не является однопоточным и ссылочные данные (B) не являются статическими, то это не сработает.
2. @Paul qsort — единственная стандартная функция сортировки в C, и она работает подобным образом, в противном случае вам придется создавать свою собственную или использовать что-то нестандартное, например qsort_r — добавлен пример для этого. Если вы не находитесь в многопоточной среде, A и B вполне могут быть локальными. Вам просто нужно установить глобальное
int *
значение для вашего массива B перед вызовом qsort3. @nos, стандартный или нет, если это не работает, вы не сможете его использовать 🙂 Работает глобальный (хотя это немного попахивает кодом) или используйте структуру-оболочку, как предлагали другие (включая меня).
4. @Нет, да, это так. Но это не было частью вашего ответа или комментария, когда я добавлял свой комментарий… qsort_r — это определенно правильный путь, если он доступен