桶排序
桶排序 (Bucketsort)或所谓的箱排序,是一个排序算法,工作的原理是将数组分到有限数量的桶子里。每个桶子再个别排序(有可能再使用别的排序算法或是以递归方式继续使用桶排序进行排序)。桶排序是鸽巢排序的一种归纳结果。当要被排序的数组内的数值是均匀分配的时候,桶排序使用线性时间(Θ(n))。但桶排序并不是 比较排序,他不受到 O(n log n) 下限的影响。
算法步骤
1.设置固定数量的空桶。
2.把数据放到对应的桶中。
3.对每个不为空的桶中数据进行排序。
4.拼接不为空的桶中数据,得到结果。
排序动画过程解释
首先,设置固定数量的空桶,在这里为了方便演示,设置桶的数量为 5 个空桶
遍历整个数列,找到最大值为 56 ,最小值为 2 ,每个桶的范围为 ( 56 - 2 + 1 )/ 5 = 11
再次遍历整个数列,按照公式 floor((数字 – 最小值) / 11) 将数字放到对应的桶中
比如,数字 7 代入公式 floor((7 – 2) / 11) = 0 放入 0 号桶
数字 12 代入公式 floor((12 – 2) / 11) = 0 放入 0 号桶
数字 56 代入公式 floor((56 – 2) / 11) = 4 放入 4 号桶
当向同一个索引的桶,第二次插入数据时,判断桶中已存在的数字与新插入数字的大小,按照左到右,从小到大的顺序插入(可以使用前面讲解的插入排序)实现
比如,插入数字 19 时, 1 号桶中已经有数字 23 ,在这里使用插入排序,让 19 排在 23 前面
遍历完整个数列后,合并非空的桶,按从左到右的顺序合并0,1,2,3,4桶。
这样就完成了 桶排序
图片转载自:https://www.jianshu.com/p/e605fe7a23b0(排序动画的代码也在这篇博客)
以下代码主体出处:https://blog.csdn.net/CSDN_dzh/article/details/85039650
main.cpp
#include"head.h"
int main()
{
int len;
int a[MaxSize];
cout << "输入随机数组元素个数" << endl;
cin >> len;
cout << endl;
cout << "生成一个元素个数为" << len << "的随机数组" << endl;
Array_generate(a, len);
cout << endl;
cout <<" 桶排序结果如下:" << endl;
Bucket_Sort(a,len);
for (int i = 0; i < len; ++i)
cout << setw(3)<<a[i];
return 0;
}
head.h`
#include<iostream>
#include<time.h>
#include <iomanip>
using namespace std;
// 桶的个数
#define BucketNumber 100
#define MaxSize 30
// 桶元素结点
typedef int ElemType;
struct Node {
ElemType key;
struct Node* next;
};
typedef Node* ptr2Node;
// 桶头结点
struct Bucket {
ptr2Node head, tail;//头尾指针
};
void Bucket_Sort(ElemType a[], int len);
void Array_generate(int a[], int len);
operation.cpp
#include"head.h"
void Array_generate(int a[], int len)
{
srand(time(NULL));
for (int i = 0;i < len;i++)
{
a[i] = rand() % 100;
}
for (int j = 0;j < len;j++)
{
cout << setw(3) << a[j];
}
cout << endl;
}
void Bucket_Sort(ElemType a[], int len) {
int i;
ptr2Node tmp, p, List = NULL;
Bucket B[BucketNumber]; //链表指针数组
for (i = 0; i < BucketNumber; i++) // 初始化每个桶为空链表
B[i].head = B[i].tail = NULL;
for (i = 0; i < len; i++) { // 将数组元素逆序存入初始链表List
tmp = (ptr2Node)malloc(sizeof(struct Node));
tmp->key = a[i];
tmp->next = List;
List = tmp;//相当于前插法,执行完毕后list指向链表第一个节点
}
// 分配
p = List;
while (p) {
// 从List中摘除元素放到桶子里(此时list中元素是无序的)
tmp = p; p = p->next;
// 插入B[tmp->key]号桶尾
if (B[tmp->key].head == NULL)
B[tmp->key].tail = tmp;
tmp->next = B[tmp->key].head;
B[tmp->key].head = tmp; //每一个桶相当与一个链表
}
// 收集
List = NULL;
for (i = BucketNumber - 1; i >= 0; i--) // 将桶子里的元素依次放入list中(此时list中元素变得有序)
if (B[i].head) { // 如果桶不为空
// 整桶插入List表头
B[i].tail->next = List;
List = B[i].head;
B[i].head = B[i].tail = NULL; // 清空桶
}
// 将List复制到a[]并释放空间
for (i = 0; i < len; i++) {
tmp = List;
List = List->next;
a[i] = tmp->key;
free(tmp);
}
}