Ошибка зацикливания сортировки по основанию

Я пытаюсь реализовать сортировку по основанию для целых чисел в C, и я сталкиваюсь с ошибкой зацикливания, которую я не могу исправить. Вот код и вывод. Я не знаю точной части, которая неверна, поэтому, пожалуйста, извините за длину сообщения.

Может ли кто-нибудь указать на мои ошибки?

#include <stdio.h>
#define BINS 16
#define GROUP 4

int main(int argc, const char *argv[])
{
    int mask = 0xf;
    int i, j;
    int list[] = {0x65c6, 0xbeb, 0x96ba, 0x9a7d};
    int buffer[GROUP];
    int *temp, *src_ptr, *dest_ptr;
    int cnt[BINS];
    int map[BINS];
    map[0] = 0;

    //init pointers to the list of unsorted numbers and temp buffer
    src_ptr = list;
    dest_ptr = buffer;

    //print unsorted list
    putchar('\n');
    printf("unsorted list: \n");
    for(i = 0; i < GROUP; i++) 
        printf("int: %d hex: 0x%x ", src_ptr[i], src_ptr[i]);
    putchar('\n');

    j = 0;
    while(j < GROUP)
    {
        //initalize the count
        for(i = 0; i < BINS; i++)
            cnt[i] = 0;
        
        //count significant digits. shifting i * group # of times
        for(i = 0; i < GROUP; i++)
            cnt[(src_ptr[i] >> i*GROUP) & mask]++;

        //initalize the map
        map[0] = 0;
        for(i = 0; i < BINS; i++)
            map[i] = 0;

        //compute the map
        for(i = 1; i < BINS; i++)
        {
            map[i] = (map[i - 1] + cnt[i - 1]);
        }

        //shift the elements in buffer[] and list[] via their pointers. 
        //shifting i * group # of times
        for(i = 0; i < GROUP; i++)
        {
            dest_ptr[map[(src_ptr[i] >> i*GROUP) & mask]++] = src_ptr[i];
        }

        //perform a swap of list[] and buffer[] via their pointers
        temp = src_ptr;
        src_ptr = dest_ptr;
        dest_ptr = src_ptr;
    
        j++;
    }

    //print list for reference
    putchar('\n');
    printf("sorted list: \n");
    for(i = 0; i < GROUP; i++) 
        printf("int: %d hex: 0x%x ", src_ptr[i], src_ptr[i]);
    putchar('\n');
    
    //print buffer for reference
    putchar('\n');
    printf("sorted buffer: \n");
    for(i = 0; i < GROUP; i++) 
        printf("int: %d hex: 0x%x ", dest_ptr[i], dest_ptr[i]);
    putchar('\n');

    return 0;
}    

вывод:

несортированный исходный список: int: 26054 hex: 0x65c6 int: 3051 hex: 0xbeb int: 38586 hex: 0x96ba int: 39549 hex: 0x9a7d

отсортированный список: int: 3051 hex: 0xbeb int: 3051 hex: 0xbeb int: 3051 hex: 0xbeb int: 3051 hex: 0xbeb

отсортированный буфер: int: 3051 hex: 0xbeb int: 3051 hex: 0xbeb int: 3051 hex: 0xbeb int: 3051 hex: 0xbeb


person Community    schedule 19.10.2013    source источник
comment
Ваш код подкачки: temp = src_ptr; src_ptr = dest_ptr; dest_ptr = src_ptr; должен ссылаться на temp дважды (и мой компилятор сказал мне, что вы делаете это неправильно, потому что он сказал ошибку: переменная ‘temp’ установлена, но не используется [-Werror=unused-but-set-variable]). Вам нужно заставить компилятор генерировать подобные предупреждения, а затем учитывать их. Код подкачки должен быть: temp = src_ptr; src_ptr = dest_ptr; dest_ptr = temp; конечно. Это необходимое изменение (при условии, что там требуется обмен); это недостаточное изменение.   -  person Jonathan Leffler    schedule 20.10.2013


Ответы (1)


