отслеживание исходных индексов массива после сортировки в C

#c #arrays #sorting #qsort

#c #массивы #сортировка #qsort

Вопрос:

Скажем, у меня есть массив A[5] , состоящий из 5 элементов 5,4,1,2,3 . Теперь я сортирую эти массивы в порядке возрастания. таким образом, результирующий массив теперь будет 1,2,3,4,5 . Я использую qsort() функцию stdlib.h для сортировки этого. Вопрос в том, как я могу получить индексы исходного массива относительно моего нового массива. первоначально мои индексы были 0,1,2,3,4 для соответствующих значений 5,4,1,2,3 , а теперь индексы изменились на 2,3,4,1,0. Как я могу эффективно получить эти индексы в C? Заранее благодарю вас (пожалуйста, напишите код, если это возможно)

Комментарии:

1. Вместо сортировки самого массива создайте массив индексов и отсортируйте это с помощью функции сравнения, которая сравнивает индексированные значения.

2. не могли бы вы привести пример? Мне это не совсем понятно

3. Ну, вы хотите comp(i, j) вернуть a[i] < a[j] (а не i < j ) и т.д.

4. можете ли вы помочь мне с этим? Я поясню на примере. 5,4,1,2,3 был моим несортированным массивом. Теперь мне дан индекс. Давайте возьмем 3-й индекс, значение в 3-м индексе равно 2. Теперь мне нужно найти индекс со значением 2 после сортировки массива. Как мне это сделать?

Ответ №1:

Существует также следующий метод при ограниченных условиях.

 #include <stdio.h>

int main(void){
    int data[] ={ 5,4,1,2,3 }; //Without duplication, The number of limited range.
    int size = sizeof(data)/sizeof(*data);
    int keys[size];
    int i;

    printf("data :n");
    for(i=0;i<size;i  ){
        printf("%d ",data[i]);
    }
    for(i=0;i<size;i  ){
        keys[data[i]-1]=i;
    }

    printf("nndatatindexn");
    for(i=0;i<size;i  ){
        printf("%dt%dn", data[keys[i]], keys[i]);
    }
    return 0;
}
/* result sample
data :
5 4 1 2 3

data    index
1       2
2       3
3       4
4       1
5       0
*/
  

Как отсортировать массив по индексу @Kerrek, предлагается следующим образом.

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

int *array;

int cmp(const void *a, const void *b){
    int ia = *(int *)a;
    int ib = *(int *)b;
    return array[ia] < array[ib] ? -1 : array[ia] > array[ib];
}

int main(void){
    int data[] ={ 5,4,1,2,3 };
    int size = sizeof(data)/sizeof(*data);
    int index[size];//use malloc to large size array
    int i;

    for(i=0;i<size;i  ){
        index[i] = i;
    }
    array = data;
    qsort(index, size, sizeof(*index), cmp);
    printf("nndatatindexn");
    for(i=0;i<size;i  ){
        printf("%dt%dn", data[index[i]], index[i]);
    }
    return 0;
}
  

Комментарии:

1. Каков предел? Могу ли я использовать этот метод для 10 ^ 5 элементов в массиве? И максимальный размер моего целого числа равен 10 ^ 9.

2. @user3807678 Я думаю, что это может быть способом Керрека, таким как рекомендации в целом. Я добавил пример кода.

3. Большое спасибо за код! Мне был предоставлен старый индекс значения, я должен найти новый индекс значения в отсортированном массиве. Как мы можем это сделать в том же примере?

4. @user3807678 Я не понимаю, о чем ты говоришь. вы хотите i ?

5. Я поясню на примере. 5,4,1,2,3 был моим несортированным массивом. Теперь мне дан индекс. Давайте возьмем 3-й индекс, значение в 3-м индексе равно 2. Теперь мне нужно найти индекс со значением 2 после сортировки массива. Как мне это сделать?

Ответ №2:

Возьмем 2D-массив. Сохраняйте числа в первом столбце, а затем соответствующие индексы во втором столбце. Вы можете написать свою функцию сравнения как:

 int compare ( const void *pa, const void *pb ) 
{
    const int *a = pa;
    const int *b = pb;
    if(a[0] == b[0])
        return a[1] - b[1];
    else
        return a[0] - b[0];
}  
  

