桶排序在操作上类似于基数排序。
这是一种
分治/划分的思想。先定义一个“桶”,把数据集合分成若干个小集合。然后桶内的排序就是用普通的排序方法,选一个最优的。
划分的方法是需一个
映射函数f(k),将所有数据分别映射到各自的桶中。
基数排序的划分就是按照每个权值位的,桶排序也可以这样,但更好的情况是有一个能
类似hash的函数,能做到更好的映射。
效率:
平均时间复杂度为线性的O(N+C),其中C=N*(logN-logM)。
其时间复杂度随着桶的数目增多而减小,最好的时间复杂度达到O(N)。极限情况是N个数据排序用N个桶,每桶只有1个数,这种情况就成了计数排序。
但是,桶排序不是原地的。由于桶是需要空间的,因此桶的数量越多,空间复杂度会增加。因此, 桶排序对数据的分布要求比较严苛。
另外,桶排序是 稳定的。
其时间复杂度随着桶的数目增多而减小,最好的时间复杂度达到O(N)。极限情况是N个数据排序用N个桶,每桶只有1个数,这种情况就成了计数排序。
但是,桶排序不是原地的。由于桶是需要空间的,因此桶的数量越多,空间复杂度会增加。因此, 桶排序对数据的分布要求比较严苛。
另外,桶排序是 稳定的。
桶排序的一种最简单的实现:以十位为标准进行划分,一共0-9十种桶。把原数据依次按划分标准放入对应的桶中。
- #include <iostream>
- #include <malloc.h>
- using namespace std;
- typedef struct node{
- int key;
- struct node* next;
- }keynode;
- void sort(int keys[], int size, int bucket_size)
- {
- keynode **bucket_table = (keynode**)malloc(sizeof(keynode*)*bucket_size);
- //init bucket
- for(int i=0;i<bucket_size;i++)
- {
- //桶内的首个结点记录着桶内的数据个数
- bucket_table[i] = (keynode*)malloc(sizeof(keynode));
- bucket_table[i]->key = 0;
- bucket_table[i]->next = NULL;
- }
- //fill bucket
- for(int j=0;j<size;j++)
- {
- keynode *node = (keynode*)malloc(sizeof(keynode));
- node->key = keys[j];
- node->next = NULL;
- //mapping function
- int index = keys[j]/10;
- //桶内采用的是插入排序法
- keynode *p = bucket_table[index];
- p->key ++;
- if(p->key == 0)
- {
- p->next = node;
- }
- else
- {
- while(p->next != NULL && p->next->key <= node->key)
- p = p->next;
- node->next = p->next;
- p->next = node;
- }
- }
- for(int b=0;b<bucket_size;b++)
- for(keynode *k=bucket_table[b]->next;k!=NULL;k=k->next)
- cout<<k->key<<" ";
- cout<<endl;
- }
- int main()
- {
- int data[] = {34,76,12,45,87,44,62,14};
- int size = sizeof(data)/sizeof(int);
- sort(data, size, 10);
- return 1;
- }

本文深入探讨了桶排序的概念,包括它与基数排序的关系、使用映射函数进行划分的方法,以及桶排序的效率特点。文章还提供了一个以十位为标准的简单桶排序实现示例,帮助读者直观理解桶排序的原理。
2211

被折叠的 条评论
为什么被折叠?



