桶排序
桶排序(Bucket Sort)是对基数排序的一个变种。在排序过程中没有用到计数数组,而是用不同的桶来暂时存储关键字。看一个示意图:
排序序列 123 234 45 111 6 128
整个过程就是在不断地分配、收集。并且每一个桶都是队列,所以收集的时候得按先进先出的原则,且从第0个桶开始收集。
在实际应用中,根据桶的创建策略,桶排序也有不同的写法。下面给出两种不同的桶创建方式。一、使用静态队列创建桶。二、使用二维数组模拟桶。
静态队列桶
- #include<iostream>
- #include<iomanip>
- using namespace std;
- //记录类型
- typedef struct record
- {
- int key;
- int next;
- }Record;
- //静态队列
- typedef struct queue
- {
- //队头
- int head;
- //队尾
- int tail;
- }StaticQueue;
- //获取最大位数
- int get_max_digit(int array[], int n)
- {
- int digit, max;
- digit = 0;
- max = array[0];
- for (int i = 1; i < n; i++)
- {
- if (array[i] > max)
- max = array[i];
- }
- while (max)
- {
- digit++;
- max /= 10;
- }
- return digit;
- }
- /*
- 收集
- 把10个桶连接起来
- */
- void collect(Record rec[], StaticQueue queue[], int& first)
- {
- //k是桶号
- int tail, k = 0;
- //先找到第一个非空的桶
- while (queue[k].head == -1)
- k++;
- //用first记录第一个记录的位置,为下次分配使用
- first = queue[k].head;
- tail = queue[k].tail;
- while (k < 9)
- {
- k++;
- while (k < 9 && queue[k].head == -1)
- k++;
- //把上一个桶的尾部和当前桶的头部连接起来
- if (queue[k].head != -1)
- {
- rec[tail].next = queue[k].head;
- tail = queue[k].tail;
- }
- }
- rec[tail].next = -1;
- }
- /*
- 分配
- 把n个记录分配到10个桶中
- r:从右数按第r位排序(r=1,2...)
- first:第一个记录的下标
- */
- void distribute(Record rec[], int r, int first, StaticQueue queue[])
- {
- //先把队列初始化
- int i, d, cur = first;
- for (i = 0; i < 10; i++)
- queue[i].head = -1;
- i = d = 1;
- while (i < r)
- {
- i++;
- d *= 10;
- }
- int k;
- //把记录分配每一个桶中
- while (cur != -1)
- {
- k = (rec[cur].key / d) % 10;
- //桶空,则当前记录是第一个
- if (queue[k].head == -1)
- queue[k].head = cur;
- else//桶非空,则当前记录连接到尾部
- rec[queue[k].tail].next = cur;
- //修改队列尾部,这一句不可忘了
- queue[k].tail = cur;
- //继续给下一个记录分桶
- cur = rec[cur].next;
- }
- }
- /*
- 重排
- first:第一个记录的下标
- */
- void arrange(Record rec[], int n, int first)
- {
- int i, j = first;
- Record temp;
- for (i = 0; i < n - 1; i++)
- {
- temp = rec[j];
- rec[j] = rec[i];
- rec[i] = temp;
- rec[i].next = j;
- j = temp.next;
- while (j <= i)
- j = rec[j].next;
- }
- }
- /*
- 基数排序
- array:待排序序列
- n:序列大小
- */
- void RadixSort(int array[], int n)
- {
- //对排序序列进行封装
- int i;
- Record *rec = new Record[n];
- for (i = 0; i < n; i++)
- {
- rec[i].key = array[i];
- rec[i].next = i + 1;
- }
- rec[n - 1].next = -1;
- /*
- 创建静态队列,每一个队列相当于一个桶
- 对于十进制数,只需10个桶即可
- */
- StaticQueue queue[10];
- //获取最大排序位数
- int digit = get_max_digit(array, n);
- int first = 0;
- for (i = 1; i <= digit; i++)
- {
- distribute(rec, i, first, queue);
- collect(rec, queue, first);
- }
- //重排
- arrange(rec, n, first);
- //回放
- for (i = 0; i < n; i++)
- array[i] = rec[i].key;
- //释放空间
- delete[]rec;
- }
- //打印
- void print(int array[], int n)
- {
- for (int i = 0; i < n; i++)
- cout << setw(6) << array[i];
- cout << endl;
- }
- int main()
- {
- cout << "******桶排序(静态队列)***by David***" << endl;
- int array[] = { 123, 234, 45, 111, 6, 128 };
- int n = sizeof(array) / sizeof(int);
- cout << "原序列" << endl;
- print(array, n);
- cout << "桶排序" << endl;
- RadixSort(array, n);
- print(array, n);
- system("pause");
- return 0;
- }
运行
代码下载:桶排序(静态队列)
二维数组桶
- #include<iostream>
- #include<iomanip>
- using namespace std;
- //最大排序个数
- const int N = 12;
- //分配
- void distribute(int array[], int n, int bucket[][N+1], int r)
- {
- int i;
- //对桶进行初始化,bucket[i][0]存放的是第i个桶中元素个数
- for (i = 0; i < 10; i++)
- bucket[i][0] = 0;
- int d;
- i = d = 1;
- while (i < r)
- {
- d *= 10;
- i++;
- }
- int k;
- for (i = 0; i < n; i++)
- {
- k = (array[i] / d) % 10;
- bucket[k][0]++;
- bucket[k][bucket[k][0]] = array[i];
- }
- }
- //收集
- void collect(int array[], int n, int bucket[][N+1])
- {
- int i, j, index;
- index = 0;
- for (i = 0; i < 10; i++)
- for (j = 1; j <= bucket[i][0]; j++)
- array[index++] = bucket[i][j];
- }
- //获取最大位数
- int get_max_digit(int array[], int n)
- {
- int digit, max;
- digit = 0;
- max = array[0];
- for (int i = 1; i < n; i++)
- {
- if (array[i] > max)
- max = array[i];
- }
- while (max)
- {
- digit++;
- max /= 10;
- }
- return digit;
- }
- //桶排序
- void BucketSort(int array[], int n)
- {
- int digit = get_max_digit(array, n);
- int i;
- int bucket[10][N+1];
- for (i = 1; i <= digit; i++)
- {
- //分配
- distribute(array, n, bucket, i);
- //收集
- collect(array, n, bucket);
- }
- }
- //打印
- void print(int *a, int n)
- {
- for (int i = 0; i < n; i++)
- cout << setw(6) << a[i];
- cout << endl;
- }
- int main()
- {
- cout << "******桶排序(二维数组)***by David***" << endl;
- int array[] = { 123, 234, 45, 111, 6, 128 };
- int n = sizeof(array) / sizeof(int);
- cout << "原序列" << endl;
- print(array, n);
- cout << "桶排序" << endl;
- BucketSort(array, n);
- print(array, n);
- system("pause");
- return 0;
- }
运行
代码下载:桶排序(二维数组)
小结
上面的两种方式都是桶排序的具体实现,总体上是分配和收集的过程。不过细节很多,需要仔细看代码。