2015-10-27 4 views
2

Как можно (эффективно/быстро) определить ранжирование (элементов) вектора в C (не C++ или использование нестандартных библиотек)? Например, ранг (ing) вектора x=(0.25, 0.54, 0.38, 0.32, 0.49, 0.06, 0.41, 0.21, 0.98, 0.23) должен быть rank(x)=(4, 9, 6, 5, 8, 1, 7, 2, 10, 3).Как вычислить ранг вектора в C?

Как следует из названия, «ранжирование» дает ранг каждого элемента вектора по отношению ко всем другим элементам вектора. Так rank(x[k])=l означает, что k й элемент x является l го наименьшим среди всех элементов в x (например, для k=6 в приведенном выше примере, l равен 1, то есть, 6-й элемент х является наименьшим). Обратите внимание, что такая функция rank() существует в нескольких других языках программирования, но я еще не видел реализацию C. Я ищу чистую реализацию C, которая работает как можно быстрее для векторов целых чисел или действительных чисел.

+0

* ха-ха *, хороший комментарий ... спасибо. Я скоро его обновлю. –

+0

Сортируйте значения, их позиция будет их * rank - 1 *, используйте ['qsort (3)'] (http://man7.org/linux/man-pages/man3/qsort.3.html) –

+0

. .. уверен, но qsort не позволяет передать второй вектор (индексов), который затем управляется соответствующим образом ... Кроме того, я не хороший программист на C, я хотел бы узнать у более опытных пользователей C здесь, как для этого. Я мог представить, что вы определяете какую-то структуру и работу над этим ... –

ответ

5

Один из способов сделать это, чтобы сопоставить данные с индексами, сортировать с помощью qsort и компаратора, который проверяет только значение и игнорирует индекс, а затем присваивает ранги в соответствии с отсортированными индексами.

Вот реализация, которая заключается в временном массиве пар, вместо использования автоматического хранилища. Это безопаснее в тех случаях, когда объем данных достаточно велик, чтобы перехватить стек.

#include <stdio.h> 
#include <stdlib.h> 

struct rank_pair { 
    double val; 
    size_t ind; 
}; 

int cmp_rank_pair(const void* a, const void* b) { 
    struct rank_pair *lhs = (struct rank_pair*)a; 
    struct rank_pair *rhs = (struct rank_pair*)b; 
    return lhs->val < rhs->val ? -1 : (lhs->val > rhs->val ? 1 : 0); 
} 

void rank(double a[], int r[], size_t n) { 
    struct rank_pair *tmp = malloc(n*sizeof(struct rank_pair)); 
    for (int i = 0 ; i != n ; i++) { 
     tmp[i].val = a[i]; 
     tmp[i].ind = i; 
    } 
    qsort(tmp, n, sizeof(struct rank_pair), cmp_rank_pair); 
    for (int i = 0 ; i != n ; i++) { 
     r[tmp[i].ind] = i+1; 
    } 
    free(tmp); 
} 

int main(void) { 
    const size_t N = 10; 
    double a[] = {0.25, 0.54, 0.38, 0.32, 0.49, 0.06, 0.41, 0.21, 0.98, 0.23}; 
    int r[N]; 
    rank(a, r, N); 
    for (int i = 0 ; i != N ; i++) { 
     printf("%d\n", r[i]); 
    } 
    return 0; 
} 

Demo.

+0

Спасибо за помощь, это именно то, что я искал. –

+0

@ rcgldr. Сортировка массива индексов по значениям немного сложнее сделать с 'qsort', потому что его компаратор - простая функция. 'qsort_r' будет делать трюк, но он не является стандартным. Статическая переменная была бы еще одним способом, но она делает решение, которое не является повторным. Массив указателей решает эту проблему, но я решил, что если я все равно создаю вспомогательный массив, я мог бы также показать, как это сделать с помощью массива пар. – dasblinkenlight

+0

@dasblinkenlight - Да, индексы будут проблемой, поэтому массив указателей будет альтернативным методом для получения ранга. Для большого массива сортировка по байтам/радиусу по байтам (4 прохода для 32-битных значений, 8 проходов для 64-битных значений) должна быть быстрее (ОП упоминается как можно быстрее). Для знаковых целых чисел или реалов бит знака должен быть переключен при использовании самого значимого байта для целей индексирования (при условии, что байт рассматривается как беззнаковый). – rcgldr

Смежные вопросы