号称效率为O(n)的排序算法-----计数排序

  今天下午研究了下CountingSort算法,虽然这个算法的效率为O(n),简单测试了一下,确实蛮快的。但是这个算法的限制太多:

   数据集必须为正整数。。。(也就是说数据集中不能有负数和小数,连0都不行!!) 因此这个算法的应用范围很小,不过速度确实很快。其实网上已经有很多示例了,不过看和自己写一个示例感觉是完全不一样的,呵呵。。。

 

 问:为什么这个算法能不比较就知道数值的位置呢?
 答:因为这个算法引入了”数轴“的概念,”数轴“的作用相当于是一个计数器,记录了每个数值出现的频率,
 ”数轴“的大小应该为数据集中的最大值,以数据集中的数值作为索引(因此,前提条件是数据集必须都是正整数)
 如在数组{1,2,3,4,5,4},”数轴“的大小应该为5 , 具体内容为:{1,1,1,2,1}
 然后再计算数据集中的每个数值的位置:其实就是累加”数轴“ 累加后的结果为:{1,2,3,5,6}
 因为”数轴“是有序的,因此,可以由”数轴“告诉你数据集中每个数值的位置,如:数值 3在整个数据集的第3位,直接插入即可。
 这下明白了吧,关键就是”数轴“是有序的。

 

上代码:

   CountingSort.h:

   template <class T> class CountingSort { public: CountingSort(); ~CountingSort(); bool Sort(T* needSortArrayPtr,long length); T* GetResult(); private: T m_max; bool _FindMax(T*needSortArrayPtr,long length); T* m_resultArrayPtr; };

   头文件没啥好注释的。。。

   CountingSort.cpp:

    #include <string> #include <iostream> #include "CountingSort.h" //这个头文件主要是为了计算一个数组中的最大值。 #include "../../Max.cpp" template <class T> CountingSort<T>::CountingSort(){ m_resultArrayPtr = NULL; } template <class T> CountingSort<T>::~CountingSort(){ delete [] m_resultArrayPtr; } template <class T> bool CountingSort<T>::Sort(T* needSortArrayPtr,long length){ if( length < 1 ) return false; if(_FindMax(needSortArrayPtr,length)!=true) return false; //之所以有这个判断是因为,计数排序的前提是数据集必须为正整数, //因此,如果最大值为负时,则数据集一定不全为正, if(m_max < 0) return false; long numberLineCount(0); numberLineCount = static_cast<long>(m_max); // “数轴”,用于存放数据集中每个数值出现的频率 T *numberLinePtr = new T[numberLineCount]; memset(numberLinePtr,0,numberLineCount*sizeof(T)); long index(0); for(int i= 0;i<length;i++){ index = static_cast<long>(*(needSortArrayPtr+i)); ++ (*(numberLinePtr+index-1)); } //计算出数据集中每个数值在位置,注意:这里是理解这个非比较算法的重点, for(int i=1;i<numberLineCount;i++){ (*(numberLinePtr+i)) += (*(numberLinePtr+i-1)); } m_resultArrayPtr = new T[length]; memset(m_resultArrayPtr,0,length*sizeof(T)); for(int i=0;i < length;i++){ //这里先用拿到数据集中的一个数值 index = static_cast<long>(*(needSortArrayPtr+i)); //由这个数值作为索引去取这个数值的位置 //问:”数轴“为什么不会越界呢? //答:之前我们new这个”数轴“的时候是以整个数据集中的最大值来创建的。 index = static_cast<long>(*(numberLinePtr+index - 1)); //由位置直接插入。 *(m_resultArrayPtr+index-1) = static_cast<long>(*(needSortArrayPtr+i)); //这一步是必须的,如果数据集中有相同的数值时,必须减1。 --(*(numberLinePtr+*(needSortArrayPtr+i) - 1)); } delete [] numberLinePtr; return true; } template <class T> T* CountingSort<T>::GetResult(){ if(m_resultArrayPtr!=NULL) return m_resultArrayPtr; } template <class T> bool CountingSort<T>::_FindMax(T* needSortArrayPtr,long length){ Max<T> max; m_max = max.GetMax(needSortArrayPtr,length); return true; }

   测试代码:

 

   #include <iostream> #include "CountingSort.cpp" int main(int argc,char *argv[]){ const int length = 10000; long *a = new long[length]; for(int i=0;i<length;i++){ *(a+i) = i+1; } *(a+1) = 908908; *(a+2) = 123123; CountingSort<long> sort; sort.Sort(a,length); long * result; result = sort.GetResult(); for(int i=0;i<length;i++){ std::cout << *(result+i) << std::endl; } return 0; }

 

  所有程序在XP SP3,VC2008在编译通过。

   由于求最大值的类没有列出来,干脆我打个包发到资源上去。。。。。这个是整个完整的示例,有需要的朋友可以下载:

 

  http://download.csdn.net/source/1320980

 

你可能感兴趣的:(号称效率为O(n)的排序算法-----计数排序)