刚才在JULY的博客上看了对海量数据排序的讲解(http://blog.csdn.net/v_JULY_v/archive/2011/05/28/6451990.aspx),仔细看了几遍,大概理解了使用归并排序的执行过程。于是想知道如果把归并排序替换成其他方法是否可行。仔细想了一下,觉得桶排序可以一试,所写了程序测试了一下。
算法的思路是:
第一步。把每个数据最高的k位作为桶编号,创建2^k个桶.然后把每个数据加入到对应的桶中,因为内存有限,把每个桶与一个文件对应,这样可以得到2^k个文件,由于不同桶中的数据大小已经不同,所以只需要分别把每个桶中的数据排好,那么全部数据就是有序的了。
第二步。采用类似计数排序的方法分别对每个文件(桶)中的数据进行排序,由于内存有限不能直接使用计数排序,而是用计数排序的简化版。
先用一个数组统计每个数字出现的次数
arr[SIZE]={0};
for each d;
++arr[d];
然后根据数组中每个元素出现的次数由小到大地输出数据。
for each i in arr
num=arr[i];
while num!=0
print i; //输出结果
num=num-1;
这样就把一个文件中的数据排好了,分析上面的算法会发现它是 不稳定 的排序算法。
分析数组arr的大小。
因为数据有10^7个,因此,arr中元素的类型至少应是int类型的,占4个字节。由于内存限制为1M 所以数组arr的大小可取到256k=2^18.
也就是说第一步的每个桶最多只能放2^18个不同的数。题目说每个数字最大为10^7=2^24,因此可以将每个数字的第18~23位作为桶编号,可得64个桶。又因为10^7的二进制形式的第18~23位是100110,转成十进制是38, 即最大的数落在编号为38的桶中。因此实际只需39个桶即可。
---------------------------------------------------------------------------------------
实验结果:
我在vs2010的release版下测试,所使用的数据是用JULY博客中的给出的随机数生成算法生成的。排序所花的总时间为39秒。
又在同样的环境下测试了一下JULY博客中的算法执行时间为:
The time needs in memory sort: 22172ms
The time needs in merge sort: 20344ms
这个算法是按两步分别计时的,所以总时间为42秒。
可见两个算法执行时间相似。
--------------------------------------------------------------------------------
源码:
-----------------------------------------------------------------------------------------------
------------------------------------------------------------------------------------------------
对上面的程序改进了一下,上面的算法保存桶中数据时,存的是整个数字,但实际上数据的高位是不用存的,同一个桶中的数据的高位都是相同的,根据桶的编号就可以把数据的高位部分确定出来。于是我对程序做了修改。
原来的桶文件大小约为2.0M,改进以后每个桶的大小为1.68M,执行时间也有所降低。
改进后的算法的执行时间为28秒。
又重复做了几次试验,发现所用时间均为33秒。
-------------------------------------
源码: