桶排序
当桶排序的输入符合均匀分布时,可以以线性期望时间运行。桶排序是对输入做了假设。
思想:将区间划分为几个相同大小的子区间。将n个元素分布到桶中也就是区间中。这种分布是使用一个函数进行映射。此时就已经对数据进行了分区,其实就是有点类似快速排序一样,不过分区间的方式不同而已。然后再对区间中的数据进行排序,这个时候我们可以使用效率较高的排序方法进行排序。我们可以使用链表来操作。
效能分析:将元素映射到桶中使用的时间是O(n)。利用先进的比较排序算法对每个桶内的所有数据进行排序,其时间复杂度为 O(N*logN),所以对于N个待排数据,M个桶,平均每个桶[N/M]个数据的桶排序平均时间复杂度为:
O(N)+O(M*(N/M)*log(N/M))=O(N+N*(logN-logM))=O(N+N*logN-N*logM)) 当N=M时,即极限情况下每个桶只有一个数据时。桶排序的最好效率能够达到O(N)。
即使输入不符合均匀分布,桶排序也仍然可以以线性时间运行。只要输入满足同的尺寸的平方和与总的元素数目呈线性关系。桶数量M越大,其
效率越高,最好的时间复杂度达到O(N)。 当然桶排序的空间复杂度 为O(N+M) 。
template<class T>
class BucketNode
{
public:
T key;
BucketNode<T>* next;
BucketNode()
{
next=NULL;
}
};
template<class T>
class BucketList
{
public:
BucketNode<T>** root;//指向桶元素中最顶端那个元素。因为这个指针数组中每一个元素也是一个BucketNode*类型
BucketList()
{
root=NULL;
}
void BUCKET_SORT(T* bucketArray,int length);//桶排序
};
void Test();
#include "stdafx.h"
#include "BucketSort.h"
template<class T>
void BucketList<T>::BUCKET_SORT(T* bucketArray,int length)
{
//现在假设是在0-100的元素
root=new BucketNode<T>*[length];
for (int i=0;i<length;i++)
{
*(root+i)=new BucketNode<T>();//有一个头元素,也就是说在这个元素中什么都不存放,有点浪费?
}
//一个思想是不想一下子就建立这么多的索引,有的空间也是在浪费。不行,如果按照需求建立的话,后面的元素怎样的查找
//找到这个索引所在的位置呢,必须是实现就分配好了的
int index=0;
BucketNode<T>*tempNode=NULL;
for (int i=0;i<length;i++)
{
index=*(bucketArray+i)/10;//因为实在0-100之间的元素。索引值为其十位的值
tempNode=*(root+index);//得到索引的这个元素
BucketNode<T>*newNode=new BucketNode<T>();
newNode->key=*(bucketArray+i);
if (tempNode->next==NULL)//若元素为空
{
tempNode->next=newNode;
}
else
{
while(tempNode->next!=NULL&&tempNode->next->key<newNode->key)
{
tempNode=tempNode->next;
}
newNode->next=tempNode->next;
tempNode->next=newNode;
}
}
for (int i=0;i<length;i++)
{
tempNode=*(root+i);
while(tempNode->next!=NULL)
{
cout<<tempNode->next->key<<" ";
tempNode=tempNode->next;
}
cout<<endl;
}
}
void Test()
{
int testArray[]={16,4,10,14,7,9,3,2,8,1};
cout<<"排序前的数组"<<endl;
for (int i=0;i<10;i++)
{
cout<<testArray[i]<<" ";
}
BucketList<int>*bucketList=new BucketList<int>();
cout<<"排序之后的数组"<<endl;
bucketList->BUCKET_SORT(testArray,10);
}
当然我上面桶内部的插入排序并不是高效的排序方式。可以使用快排序,这个时候我们的结点势必要有prev的指针。