В коде две проблемы:

  1. Ваш код подкачки: temp = src_ptr; src_ptr = dest_ptr; dest_ptr = src_ptr; должен дважды ссылаться на temp (и мой компилятор сказал мне, что вы делаете это неправильно, потому что он сказал "error: variable ‘temp’ set but not used [-Werror=unused-but-set-variable]"). Вам нужно заставить компилятор генерировать подобные предупреждения, а затем учитывать их. Код подкачки должен быть: temp = src_ptr; src_ptr = dest_ptr; dest_ptr = temp; конечно. Это необходимое изменение; это недостаточное изменение.

    Я ожидаю, что мой код будет правильно скомпилирован под:

    gcc -g -O3 -std=c11 -Wall -Wextra -Wmissing-prototypes -Wstrict-prototypes -Wold-style-definition -Wold-style-declaration -Werror  radixsort.c -o radixsort
    
  2. Вы неправильно использовали j при переключении передач. У вас есть:

    cnt[(src_ptr[i] >> i*GROUP) & mask]++;
    dest_ptr[map[(src_ptr[i] >> i*GROUP) & mask]++] = src_ptr[i];
    

    Тебе нужно:

    cnt[(src_ptr[i] >> j*GROUP) & mask]++;
    dest_ptr[map[(src_ptr[i] >> j*GROUP) & mask]++] = src_ptr[i];
    

Этот код правильно сортируется:

#include <stdio.h>

enum { BINS  = 16  };
enum { GROUP = 4   };
enum { MASK  = 0xF };

static void dump_array(char const *tag, size_t n, int a[n])
{
    printf("%s:\n", tag);
    for (size_t i = 0; i < n; i++)
        printf("int: %5d hex: 0x%.4X\n", a[i], a[i]);
}

int main(void)
{
    int i, j;
    int list[] = {0x65C6, 0x0BEB, 0x96BA, 0x9A7D};
    int buffer[GROUP];
    int *temp, *src_ptr, *dest_ptr;
    int cnt[BINS];
    int map[BINS];
    map[0] = 0;

    // init pointers to the list of unsorted numbers and temp buffer
    src_ptr = list;
    dest_ptr = buffer;

    // print unsorted list
    dump_array("unsorted list", GROUP, src_ptr);

    j = 0;
    while (j < GROUP)
    {
        // initalize the count
        for (i = 0; i < BINS; i++)
            cnt[i] = 0;

        // count significant digits. shifting i * group # of times
        for (i = 0; i < GROUP; i++)
            cnt[(src_ptr[i] >> j*GROUP) & MASK]++;

        // initalize the map
        map[0] = 0;
        for (i = 0; i < BINS; i++)
            map[i] = 0;

        // compute the map
        for (i = 1; i < BINS; i++)
        {
            map[i] = (map[i - 1] + cnt[i - 1]);
        }

        // shift the elements in buffer[] and list[] via their pointers.
        // shifting i * group # of times
        for (i = 0; i < GROUP; i++)
        {
            dest_ptr[map[(src_ptr[i] >> j*GROUP) & MASK]++] = src_ptr[i];
        }

        // perform a swap of list[] and buffer[] via their pointers
        temp = src_ptr;
        src_ptr = dest_ptr;
        dest_ptr = temp;
        j++;
    }

    // print list for reference
    dump_array("sorted list", GROUP, src_ptr);

    // print buffer for reference
    dump_array("sorted buffer", GROUP, dest_ptr);

    return 0;
}

Пример вывода:

unsorted list:
int: 26054 hex: 0x65C6
int:  3051 hex: 0x0BEB
int: 38586 hex: 0x96BA
int: 39549 hex: 0x9A7D
sorted list:
int:  3051 hex: 0x0BEB
int: 26054 hex: 0x65C6
int: 38586 hex: 0x96BA
int: 39549 hex: 0x9A7D
sorted buffer:
int: 26054 hex: 0x65C6
int: 38586 hex: 0x96BA
int: 39549 hex: 0x9A7D
int:  3051 hex: 0x0BEB

Обобщенный код

Код выше использует GROUP для двух разных целей. Один для длины списка, который нужно отсортировать (и распечатать). Один для количества групп цифр, по которым выполняется сортировка по основанию. Приведенный ниже код обобщается для отделения размера списка от групп счисления. Он также очищает некоторые комментарии, не исправленные в исходном коде, и т. д.

#include <stdio.h>

enum { BINS  = 16  };
enum { GROUP = 4   };
enum { MASK  = 0xF };

static void dump_array(char const *tag, size_t n, int a[n])
{
    printf("%s:\n", tag);
    for (size_t i = 0; i < n; i++)
        printf("int: %5d hex: 0x%.4X\n", a[i], a[i]);
}

