问题
A book I have says this:
a) Place each value of the one-dimensional array into a row of the bucket array based on the value's ones digit. For example, 97 is placed in row 7, 3 is placed in row 3, and 100 is placed in row 0. This is called a "distribution pass."
b) Loop through the bucket array row by row, and copy the values back to the original array. This is called a "gathering pass." The new order of the preceding values in the one-dimensional array is 100, 3, and 97.
c) Repeat this process for each subsequent digit position.
I am having a lot of trouble trying to understand and implement this. So far I have:
void b_sort(int sarray[], int array_size) {
const int max = array_size;
for(int i = 0; i < max; ++i)
int array[i] = sarray[i];
int bucket[10][max - 1];
}
I'm thinking that in order to sort them by ones, tens, hundreds, etc, I can use this:
for(int i = 0; i < max; ++i)
insert = (array[i] / x) % 10;
bucket[insert];
where x = 1, 10, 100, 1000, etc. I am totally lost on how to write this now.
回答1:
Here's a bucket sort based on the info in the OP question.
void b_sort(int sarray[], int array_size) {
const int max = array_size;
// use bucket[x][max] to hold the current count
int bucket[10][max+1];
// init bucket counters
for(var x=0;x<10;x++) bucket[x][max] = 0;
// main loop for each digit position
for(int digit = 1; digit <= 1000000000; digit *= 10) {
// array to bucket
for(int i = 0; i < max; i++) {
// get the digit 0-9
int dig = (sarray[i] / digit) % 10;
// add to bucket and increment count
bucket[dig][bucket[dig][max]++] = sarray[i];
}
// bucket to array
int idx = 0;
for(var x = 0; x < 10; x++) {
for(var y = 0; y < bucket[x][max]; y++) {
sarray[idx++] = bucket[x][y];
}
// reset the internal bucket counters
bucket[x][max] = 0;
}
}
}
Notes Using a 2d array for the bucket wastes a lot of space... an array of queues/lists usually makes more sense.
I don't normally program in C++ and the above code was written inside the web browser, so syntax errors may exist.
回答2:
The following code uses hex digits for a bucket sort (for BITS_PER_BUCKET=4
). Ofcourse it is meant to be instructive, not productive.
#include <assert.h>
#include <stdio.h>
#define TEST_COUNT 100
#define BITS_PER_BUCKET 4
#define BUCKET_COUNT (1 << BITS_PER_BUCKET)
#define BUCKET_MASK (BUCKET_COUNT-1)
#define PASS_COUNT (8*sizeof(int)/BITS_PER_BUCKET)
int main(int argc, char** argv) {
printf("Starting up ...");
assert((PASS_COUNT*BITS_PER_BUCKET) == (8*sizeof(int)));
printf("... OK\n");
printf("Creating repeatable very-pseudo random test data ...");
int data[TEST_COUNT];
int x=13;
int i;
for (i=0;i<TEST_COUNT;i++) {
x=(x*x+i*i) % (2*x+i);
data[i]=x;
}
printf("... OK\nData is ");
for (i=0;i<TEST_COUNT;i++) printf("%02x, ",data[i]);
printf("\n");
printf("Creating bucket arrays ...");
int buckets[BUCKET_COUNT][TEST_COUNT];
int bucketlevel[BUCKET_COUNT];
for (i=0;i<BUCKET_COUNT;i++) bucketlevel[i]=0;
printf("... OK\n");
for (i=0;i<PASS_COUNT;i++) {
int j,k,l;
printf("Running distribution pass #%d/%d ...",i,PASS_COUNT);
l=0;
for (j=0;j<TEST_COUNT;j++) {
k=(data[j]>>(BITS_PER_BUCKET*i)) & BUCKET_MASK;
buckets[k][bucketlevel[k]++]=data[j];
l|=k;
}
printf("... OK\n");
if (!l) {
printf("Only zero digits found, sort completed early\n");
break;
}
printf("Running gathering pass #%d/%d ...",i,PASS_COUNT);
l=0;
for (j=0;j<BUCKET_COUNT;j++) {
for (k=0;k<bucketlevel[j];k++) {
data[l++]=buckets[j][k];
}
bucketlevel[j]=0;
}
printf("... OK\nData is ");
for (l=0;l<TEST_COUNT;l++) printf("%02x, ",data[l]);
printf("\n");
}
}
回答3:
a rewrite of Louis's code in C++11 with STL queues.
void bucket_sort(vector<int>& arr){
queue<int> buckets[10];
for(int digit = 1; digit <= 1e9; digit *= 10){
for(int elem : arr){
buckets[(elem/digit)%10].push(elem);
}
int idx = 0;
for(queue<int>& bucket : buckets){
while(!bucket.empty()){
arr[idx++] = bucket.front();
bucket.pop();
}
}
}
}
来源:https://stackoverflow.com/questions/9317248/writing-bucket-sort-in-c