http://pisces-java.iteye.com/blog/766745
题目大意:移动公司需要对已经发放的所有139段的号码进行统计排序,已经发放的139号码段的文件都存放在一个文本文件中(原题是放在两个文件中),一个号码一行,现在需要将文件里的所有号码进行排序,并写入到一个新的文件中;号码可能会有很多,最多可能有一亿个不同的号码(所有的139段号码),存入文本文件中大概要占1.2G的空间;jvm最大的内存在300以内,程序要考虑程序的可执行性及效率;只能使用Java标准库,不得使用第三方工具。
这是个典型的大数据量的排序算法问题,首先要考虑空间问题,一下把1.2G的数据读入内存是不太可能的,就算把1一亿条数据,转都转换成int类型存储也要占接近400M的空间。当时做个题目我并没有想太多的执行效率问题,主要就考虑了空间,而且习惯性的想到合并排序,基本思想是原文件分割成若干个小文件并排序,再将排序好的小文件合并得到最后结果,算法大概如下:
1.顺序读取存放号码文件的中所有号码,并取139之后的八位转换为int类型;每读取号码数满一百万个(这个数据可配置)将已经读取的号码排序并存入新建的临时文件。
2.将所有生成的号码有序的临时文件合并存入结果文件。
这个算法虽然解决了空间问题,但是运行效率极低,由于IO读写操作太多,加上步骤1中的排序的算法(快速排序)本来效率就不高(对于电话排序这种特殊情况来说),导致1亿条数据排序运行3个小时才有结果。
如果和能够减少排序的时间呢?首当其冲的减少IO操作,另外如果能够有更加好排序算法也行。前天无聊再看这个题目时突然想到大三时看《编程珠玑》时上面也有个问题的需求这个这个题目差不多,记得好像使用是位向量(实际上就是一个bit数组),用电话作为index,心中大喜,找到了解决此问题的最完美方案啦:用位向量存储电话号码,一个号码占一个bit,一亿个电话号码也只需要大概12M的空间;算法大概如下:
1.初始化bits[capacity];
2.顺序所有读入电话号码,并转换为int类型,修改位向量值:bits[phoneNum]=1;
3.遍历bits数组,如果bits[index]=1,转换index为电话号码输出。
Java中没有bit类型,一个boolean值占空间为1byte(感兴趣的可以自己写程序验证),我自己写个个用int模拟bit数组的类,代码如下:
- publicclassBitArray{
-
privateint[]bits=null;
-
privateintlength;
-
-
privatefinalstaticint[]bitValue={
-
0x80000000,
-
0x40000000,
-
0x20000000,
-
0x10000000,
-
0x08000000,
-
0x04000000,
-
0x02000000,
-
0x01000000,
-
0x00800000,
-
0x00400000,
-
0x00200000,
-
0x00100000,
-
0x00080000,
-
0x00040000,
-
0x00020000,
-
0x00010000,
-
0x00008000,
-
0x00004000,
-
0x00002000,
-
0x00001000,
-
0x00000800,
-
0x00000400,
-
0x00000200,
-
0x00000100,
-
0x00000080,
-
0x00000040,
-
0x00000020,
-
0x00000010,
-
0x00000008,
-
0x00000004,
-
0x00000002,
-
0x00000001
- };
-
publicBitArray(intlength){
-
if(length<0){
-
thrownewIllegalArgumentException("length必须大于零!");
- }
-
bits=newint[length/32+(length%32>0?1:0)];
-
this.length=length;
- }
-
-
publicintgetBit(intindex){
-
if(index<0||index>length){
-
thrownewIllegalArgumentException("length必须大于零小于"+length);
- }
-
intintData=bits[index/32];
-
return(intData&bitValue[index%32])>>>(32-index%32-1);
- }
-
-
publicvoidsetBit(intindex,intvalue){
-
if(index<0||index>length){
-
thrownewIllegalArgumentException("length必须大于零小于"+length);
- }
-
if(value!=1&&value!=0){
-
thrownewIllegalArgumentException("value必须为0或者1");
- }
-
intintData=bits[index/32];
-
if(value==1){
-
bits[index/32]=intData|bitValue[index%32];
-
}else{
-
bits[index/32]=intData&~bitValue[index%32];
- }
- }
-
publicintgetLength(){
-
returnlength;
- }
- }
bit数组有了,剩下就是算法代码,核心代码如下:
- bitArray=newBitArray(100000000);
-
-
while((phoneNum=bufferedReader.readLine())!=null){
-
phoneNum=phoneNum.trim().substring(3);
-
- phoneNumAsInt=Integer.valueOf(phoneNum);
-
-
bitArray.setBit(phoneNumAsInt,1);
- }
-
-
for(inti=0;i<sortUnit;i++){
-
if(bitArray.getBit(i)==1){
-
writer.write("139"+leftPad(String.valueOf(i+sortUnit*times),8));
- writer.newLine();
- }
- }
- writer.flush();
经测试,修改后的算法排序时只需要20多M的内存,一亿条电话号码排序只要10分钟(时间主要花在IO上),看来效果还是很明显的。
这个算法很快,不过也有他的局限性:
1.只能用于整数的排序,或者可以准确映射到正整数(对象不同对应的正整数也不相同)的数据的排序。
2.不能处理重复的数据,重复的数据排序后只有一条(如果有这种需求可以在这个算法的基础上修改,
给出现次数大于1的数据添加个计数器,然后存入Map中)
3.对于数据量极其大的数据处理可能还是比较占用空间,
这种情况可配合多通道排序算法解决。
PS:这个算法的思想源于《编程珠玑》,有兴趣的可以读读那本书,非常不错!
分享到:
相关推荐
标题中的“15行代码5秒搞定上...通过以上步骤,我们不仅能学习到一种高效的整数排序方法,还能进一步提升对算法优化、Java编程以及大数据处理的理解。这种知识对于任何涉及数据处理和分析的IT专业人员都是极其宝贵的。
总的来说,起泡法排序是一种直观且易于理解的排序算法,虽然其时间复杂度在最坏情况下为O(n^2),在大数据量的排序中效率较低,但在教学和小型数据排序中仍有一定的应用价值。通过分析和实现这个例子,学生可以深入...
编写程序,实现所有内部排序算法,并比较这些算法在不同数据量下的运行时间。 (1)排序算法包括:插入排序、希尔排序、堆排序、归并排序、快速排序、基数排序。 (2)对整数进行排序。 (3)程序功能:可从键盘输入...
在实际应用中,排序和查找算法的优化至关重要,尤其是在处理大数据量时。例如,可以使用对象的特性(如键或哈希值)来改进查找效率,或者通过优化排序算法来减少时间复杂度。此外,内存管理、多线程并行处理也是提高...
数据结构中的基数排序是一种非比较型整数排序算法,它基于数字的位宽进行排序,尤其适用于处理大量相同数字的情况。基数排序的核心思想是将数字按照位数从低位到高位分别进行桶排序,最终得到完全有序的序列。下面将...
大数据量、海量数据处理需要使用各种数据结构和算法来解决,例如Hash表、Trie树、Bloom filter、堆排序等。根据不同的问题,选择合适的数据结构和算法是关键。在解决大数据量、海量数据处理问题时,需要充分考虑数据...
选择排序的时间复杂度始终为O(n²),不适用于大数据量的排序。 8. **希尔排序**:希尔排序是插入排序的改进版,通过增量序列将待排序的元素进行分组,然后对每个组进行插入排序,最后进行一次插入排序。希尔排序的...
2. **基数排序**:基数排序是一种非比较型整数排序算法,它根据数字位数从低到高进行排序。基数排序的时间复杂度为线性,非常适用于处理大量整数的排序。在C++和C中,我们可以利用数组和计数排序的思想来实现基数...
总的来说,基数排序是一种非常有效的整数排序算法,尤其适用于处理具有固定范围和多个关键字的数据。通过选择合适的关键字处理策略,基数排序能够高效地完成排序任务,为大数据处理提供了有力的工具。
例如,当数据量较大且对稳定性要求不高的时候,可以选择快速排序或堆排序;对于小规模或基本有序的数据,插入排序和冒泡排序可能会更高效;而对于特定类型的整数排序,基数排序则表现出色。在实际应用中,需要根据...
堆排序适合大数据量的场景,因为它不需要递归或二维数组,避免了大数据量时可能出现的栈溢出。 4. **Shell排序**:Shell排序是插入排序的一种优化版本,通过间隔序列(例如,希尔序列)来减少元素的交换次数。它在...
排序算法是计算机科学中至关重要的一部分,它涉及到如何有效地组织和排列数据。无论是处理数据库记录、优化数据结构...记住,选择哪种排序算法取决于数据的特性和性能需求,比如数据量大小、是否稳定、空间复杂度等。
内部排序是指待排序的数据全部存储在内存中,而外部排序则是指待排序的数据量过大以至于无法一次性全部加载到内存中,需要分批处理。 #### 二、常见排序算法详解 ##### 1. 冒泡排序(Bubble Sort) 冒泡排序是一...
本话题聚焦于“易语言自定义数据类型数组排序”,将深入探讨如何在易语言中创建、操作自定义数据类型数组,并实现各种排序算法,如根据产地、类别和售价等属性进行排序。 自定义数据类型在易语言中允许我们定义包含...
它保证了稳定的排序,适用于大数据量的排序,但需要额外的内存空间。 5. **基数排序**:基数排序是一种非比较型排序,通过按照数字的位数从低位到高位进行排序。它适合处理具有固定范围的整数,如电话号码或邮政...
- **基数排序**:根据数字的每一位分别进行排序,适合于处理整数排序。 排序的历史悠久,从古代的字母排序到现代计算机的诞生和发展,排序技术经历了显著的进步。随着计算机技术的演进,排序算法也在不断地优化,...
基数排序基于数字的位数,从低位到高位逐位排序,适合处理大量整数排序,时间复杂度为O(kn),其中k是数字的最大位数。 ### 排序算法的选择原则 - 对于小规模数据(n≤50),直接插入排序或直接选择排序是不错的...
最后,基数排序是一种非比较型整数排序算法,它依据整数的位数从低位到高位进行排序。基数排序的时间复杂度为O(d*(n+k)),其中d是数字的最大位数,k是基数(通常是10)。基数排序适用于处理大量相同元素的情况,特别...
- 外部排序场景,即数据量过大无法完全加载到内存中,此时可以采用桶排序来分批处理数据。 **案例分析**: 假设需要根据年龄对100万用户数据进行排序,可以将用户年龄分布在一个合理的范围内(例如18岁到100岁),...