我有一个至少有2000个随机唯一整数的数组,每个整数的范围为0< n< 65000
我必须对它进行排序,然后获取数组中随机值的索引。这些操作中的每一个都必须尽可能快。对于搜索二进制搜索似乎很好。
对于排序我使用了标准的快速排序算法(qsort),但我被告知,使用给定的信息,标准排序算法将不是最有效的。所以问题很简单 - 使用给定的信息对数组进行排序的最有效方法是什么?对此完全感到困惑。
答案 0 :(得分:7)
我不知道为什么那个告诉你的人会如此反对神秘,但确实qsort
并不是用C ++对整数(或通常是任何东西)进行排序的最有效方法。请改用std::sort
。
可能你可以针对规定的特殊情况(0-65k范围内的2000个不同的随机整数)改进你的实现std::sort
,但是你不太可能做好多了,几乎肯定不值得努力。我能想到的事情可能有所帮助:
使用快速排序,但使用不同的数据透视表选择或不同的阈值,可以根据sort
的实现方式切换到插入排序。这基本上是修补。
使用某种并行排序。 2000元素是如此之小,我怀疑创建额外线程的时间将立即杀死任何性能改进的希望。但是如果你做了很多种,那么你就可以平均在所有这些线程中创建线程的成本,并且只担心线程同步的开销而不是创建线程。
也就是说,如果你生成并对数组进行排序,然后在其中只查找一个值,然后生成一个新数组,那么每次排序整个数组都会浪费精力。您可以在数组中运行,计算小于目标值的值的数量:此计数是它将具有的索引。使用std::count_if
或短循环。
每项操作都必须尽可能快。
这不是合法的软件工程标准。经过足够数月或数年的工程努力,几乎任何事情都可以变得更快 - 没有任何复杂的事情可以“尽可能快”,即使它是你也无法证明它不会更快,并且即使你可以在某处或很快发明新的硬件,其中最快的解决方案是不同的和更好的。除非你打算一生都在完成这项任务并最终失败,否则要获得一个更现实的目标; - )
答案 1 :(得分:1)
对于排序均匀分布的随机整数Radix Sort通常是最快的算法,它可以比快速排序快2倍或更多。但是,可能很难找到优化的实现,快速排序更加普遍。基数排序和快速排序都可能具有非常差的最坏情况性能,如O(N ^ 2),因此如果最坏情况下的性能很重要,则必须查看其他地方,也许您选择introsort,这类似于标准: :用C ++排序。
对于数组查找,哈希表是目前禁用的方法。如果您不想要其他数据结构,可以随时选择binary search。如果您具有均匀分布的数字interpolation search可能是最有效的方法(最佳平均性能)。
答案 2 :(得分:0)
标准排序算法以及几乎所有标准排序算法都是非常好的通用解决方案。如果您对数据一无所知,如果它真的由“随机唯一整数”组成,那么您可以选择其中一个标准实现。
另一方面,大多数编程问题出现在一个讲述数据的上下文中,而附加信息通常会导致更有效的问题特定解决方案。
例如,您的数据是一次显示还是以块状显示?如果它是零碎的,您可以通过交叉增量排序(例如双枢轴快速排序)和数据采集来加快速度。
答案 3 :(得分:0)
由于您的数字域很小,您可以创建一个包含65000个条目的数组,将您看到的数字的索引设置为1,然后将所有设置为1的数字作为已排序的数组。这将完全是67000(假设数组的初始化是无成本的)迭代。
由于列表包含2000个条目,O(n*log(n))
可能会更快。我可以想到没有其他的O(n)算法,所以我想你最好使用通用算法。
答案 4 :(得分:0)
Quicksort的复杂性为O(n*log(n))
,在您的情况下为n = 2000
。 log(2000) = 10.965784
。
您可以使用以下算法之一对O(n)
进行排序:
我已将std::sort()
与N = 100000000
的计数排序进行了比较:
#include <iostream>
#include <vector>
#include <algorithm>
#include <time.h>
#include <string.h>
using namespace std;
void countSort(int t[], int o[], int c[], int n, int k)
{
// Count the number of each number in t[] and place that value into c[].
for (int i = 0; i < n; i++)
c[t[i]]++;
// Place the number of elements less than each value at i into c[].
for (int i = 1; i <= k; i++)
c[i] += c[i - 1];
// Place each element of t[] into its correct sorted position in the output o[].
for (int i = n - 1; i >= 0; i--)
{
o[c[t[i]] - 1] = t[i];
--c[t[i]];
}
}
void init(int t[], int n, int max)
{
for (int i = 0; i < n; i++)
t[i] = rand() % max;
}
double getSeconds(clock_t start)
{
return (double) (clock() - start) / CLOCKS_PER_SEC;
}
void print(int t[], int n)
{
for (int i = 0; i < n; i++)
cout << t[i] << " ";
cout << endl;
}
int main()
{
const int N = 100000000;
const int MAX = 65000;
int *t = new int[N];
init(t, N, MAX);
//print(t, N);
clock_t start = clock();
sort(t, t + N);
cout << "std::sort " << getSeconds(start) << endl;
//print(t, N);
init(t, N, MAX);
//print(t, N);
// o[] holds the sorted output.
int *o = new int[N];
// c[] holds counters.
int *c = new int[MAX + 1];
// Set counters to zero.
memset(c, 0, (MAX + 1) * sizeof(*c));
start = clock();
countSort(t, o, c, N, MAX);
cout << "countSort " << getSeconds(start) << endl;
//print(o, N);
delete[] t;
delete[] o;
delete[] c;
return 0;
}
结果(以秒为单位):
std::sort 28.6
countSort 10.97
对于N = 2000
,两种算法都会给0
次。