排序算法__桶排序
一、介绍
桶排序是将待排序集合中处于同一个值域的元素存入同一个桶中,也就是根据元素值特性将集合拆分为多个区域,则拆分后形成的多个桶,从值域上看是处于有序状态的。对每个桶中元素进行排序,则所有桶中元素构成的集合是已排序的。桶排序更是对计数排序的改进,计数排序申请的额外空间跨度从最小元素值到最大元素值,若待排序集合中元素不是依次递增的,则必然有空间浪费情况。桶排序则是弱化了这种浪费情况,将最小值到最大值之间的每一个位置申请空间,更新为最小值到最大值之间每一个固定区域申请空间,尽量减少了元素值大小不连续情况下的空间浪费情况。
二、C++实现
#include<iostream>
using namespace std;
const int N=1000;
struct Node{
int data;
Node *next;
Node(int data=0)
{
this->data=data;
this->next=NULL;
}
};
//hash函数
int hash(int value)
{
return value/10;//简单地将数整除10
}
//删除结点
void deleteNode(Node *node)
{
if(!node)
{
if(!node->next) deleteNode(node->next);//如果node结点还有下一个结点就递归删除
delete(node);//删除此结点
}
}
//桶排序
void bucketSort(int array[],int n,int bucketNum/*桶的数目*/)
{
int ans[N];//排序后的结果
Node *bucket[N];
for(int i=0;i<bucketNum;i++)
{
bucket[i]=new Node();
if(!bucket[i])
{
cout<<"内存分配失败!"<<endl;
exit(-1);
}
}
for(int i=0;i<n;i++)
{
int pos=hash(array[i]);//判断此数应该放在哪个桶中
Node *p=bucket[pos];
Node *node=new Node(array[i]);
if(!node)
{
cout<<"内存分配失败!"<<endl;
exit(-1);
}
if(!p->next)//没有元素
p->next=node;
else
{
//寻找node应该插入的位置
while(p->next&&p->next->data<node->data) p=p->next;
node->next=p->next;
p->next=node;
}
}
for(int i=0,j=0;i<bucketNum;i++)//遍历各个桶
{
Node *p=bucket[i]->next;//获得桶的入口地址
while(p)
{
array[j++]=p->data;
p=p->next;
}
}
for(int i=0;i<bucketNum;i++)
deleteNode(bucket[i]);
}
int main()
{
int n=10;
int a[N]={2,45,1,56,12,57,25,89,3,23};
cout<<"排序前:";
for(int i=0;i<n;i++)
cout<<a[i]<<" ";
bucketSort(a,n,10);
cout<<endl<<"排序后:";
for(int i=0;i<n;i++)
cout<<a[i]<<" ";
return 0;
}
三、分析
元素值域的划分,也就是元素到桶的映射规则。映射规则需要根据待排序集合的元素分布特性进行选择,若规则设计的过于模糊、宽泛,则可能导致待排序集合中所有元素全部映射到一个桶上,则桶排序向比较性质排序算法演变。若映射规则设计的过于具体、严苛,则可能导致待排序集合中每一个元素值映射到一个桶上,则桶排序向计数排序方式演化。排序算法的选择,从待排序集合中元素映射到各个桶上的过程,并不存在元素的比较和交换操作,在对各个桶中元素进行排序时,可以自主选择合适的排序算法,桶排序算法的复杂度和稳定性,都根据选择的排序算法不同而不同。