对负值使用计数排序?(降序排列)

Sup*_*can 2 c# sorting counting-sort

我有一个计数排序,它应该为x > 0,它按降序对我的数组进行排序。然而,在考虑负数时,我的实现逻辑会崩溃,因为我正在处理辅助数组中的负索引values。我想以某种方式使用uint但我对它不是很熟悉。

我怎样才能克服这个使用计数排序

static void countingSort(int[] arr)    
{
    int i, j, max = -1; // I think it falls apart about here 
    int[] values;

    for (i = 0; i < arr.Length; i++)
        if (arr[i] > max) max = arr[i];

    values = new int[max + 1];

    //Here it reaches for a negative index when i = 2,looking for -6.            
    for (i = 0; i < arr.Max(); i++)
        values[arr[i]]++; 

    i = 0; j = values.Length - 1;
    while (i < arr.Length)
    {
        if (values[j] > 0)
        {
            values[j]--;
            arr[i] = j;
            i++;
        }
        else j--;
    }
}
Run Code Online (Sandbox Code Playgroud)

我知道我的问题是帮助数组的索引。而且由于我不想继续使用负索引创建数组,我有点难住了。

您甚至可以在不将整个类实现为索引器的情况下在 c# 中做到这一点吗?我知道你可以在 C 中做到这一点,它的定义很好:

来自 C99 §6.5.2.1/2:下标运算符 [] 的定义是 E1[E2] 与 (*((E1)+(E2))) 相同。

我的测试数组是 { 8, 5, -6, 7, 1, 4 }

我的预期输出是 { 8, 7, 5, 4, 1, -6 }

Pet*_*iho 6

在您的示例中,您已经在扫描输入数组以查找最大值。缺少的是您还没有扫描输入数组以找到最小值。如果添加它,然后知道最小值,则可以偏移数组索引的范围以允许负数(如果仅处理正数,甚至可能减小数组的大小)。

那看起来像这样:

static void Sort(int[] array)
{
    int min = int.MaxValue, max = int.MinValue;

    for (int i = 0; i < array.Length; i++)
    {
        if (array[i] < min)
        {
            min = array[i];
        }

        if (array[i] > max)
        {
            max = array[i];
        }
    }

    int[] counts = new int[max - min + 1];

    for (int i = 0; i < array.Length; i++)
    {
        counts[array[i] - min]++;
    }

    int k = 0;

    for (int j = max; j >= min; j--)
    {
        for (int i = 0; i < counts[j - min]; i++)
        {
            array[k++] = j;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

请注意,这种排序的一个显着缺点是需要维护一个连续数组,其中包含输入中所有可能的值。即使输入数组中只有两个元素,如果它们的值是int.MinValueand int.MaxValue,您也需要一个 16GB 大的中间数组(暂时忽略使用整数数学计算数组长度时会遇到麻烦)只是int)。

另一种方法是使用字典来存储计数。这允许您避免为不存在的输入值分配内存。它也恰好允许你只需要扫描一次输入,而不是两次(但这样做的代价是你正在处理一个数据结构,当你添加新元素时,它必须重新分配它的底层存储,所以算法复杂度并没有真正降低多少)。

那看起来像这样:

static void Sort(int[] array)
{
    int min = int.MaxValue, max = int.MinValue;

    Dictionary<int, int> counts = new Dictionary<int, int>();

    for (int i = 0; i < array.Length; i++)
    {
        if (array[i] < min)
        {
            min = array[i];
        }

        if (array[i] > max)
        {
            max = array[i];
        }

        int count;

        // If the key is not present, count will get the default value for int, i.e. 0
        counts.TryGetValue(array[i], out count);
        counts[array[i]] = count + 1;
    }

    int k = 0;

    for (int j = max; j >= min; j--)
    {
        int count;

        if (counts.TryGetValue(j, out count))
        {
            for (int i = 0; i < count; i++)
            {
                array[k++] = j;
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)