c - 将具有重复值的整数数组部分排序到存储桶中的最快方法

标签 c arrays algorithm sorting bucket

假设我有一个大型未排序整数数组 (C/C++),它们大多重复小范围的值。例如,如果我从以下数组开始:

{ 0, 3, 3, 3, 0, 1, 1, 1, 3, 2, 2, 3, 0, 1, 1, 1, 2, 2, 2, 2, 0, 0, 1}

我想以这样的方式结束:

{ 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3}

实际上,我的数组将有数千个元素,但它们可以拥有的值的范围仍然相对较小,比如十几个可能的值。

我的问题是传统的排序算法(qsort、mergesort 等)似乎有点矫枉过正,因为它们会尽力确保每个元素都处于正确的位置。但我正在寻找一种算法,它只关心将元素分组到“桶”中,并且知道一旦实现就终止。

最佳答案

嗯,基于此:

unsorted array of integers that mostly repeat a small range of values

假设您的列表中有最大值,您可以这样做:

#include <stdio.h>
#include <string.h>

int group_vals(int *arr, size_t len, int max)
{
    int count[max+1];
    memset(count, 0, sizeof count);


    for(size_t i = 0; i < len; ++i)
        count[arr[i]]++;

    size_t index = 0;
    for(size_t i = 0; i < max + 1; ++i)
    {
        for(size_t j = 0; j < count[i]; ++j)
            arr[index++] = i;
    }
}

int main(void)
{
    int arr[] = { 0, 3, 3, 3, 0, 1, 1, 1, 3, 2, 2, 3, 0, 1, 1, 1, 2, 2, 2, 2, 0, 0, 1};

    for(size_t i = 0; i < sizeof arr / sizeof *arr; ++i)
        printf("%d, ", arr[i]);
    puts("");

    group_vals(arr, sizeof arr / sizeof *arr, 3);

    for(size_t i = 0; i < sizeof arr / sizeof *arr; ++i)
        printf("%d, ", arr[i]);
    puts("");

    return 0;
}

这里我知道3是列表的最大值。这输出

0, 3, 3, 3, 0, 1, 1, 1, 3, 2, 2, 3, 0, 1, 1, 1, 2, 2, 2, 2, 0, 0, 1, 
0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 1, 

编辑

注意:作为用户 coderredoc评论中指出,这种方法的局限性 是它仅在原始数组仅包含正数时才起作用。 改进它来处理负数并不是一个大问题:

int group_vals(int *arr, size_t len, int absmax)
{
    int count[2*absmax+1];
    memset(count, 0, sizeof count);


    for(size_t i = 0; i < len; ++i)
    {
        int v = arr[i];
        size_t idx;

        if(v == 0)
            idx = absmax;
        else
            idx = absmax + v;

        count[idx]++;
    }

    size_t index = 0;
    for(size_t i = 0; i < 2*absmax + 1; ++i)
    {
        int v;
        if(i == absmax)
            v = 0;
            v = i - absmax;

        for(size_t j = 0; j < count[i]; ++j)
        {
            arr[index++] = v;
        }
    }
}

现在函数期望数组绝对值的最大值。

此版本打印:

-2, 0, 1, 3, 2, 3, -2, -1, -1, 3, 3, 
-2, -2, -1, -1, 0, 1, 2, 3, 3, 3, 3, 

PS:我没有读John Zwinck的回答,但我们都有相同的想法,这就是 它的C版本。

关于c - 将具有重复值的整数数组部分排序到存储桶中的最快方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48738281/

相关文章:

c - 在运行时为文件分配唯一编号

c - Valgrind 大小为 1 的无效读取 (sscanf)

c - 尝试使用函数基于另一个列表创建排序列表

java - 我的数组中的位置 [1] 无法注册

algorithm - BLX-alpha交叉: what approach is the right one?

c - 在C程序中请求管理员权限?

c++ - 最小未排序数组的最小相等搜索

java - 在java中编辑对象二维数组的字段

algorithm - 文本的三向合并算法

algorithm - 这个组合优化问题是 NP 难的吗?