给你一个文件里面包含全国人民(14亿)的年龄数据(0~180),现在要你统计每一个年龄有多少人?
限制: 给定机器为 单台+1CPU+1G内存。不得使用现成的容器,比如map等。
- 假设每个年龄数据为2位数,gbk编码下每个数字字符size = 1B,该文件总大小 = 14*(10^8)*2B /1000 /1000 /1000 = 1.4G , 一次放不下
- 且使用排序算法的话,排序的最高效算法时间复杂度为:O(nlogn) ,其中n=14亿,排不出来,而且内存也不够。
- 如果使用现成的容器可以直接解决,如不使用现成容器,可以考虑用数组来实现。
数组算法
int a[] = new int[180];
a[0]++; // 0表示的是0岁,a[0]的值表示的就是0有多少人.
下标:数组最优一个特点。这里可以通下标表示成有意义的数据,不只是数据里面的标记,年龄和下标对应。随机访问:可以直接通过下标定位到数组中的某一个数据(高效查询)
public class AgeStas {
public static void main(String[] args) throws Exception {
String str = null;
String fileName = "/Users/WorkSpace/data-structure-algorithm/src/com/chenrx/algorithm/age.txt";
InputStreamReader isr = new InputStreamReader(new FileInputStream(fileName),"UTF-8");
long start = System.currentTimeMillis();
BufferedReader br = new BufferedReader(isr);
int tot = 0 ; // 14亿
// 缓存桶
int data[] = new int[200];
while((str = br.readLine()) != null){ //一行一行的读 O(n)
int age = Integer.valueOf(str);
data[age] ++ ;
tot ++ ;
}
// O(n) 14亿.
// 单核Cpu处理速度(考虑了和内存的交互速度): 100万/秒 - 1000万/秒
// 100s ~ 1000s之间
// 16核 6s ~ 60s之间
System.out.println("总共的数据大小: " + tot);
for(int i = 0 ; i < 200 ; i ++){//下标从0开始的
System.out.println(i + ":" + data[i]);
}
// 43757ms => 43s
System.out.println("计算花费的时间为:" + (System.currentTimeMillis() - start) + "ms");
}
}
// 输出结果
总共的数据大小: 1400000000
0:7780353
1:7778794
2:7773040
3:7779555
4:7776882
5:7773873
6:7778810
7:7777106
8:7781165
9:7782188
10:7774890
11:7776274
12:7778024
13:7777931
...