【发布时间】:2011-04-26 14:34:11
【问题描述】:
函数定义为
void bucketsort(Array& A){
size_t numBuckets=A.size();
iarray<List> buckets(numBuckets);
//put in buckets
for(size_t i=0;i!=A.size();i++){
buckets[int(numBuckets*A[i])].push_back(A[i]);
}
////get back from buckets
//for(size_t i=0,head=0;i!=numBuckets;i++){
//size_t bucket_size=buckets[i].size();
//for(size_t j=0;j!=bucket_size;j++){
// A[head+j] = buckets[i].front();
// buckets[i].pop_front();
//}
//head += bucket_size;
//}
for(size_t i=0,head=0;i!=numBuckets;i++){
while(!buckets[i].empty()){
A[head] = buckets[i].back();
buckets[i].pop_back();
head++;
}
}
//inseration sort
insertionsort(A);
}
List 在 STL 中只是 list<double>。
数组的内容是在[0,1)中随机生成的。理论上桶排序应该比快速排序更快,因为它是O(n),但是它失败了,如下图。
我使用google-perftools 在 10000000 双数组上对其进行分析。它报告如下
似乎我不应该使用 STL 列表,但我想知道为什么? std_List_node_base_M_hook 是做什么的?我应该自己写列表类吗?
PS:实验与改进
我试过只留下放入桶的代码,这解释了大部分时间都用于建立桶。
进行了以下改进:
- 使用STL向量作为桶,为桶预留合理空间
- 使用两个辅助数组来存储构建桶的信息,从而避免使用链表,如下代码
void bucketsort2(Array& A){
size_t numBuckets = ceil(A.size()/1000);
Array B(A.size());
IndexArray head(numBuckets+1,0),offset(numBuckets,0);//extra end of head is used to avoid checking of i == A.size()-1
for(size_t i=0;i!=A.size();i++){
head[int(numBuckets*A[i])+1]++;//Note the +1
}
for(size_t i=2;i<numBuckets;i++){//head[1] is right already
head[i] += head[i-1];
}
for(size_t i=0;i<A.size();i++){
size_t bucket_num = int(numBuckets*A[i]);
B[head[bucket_num]+offset[bucket_num]] = A[i];
offset[bucket_num]++;
}
A.swap(B);
//insertionsort(A);
for(size_t i=0;i<numBuckets;i++)
quicksort_range(A,head[i],head[i]+offset[i]);
}
下图中的结果
其中行从使用列表作为存储桶的列表开始,从使用向量作为存储桶的向量开始,使用辅助数组开始 2。默认情况下最后使用插入排序,有些使用快速排序,因为存储桶大小很大。
注意“list”和“list,only put in”、“vector,reserve 8”和“vector,reserve 2”几乎重叠。
我会尝试保留足够内存的小尺寸。
【问题讨论】:
-
O-bounds 是渐近定义的。在现实生活中,总是要考虑不变的因素。
-
不应该少一些bucket吗?说
A.size() / some_const?还是一个固定的数字(10、100)? -
致 Peter G.:这几乎是真的,但在这个场景中我不这么认为。我认为尺寸足够大,最重要的是时间的增加不是 O(n) 而是大约 O (n^1.26)。
-
在这种情况下,我不会自己编写任何排序,而是使用迄今为止最快的解决方案:STL 的排序
-
+1 只是为了漂亮的图表和视觉背景:希望每个问题都遇到这么多麻烦
标签: c++ algorithm performance stl