基数排序通过改变计数子程序的一个循环给出了错误的答案

时间:2018-01-01 20:36:21

标签: c arrays sorting

这似乎是一个非常微不足道的问题,但经过深思熟虑,我仍然无法弄明白。我将这两个代码用于Radix排序。

代码1

#include <stdio.h>
#include <malloc.h>

#define BUCKET_SIZE 10

void prin(int* arr,int n)
{
    int i;
    for(i=0;i<n;i++)
        printf("%d ",*(arr+i));
    printf("\n");
}

int maxi(int* arr,int n)
{
    int i,max=0;
    for(i=0;i<n;i++)
    {
        if(arr[i]>max)
            max=arr[i];
    }
    return max;
}

int* count(int *arr,int n,int k)
{
    int* count,i,index;
    int* output;
    count=(int*)calloc(BUCKET_SIZE-1,sizeof(int));
    output=(int*)malloc(n*sizeof(int));
    for(i=0;i<n;i++)
    {
        index=(arr[i]/k)%10;
        count[index]++;
    }

    for(i=0;i<BUCKET_SIZE;i++)
        count[i]+=count[i-1];

    for(i=n-1;i>=0;i--)
    {
        index=(arr[i]/k)%10;
        output[count[index]-1]=arr[i];
        count[index]--;
    }
    return output;
}

int* radixsort(int* arr,int n)
{
    int i,max,k=1;
    max=maxi(arr,n);
    while(max>0)
    {
        max/=10;
        arr=count(arr,n,k);
        k=k*10;
    }
    return arr;
}

void main()
{
    int n,i;
    scanf("%d",&n);
    int* arr;
    arr=(int*)malloc(n*sizeof(int));
    for(i=0;i<n;i++)
        scanf("%d",(arr+i));
    arr=radixsort(arr,n);
    prin(arr,n);
}

现在,如果我更改下面的sort子例程,这段代码将不会对给定的数组进行排序,我无法解释为什么会发生这种情况,我仍在遍历整个数组,所以我仍在计算正确的索引所以我的元素应该填写在正确的位置,我应该有一个排序的数组。

代码2

仅计数函数最后一个循环已更改。

int* count(int *arr,int n,int k)
{
    int* count,i,index;
    int* output;
    count=(int*)calloc(BUCKET_SIZE-1,sizeof(int));
    output=(int*)malloc(n*sizeof(int));
    for(i=0;i<n;i++)
    {
        index=(arr[i]/k)%10;
        count[index]++;
    }

    for(i=0;i<BUCKET_SIZE;i++)
        count[i]+=count[i-1];

    for(i=0;i<n;i++)
    {
        index=(arr[i]/k)%10;
        output[count[index]-1]=arr[i];
        count[index]--;
    }
    return output;
}

当我正在计算排序时,两个函数都运行良好。有人可以指出我在哪里出错我的基数排序,或者我错过了什么,以及如何计算排序。
感谢。

2 个答案:

答案 0 :(得分:2)

count函数的最后一个循环中, 当这些行复制每个&#34; bucket&#34;的内容时, 他们写了输出的最后一个元素&#34; bucket&#34;第一, 然后是倒数第二个,以第一个元素结束:

        output[count[index]-1]=arr[i];
        count[index]--;

在你的程序的第一个版本中,因为你从数组的末尾开始访问输入数组的元素并回到开头, 你首先遇到每个桶的最后一个元素(因此把它放在输出桶的最后一个位置),然后是倒数第二个元素 (你把它放在输出中的倒数第二个位置), 等等。每个存储桶的第一个元素是最后复制的 并被复制到存储桶中的第一个位置。

在程序的第二个版本中,您将继续从后到前填充每个输出存储桶中的空格,但您可以从前到后读取输入。 这样可以将每个桶的第一个元素放在该桶中的最后一个位置,并将桶的最后一个元素放在第一个位置。 也就是说,每次运行count函数时,它都会反转每个存储桶中元素的顺序。

如果要复制从前到后读取的输入数组, 你需要从前到后填写每个输出桶 使用++count[index]代替--count[index]。 您还必须以较低的数字开始count[index]的每个条目,以便您写入正确的位置。

除此之外:您的程序执行的分配比它需要的多得多,并且不会释放任何内存,因此您可能会发生大量内存泄漏。 您可以考虑将已分配的数组传递到count,而不是总是分配新数组。

答案 1 :(得分:1)

这是一个从前到后的示例,它还使用已排序的数组替换原始数组,从而释放原始数组。另一种方法是对第二个工作数组进行一次性分配,在原始数组和工作数组之间来回进行基数排序,然后保留排序后的数组,并释放&#34;其他&#34;阵列。

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

#define BUCKET_SIZE 10

void prin(int* arr, int n)
{
    int i;
    for(i = 0; i < n; i++)
        printf("%d ", arr[i]);
    printf("\n");
}

int maxi(int* arr, int n)
{
    int i,max = 0;
    for(i = 0; i < n; i++)
    {
        if(arr[i] > max)
            max = arr[i];
    }
    return max;
}

/* replaces array with sorted array, frees original array */
void count(int** parr, int n, int k)
{
    int* count, i, index;
    int* arr = *parr;
    int* output;
    int sum, cur;
    count=calloc(BUCKET_SIZE, sizeof(int));
    output=malloc(n*sizeof(int));
    for(i = 0; i < n; i++){
        index = (arr[i]/k)%10;
        count[index]++;
    }

    sum = 0;
    for(i = 0; i < BUCKET_SIZE; i++){
        cur = count[i];
        count[i] = sum;
        sum += cur;
    }

    for(i = 0; i < n; i++){
        index = (arr[i]/k)%10;
        output[count[index]++] = arr[i];
    }
    free(arr);
    free(count);
    *parr = output;
}

void radixsort(int** parr,int n)
{
    int max,k=1;
    max=maxi(*parr,n);
    while(max>0)
    {
        max/=10;
        count(parr,n,k);
        k=k*10;
    }
}

int main()
{
    int n,i;
    int* arr;
    scanf("%d",&n);
    arr = malloc(n*sizeof(int));
    for(i = 0; i < n; i++)
        scanf("%d",&arr[i]);
    radixsort(&arr,n);
    prin(arr,n);
    free(arr);
    return 0;
}