计数排序 - 效率

时间:2017-02-01 18:00:18

标签: algorithm sorting counting-sort

我在考虑计算排序以及我们如何实现它,实际上算法是如何工作的。我坚持使用一个部分,算法非常简单易懂,但其中一部分似乎没有必要。我认为人们可能会弄错,但似乎每个人都使用相同的方法,所以我在某处错了。你能解释一下吗。

以下是从geeksforgeeks

计算排序的代码
    // C Program for counting sort
#include <stdio.h>
#include <string.h>
#define RANGE 255

// The main function that sort the given string arr[] in
// alphabatical order
void countSort(char arr[])
{
    // The output character array that will have sorted arr
    char output[strlen(arr)];

    // Create a count array to store count of inidividul
    // characters and initialize count array as 0
    int count[RANGE + 1], i;
    memset(count, 0, sizeof(count));

    // Store count of each character
    for(i = 0; arr[i]; ++i)
        ++count[arr[i]];

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

    // Build the output character array
    for (i = 0; arr[i]; ++i)
    {
        output[count[arr[i]]-1] = arr[i];
        --count[arr[i]];
    }

    // Copy the output array to arr, so that arr now
    // contains sorted characters
    for (i = 0; arr[i]; ++i)
        arr[i] = output[i];
}

// Driver program to test above function
int main()
{
    char arr[] = "geeksforgeeks";//"applepp";

    countSort(arr);

    printf("Sorted character array is %s\n", arr);
    return 0;
}

很酷,但关于这一部分:

// Build the output character array
        for (i = 0; arr[i]; ++i)
        {
            output[count[arr[i]]-1] = arr[i];
            --count[arr[i]];
        }

为什么我需要这个?好的我算了一下我的数字:

假设我有阵列 - &gt; [1,3,6,3,2,4]

         INDEXES     0  1  2  3  4  5  6
  I created this -> [0, 1, 1, 2, 1, 0, 1]

比这一部分做到了这一点:

  [0, 1+0, 1+1, 2+2, 4+1, 0+5, 1+5]
  [0, 1, 2, 4, 5, 5, 6]

但是为什么?

我不能像以前一样使用我的阵列吗?这是我的想法和我的代码,请解释为什么它是错的,或者为什么其他方式更有用。

void countingSort (int *arr) {

    int countingArray[MAX_NUM] = {0};

    for (i = 0 ; i < ARRAY_SIZE ; i++)
        countingArray[arr[i]]++;

    int output_Index = 0;

    for (i = 0 ; i < MAX_NUM ; i++)
        while ( countingArray[i]-- )
            arr[output_Index++] = i;
}

2 个答案:

答案 0 :(得分:2)

对于排序整数数组的简单情况,您的代码更简单,更好。

然而,计数排序是一种通用排序算法,可以根据从要排序的项目派生的排序键进行排序,用于比较它们,而不是直接比较项目本身。对于整数数组,项和排序键可以是同一个,只需直接比较它们。

在我看来,好像geeksforgeeks代码已经从一个允许使用排序键的更通用的示例进行了改编,如下所示:

// Store count of each item
for(i = 0; arr[i]; ++i)
    ++count[key(arr[i])];

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

// Build the output array
for (i = 0; arr[i]; ++i)
{
    output[count[key(arr[i])]-1] = arr[i];
    --count[key(arr[i])];
}

其中key是一个根据项计算排序键的函数(对于整数类型,您只能返回整数本身)。在这种情况下,MAX_NUM必须替换为MAX_KEY

此方法使用额外的输出数组,因为最终结果是通过复制arr中的项而不是简单地从count中的信息生成的(仅包含每个键的项目数) 。但是,in-place counting sort是可能的。

该算法还保证stable sort(具有相同排序键的项目通过排序保留其相对顺序) - 在排序整数时这没有意义。

但是,由于他们已经删除了基于密钥排序的功能,因此没有理由感到额外的复杂性,而且您的方式更好。

他们也可能从C ++这样的语言中复制了代码,其中int cast(在使用项目索引数组时将调用它)可以重载以返回排序键,但是错误地转换为C.

答案 1 :(得分:1)

我认为您的版本是更好的方法。我怀疑编写此代码示例的人可能为其他排序算法编写了类似的代码示例 - 有许多排序算法,你需要单独的“临时空间” - 并且没有提出足够的想法进入这个。

或者,如果我们将“生成结果”与“将结果移动到位”分开,他可能觉得算法更容易解释?我不同意,如果是的话,但详细的评论清楚地说明了他的教学方法。

也就是说,您的版本存在一些小问题:

  • 您忘记声明i
  • 您应该将数组长度作为参数,而不是使用硬编码的ARRAY_SIZE。 (在代码示例中,通过使用字符串来避免此问题,因此它们可以迭代直到终止空字节。)
  • 这可能是主观的,但我认为写while ( countingArray[i]-- )更清楚,而不是for (int j = 0; j < countingArray[i]; ++j)