基数排序不排序“一些”数字?

时间:2017-12-04 07:17:59

标签: c arrays algorithm sorting radix-sort

我正在尝试实施Radix sort,从我所学到的只是它首先比较一个数字,正确顺序的地方,十分之一等等,所以第四。

我试图实现它,但没有得到满意的结果,我在这里做错了什么? 这是我的代码:

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

struct heap {
    int data;
};

int main()
{
    int arr[18] = {545, 934, 829, 883, 842, 957, 241, 856, 878, 101, 555, 20, 964, 529, 156, 161, 566, 820};
    int i;

    struct heap *heaparr = malloc(sizeof(struct heap) * 18);

    for(i=0; i<18; i++) {
        heaparr[i].data = arr[i];
    }

    int k = 0, temp, div = 1;
    int ind = 0;

    while(div<=100 ){
        k=0;
        ind = 0;
        while(k<10) {
            for(i=0; i<18; i++) {
                if ((heaparr[i].data/div)% 10 == k) {
                    temp = heaparr[ind].data;
                    heaparr[ind].data = heaparr[i].data;
                    heaparr[i].data = temp;
                    ind++;
                }
            }
            k = k+1;
        }
        div = div*10;
    }

    printf("\n");
    free(heaparr);
    return 0;
}

它给了我结果

20 101 156 161 241 545 555 566 529 842 856 820 829 878 883 957 934 964

应该是。

20 101 156 161 241 529 545 555 566 820 829 842 856 878 883 934 964 957 

2 个答案:

答案 0 :(得分:3)

基数排序要求中间排序稳定,您可以在Wikipedia中阅读。这是一张很好的图片,解释了稳定性:

enter image description here

&#34;对扑克牌进行稳定排序的一个例子。当卡按排名按稳定排序排序时,两个5s必须在它们最初所在的排序输出中保持相同的顺序。当它们以非稳定排序排序时,5s可能最终排在相反的位置在排序的输出中排序。&#34;

所以,在你的代码中,当你交换两个元素时,你不能确保从开始时采取的元素保持稳定性,并且要回到最后,这打破了基数排序的要求,从而产生不良影响。

GeeksforGeeks的启发,我将您的代码转换为使用Counting sort(对于中间排序步骤而言是稳定的):

#include <stdio.h>
#include <stdlib.h>
#include <math.h>       /* pow */

struct heap {
    int data;
};

void print(struct heap* heaparr)
{
    for(int i = 0; i < 18; i++)
        printf("%d ", heaparr[i].data);
    printf("\n");

}

// A function to do counting sort of arr[] according to
// the digit represented by exp.
struct heap* countSort(struct heap* heaparr, int n, int exp)
{
    int output[n]; // output array
    int i, count[10] = {0};

    // Store count of occurrences in count[]
    for (i = 0; i < n; i++)
        count[ (heaparr[i].data/exp)%10 ]++;

    // Change count[i] so that count[i] now contains actual
    //  position of this digit in output[]
    for (i = 1; i < 10; i++)
        count[i] += count[i - 1];

    // Build the output array
    for (i = n - 1; i >= 0; i--)
    {
        output[count[ (heaparr[i].data/exp)%10 ] - 1] = heaparr[i].data;
        count[ (heaparr[i].data/exp)%10 ]--;
    }

    // Copy the output array to arr[], so that arr[] now
    // contains sorted numbers according to current digit
    for (i = 0; i < n; i++)
        heaparr[i].data = output[i];
    return heaparr;
}

int main()
{
    int arr[18] = {545, 934, 829, 883, 842, 957, 241, 856, 878, 101, 555, 20, 964, 529, 156, 161, 566, 820};
    int i;

    struct heap *heaparr = malloc(sizeof(struct heap) * 18);

    for(i=0; i<18; i++) {
        heaparr[i].data = arr[i];
    }

    int k = 0, div = 1;

    while(div<=100 ){
        k=0;
        while(k<10) {
            for(i=0; i<18; i++) {
                countSort(heaparr, 18, (int)pow(10, heaparr[i].data/div% 10));
            }
            k = k+1;
        }
        div = div*10;
    }
    print(heaparr);
    free(heaparr);
    return 0;
}

给出:

  

20 101 156 161 241 529 545 555 566 820 829 842 856 878 883 934 957 964

但是,这应该只是一个让你入门的例子。

答案 1 :(得分:3)

@gsamaras打败了我,但这是一个小得多的最小例子。

Start with:
  52, 93, 84, 54, 24

1s位置的整个传递将值保留在相同的位置。 现在看一下处理10s地点时的交换操作:

10s, k=0
10s, k=1
10s, k=2
  24, 93, 84, 54, 52 //The first swap mis-orders the "50s"
   ^---------------^
10s, k=3
10s, k=4
10s, k=5
  24, 54, 84, 93, 52
       ^-------^
  24, 54, 52, 93, 84 //Hence they stay out-of-order when they're moved up
           ^-------^
10s, k=6
10s, k=7
10s, k=8
  24, 54, 52, 84, 93
               ^---^
10s, k=9

考虑将元素向右移动以产生空间,而不是交换,或者对每个小数位的处理进行异地处理(即,在两个缓冲区之间交替)。