C 将具有重复值的整数数组部分排序到存储桶中的最快方法
假设我有一个大的未排序整数数组(C/C++),它大部分重复一小部分值。例如,如果我从以下数组开始:C 将具有重复值的整数数组部分排序到存储桶中的最快方法,c,arrays,algorithm,sorting,bucket,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} 实际上,我的数组将有数千个元素,但它们可以拥有的值的范围仍然相对较小,比如十几个可能的值 我的问
{ 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等)似乎有点过头了,因为它们会试图确保每个元素都处于正确的位置。但我正在寻找一种算法,该算法只关心将元素分组到“bucket”中,并且知道一旦实现就终止 使用地图:
map<int, unsigned> counts;
for (auto value: values)
++counts[value];
auto it = begin(values);
for (auto value_count : counts)
while (value_count.second--)
*it++ = value_count.first;
map计数;
用于(自动值:值)
++计数[值];
自动it=开始(值);
用于(自动值\u计数:计数)
while(值\u count.second--)
*it++=值\计数优先;
也就是说,创建值到计数的有序映射,然后使用它覆盖(或在别处创建)每个值的正确计数的整个数组
当然,如果值始终是小范围内的整数,则可以使用数组而不是映射,例如[0,3]中的值:
array<unsigned, 4> counts = {};
for (auto value: values)
++counts[value];
数组计数={};
用于(自动值:值)
++计数[值];
基于此:
大部分重复小范围值的未排序整数数组
假设列表中有一个最大值,可以执行以下操作:
#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;
}
编辑
注意:正如用户在评论中指出的,这种方法的局限性
它只在原始数组仅包含正数时才起作用。
改进it以处理负数不是什么大问题:
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;
}
}
}
PS:我没有读约翰·兹温克的答案,但我们都有相同的想法,这是
C版本, C还是C++?另外:“传统的排序算法(qsort、mergesort等)似乎有点过头了”,怎么会呢?它们跑得不够快,还是有什么问题?@BaummitAugen我可以选择在这里使用。他们跑得不够快是问题所在,我需要一些可以提前终止的东西。我不需要有人为我实现整个算法,只需要一个指向对我的情况有用的东西的正确方向的指针。那么请做出选择。不同的语言会产生不同的解决方案。传统的排序算法看起来有点过分了为什么?你有一个排序问题,他们就是这样做的。我不想对元素进行计数,而是将它们部分地排序到桶中。@Sunny724这里的计数用作排序机制。由于您有许多重复项,因此计算每个重复项的数量可以被认为是将每个值放入自己的桶中。由于每个bucket中的值相同,您只需跟踪bucket中有多少项,然后写出整个排序数组。这是一个好主意,因为它实际上在不丢失数据的情况下减少了数据占用。回答..+1,但这不是一个
C
问题吗?标签上写着so@coderredoc当Neil Butterworth删除某个点的两个标签时,约翰最初已经标注了C++和C++。然后,OP在评论(问题)中说他/她想要一个C语言的解决方案,所以我再次阅读了C标签。@JohnZwinck说我和你有相同的想法,但我写了一个C语言的解决方案。我要确保你提到你还假设所有数组元素都是非负的。这是发布的两个解决方案之间的差异。@coderredoc感谢您的反馈,我没有考虑负数,我更新了我的答案。
-2, 0, 1, 3, 2, 3, -2, -1, -1, 3, 3,
-2, -2, -1, -1, 0, 1, 2, 3, 3, 3, 3,