前面一篇文章《100亿个数字的大文件如何快速找出最小的值?》中的排序结果消耗的时间相对来说比位图法排序更长。本章主要为大家介绍一下位图法排序。
位图法定义
位图法就是bitmap的缩写。所谓bitmap,就是用每一位来存放某种状态,适用于大规模数据,但数据状态又不是很多的情况。通常是用来判断某个数据存不存在的。在STL中有一个bitset容器,其实就是位图法,引用bitset介绍:
A bitset is a special container class that is designed to store bits (elements with only two possible values: 0 or 1,true or false, …).The class is very similar to a regular array, but optimizing for space allocation: each element occupies only one bit (which is eight times less than the smallest elemental type in C++: char).Each element (each bit) can be accessed individually: for example, for a given bitset named mybitset, the expression mybitset[3] accesses its fourth bit, just like a regular array accesses its elements.
数据结构
unsigned int bit[N];
在这个数组里面,可以存储 N * sizeof(int) * 8个数据,但是最大的数只能是N * sizeof(int) * 8 – 1。假如,我们要存储的数据范围为0-15,则我们只需要使得N=1,这样就可以把数据存进去。如下图:
数据为【5,1,7,15,0,4,6,10】,则存入这个结构中的情况为
了解了上面的定义和数据结构。我们在看看Jon Bentley的《编程珠玑》,刚看完第一章,觉得老外写的东西就是要比国内的生动很多! 第一章是开篇,要说的事情是:要把问题描述清楚。为了说明白这个事情,作者举了一个实例:怎样给一个磁盘文件排序? 这个问题问的很模糊是不是? 其实这个问题正确清楚的描述如下:
输入:一个最多包含n个正整数的文件,每个数都小于n,其中n=10,000,000。输入文件中没有重复的整数,没有其他数据与该整数相关联(这句话不知道是想说什么问题..)。
输出: 按升序排列这些数,并写入磁盘。
约束:有 1MB多(不超过2MB) 的内存空间可用,有充足的硬盘空间。
好了,根据上面的基础,我们来完成上一篇中的排序。相关代码如下:
private BitSet bits; public void perform( String largeFileName, int total, String destLargeFileName, Castor<Integer> castor, int readerBufferSize, int writerBufferSize, boolean asc) throws IOException { System.out.println("BitmapSort Started."); long start = System.currentTimeMillis(); bits = new BitSet(total); InputPart<Integer> largeIn = PartFactory.createCharBufferedInputPart(largeFileName, readerBufferSize); OutputPart<Integer> largeOut = PartFactory.createCharBufferedOutputPart(destLargeFileName, writerBufferSize); largeOut.delete(); Integer data; int off = 0; try { while (true) { data = largeIn.read(); if (data == null) break; int v = data; set(v); off++; } largeIn.close(); int size = bits.size(); System.out.println(String.format("lines : %d ,bits : %d", off, size)); if(asc) { for (int i = 0; i < size; i++) { if (get(i)) { largeOut.write(i); } } }else { for (int i = size - 1; i >= 0; i--) { if (get(i)) { largeOut.write(i); } } } largeOut.close(); long stop = System.currentTimeMillis(); long elapsed = stop - start; System.out.println(String.format("BitmapSort Completed.elapsed : %dms",elapsed)); }finally { largeIn.close(); largeOut.close(); } } private void set(int i) { bits.set(i); } private boolean get(int v) { return bits.get(v); }
跑完整个100亿的文件,只需要190秒,3分来钟.
以核心内存4663M/32大小的空间跑出这么个结果,而且大量时间在用于I/O,不错.
: » 100亿个数字的位图法快速排序
原创文章,作者:wure,如若转载,请注明出处:https://blog.ytso.com/tech/java/251519.html