int main(void)
{
    int list[] = {0x65C6, 0x0BEB, 0x96BA, 0x9A7D, 0x2917, 0x8A2C, 0xDEAD, 0xBEEF, 0xFACE };
    enum { LIST_SIZE = sizeof(list) / sizeof(list[0]) };
    int buffer[LIST_SIZE];
    int cnt[BINS];
    int map[BINS];

    // init pointers to the list of unsorted numbers and temp buffer
    int *src_ptr = list;
    int *dst_ptr = buffer;

    // print unsorted list
    dump_array("unsorted list", LIST_SIZE, src_ptr);

    for (int j = 0; j < GROUP; j++)
    {
        // initalize the count
        for (int i = 0; i < BINS; i++)
            cnt[i] = 0;

        // count significant digits. shifting j * group # of times
        for (int i = 0; i < LIST_SIZE; i++)
            cnt[(src_ptr[i] >> j*GROUP) & MASK]++;

        // initalize the map
        for (int i = 0; i < BINS; i++)
            map[i] = 0;

        // compute the map
        for (int i = 1; i < BINS; i++)
            map[i] = (map[i - 1] + cnt[i - 1]);

        // shift the elements in buffer[] and list[] via their pointers.
        // shifting j * group # of times
        for (int i = 0; i < LIST_SIZE; i++)
            dst_ptr[map[(src_ptr[i] >> j*GROUP) & MASK]++] = src_ptr[i];

        // perform a swap of list[] and buffer[] via their pointers
        int *tmp_ptr = src_ptr;
        src_ptr = dst_ptr;
        dst_ptr = tmp_ptr;
    }

    // print list for reference
    dump_array("sorted list", LIST_SIZE, src_ptr);

    // print buffer for reference
    dump_array("sorted buffer", LIST_SIZE, dst_ptr);

    return 0;
}

Этот код теперь предполагает, что все целочисленные значения находятся в диапазоне 0x0000..0xFFFF (4 полубайта по 4 бита каждый или 16-битные числа).

Пример вывода:

unsorted list:
int: 26054 hex: 0x65C6
int:  3051 hex: 0x0BEB
int: 38586 hex: 0x96BA
int: 39549 hex: 0x9A7D
int: 10519 hex: 0x2917
int: 35372 hex: 0x8A2C
int: 57005 hex: 0xDEAD
int: 48879 hex: 0xBEEF
int: 64206 hex: 0xFACE
sorted list:
int:  3051 hex: 0x0BEB
int: 10519 hex: 0x2917
int: 26054 hex: 0x65C6
int: 35372 hex: 0x8A2C
int: 38586 hex: 0x96BA
int: 39549 hex: 0x9A7D
int: 48879 hex: 0xBEEF
int: 57005 hex: 0xDEAD
int: 64206 hex: 0xFACE
sorted buffer:
int: 26054 hex: 0x65C6
int: 38586 hex: 0x96BA
int: 10519 hex: 0x2917
int: 35372 hex: 0x8A2C
int: 39549 hex: 0x9A7D
int: 64206 hex: 0xFACE
int:  3051 hex: 0x0BEB
int: 57005 hex: 0xDEAD
int: 48879 hex: 0xBEEF
person Jonathan Leffler    schedule 19.10.2013
comment
Фи! 1 минута позади вас! Будь проклят Красный Бэррон - person chux - Reinstate Monica; 20.10.2013
comment
FGITW снова наносит удар :D (Это самая быстрая пушка на Западе). - person Jonathan Leffler; 20.10.2013
comment
Спасибо. Я попробовал эту версию на своей машине, и она не сортируется правильно. но если я изменю условие завершения цикла while на 8, то есть while (j < 8). он работает правильно. какие-либо предложения? я не использую функцию dump_array. - person ; 20.10.2013
comment
Не знаю. Почему вы не используете функцию, эквивалентную функции dump_array()? Вам нравится писать один и тот же код много раз? Такие функции невероятно полезны при отладке кода. Если вы пытаетесь отсортировать более 4 элементов в списке или если вы пытаетесь отсортировать значения за пределами диапазона 0x0000..0xFFFF, ваш исходный код не будет хорошо адаптироваться. Смотрите мою ревизию. - person Jonathan Leffler; 20.10.2013
comment
я не говорил, что я против использования функции dump_array, я просто внес несколько быстрых изменений на основе вашего кода. я согласен dump_array лучше. но что касается моего зацикливающегося вопроса, то есть while (j < 8). я понял, что исходный код должен был быть (while j <= 4), потому что я думаю, что он относится к количеству цифр в сортируемом целом числе. еще раз спасибо за помощь, код теперь работает правильно. - person ; 20.10.2013