Вызов qsort должен быть:

 qsort(array, n, sizeof array[0], compare);  // n is representing rows  
  

Смотрите Live Demo

Ответ №3:

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

 _Thread_local uint8_t *array_to_order;
_Thread_local size_t elem_size_to_order;
_Thread_local int (*cmp_for_ordering)(const void *, const void *);

int cmp_array_entry(const size_t *a, const size_t *b)
{
    return cmp_for_ordering(amp;array_to_order[*a * elem_size_to_order], amp;array_to_order[*b * elem_size_to_order]);
}

size_t *make_order_index_array(void *array, size_t *order, size_t elem_count, size_t elem_size, int (*cmp)(const void *, const void *))
{
    // If order is provided by the caller it should have suitable contents, such as when updating an order

    // Initialise the order array if not already provided
    if (order == NULL)
    {
        order = calloc(elem_count, sizeof(size_t));

        // Initialise the order array to the unsorted indices
        for (size_t i=0; i < elem_count; i  )
            order[i] = i;
    }

    // Globals used by the comparison function to order the array
    array_to_order = array;
    elem_size_to_order = elem_size;
    cmp_for_ordering = cmp;

    // Order the order array
    qsort(order, elem_count, sizeof(size_t), cmp_array_entry);

    return order;
}
  

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

 #if defined(_MSC_VER) amp;amp; !defined(_Thread_local)
    #define _Thread_local __declspec(thread)
#endif

#if !(defined(__STDC_VERSION__) amp;amp; (__STDC_VERSION__ >= 201102L)) amp;amp; !defined(_Thread_local)
    #if defined(__GNUC__) || defined(__INTEL_COMPILER) || defined(__SUNPRO_CC) || defined(__IBMCPP__)
        #define _Thread_local __thread
    #endif
#elif defined(__GNUC__) amp;amp; defined(__GNUC_MINOR__) amp;amp; (((__GNUC__ << 8) | __GNUC_MINOR__) < ((4 << 8) | 9))
    #define _Thread_local __thread
#endif
  

Ответ №4:

 #include <limits.h>
#include <stdio.h>
#define SIZE 5
int* sortArrayNKeepIndices(int arr[], int arrSize){
    static int indexArr[SIZE];
    int arr2[arrSize];
    for (int i = 0; i < arrSize; i  ) {
        indexArr[i] = 0;
        arr2[i] = arr[i];
    }
    int min = 0, temp = 0;

    for (int i = 0; i < arrSize ; i  )
    {
        min = i;  // record the position of the smallest
        for (int j = i   1; j < arrSize; j  )
        {
            // update min when finding a smaller element
            if (arr[j] < arr[min])
                min = j;
        }
        // put the smallest element at position i
        temp = arr[i];
        arr[i] = arr[min];
        arr[min] = temp;
    } // array sorting ends here
    int ctr = 0;
    while ( ctr < arrSize) {
        min = 0;  // restart from first element
        for (int j = 0; j < arrSize; j  )
        {
            if (arr2[j] == INT_MAX) continue; // ignore already marked as minimum indices
            // update min when finding a smaller element
            if (arr2[j] < arr2[min])
                min = j;
        }
        indexArr[ctr] = min; // updating indexArr with the index of the next minimum
        arr2[min] = INT_MAX; // marking minimum element to be ignored next time
        ctr  ;
    } //keeping track of previous indices of the array elements ends here
    return indexArr;
} // function sortArrayKeepIndices ends here
int main () {
    int arr[SIZE] = {16, 15, 12, 10, 13};
    int* ptr = sortArrayNKeepIndices(arr, SIZE);
    for (int dex = 0; dex < SIZE; dex  ){
        printf("%d (%d, %d)t", arr[dex], * (ptr   dex), dex);}
}
  

// вывод будет 10 (3, 0) 12 (2, 1) 13 (4, 2) 15 (1, 3) 16 (0, 4)
// элемент (старый индекс, новый индекс)