10G整数文件需找中位数

 

题目:在一个文件中有 10G 个整数,乱序排列,要求找出中位数。内存限制为 2G。只写出思路即可(内存限制为 2G的意思就是,可以使用2G的空间来运行程序,而不考虑这台机器上的其他软件的占用内存)。

 

 

分析: 既然要找中位数,很简单就是排序的想法。那么基于字节的桶排序是一个可行的方法 (请见《桶排序 》):

思想:将整形的每1byte作为一个关键字,也就是说一个整形可以拆成4个keys,而且最高位的keys越大,整数越大。如果高位keys相同,则比较次高位的keys。整个比较过程类似于字符串的字典序。

第一步:把10G整数每2G读入一次内存,然后一次遍历这536,870,912个数据。每个数据用位运算">>"取出最高8位(31-24)。这8bits(0-255)最多表示255个桶,那么可以根据8bit的值来确定丢入第几个桶。最后把每个桶写入一个磁盘文件中,同时在内存中统计每个桶内数据的数量,自然这个数量只需要255个整形空间即可。

代价:(1) 10G数据依次读入内存的IO代价(这个是无法避免的,CPU不能直接在磁盘上运算)。(2)在内存中遍历536,870,912个数据,这是一个O(n)的线性时间复杂度。(3)把255个桶写会到255个磁盘文件空间中,这个代价是额外的,也就是多付出一倍的10G数据转移的时间。

第二步:根据内存中255个桶内的数量,计算中位数在第几个桶中。很显然,2,684,354,560个数中位数是第1,342,177,280个。假设前127个桶的数据量相加,发现少于1,342,177,280,把第128个桶数据量加上,大于1,342,177,280。说明,中位数必在磁盘的第128个桶中。而且在这个桶的第1,342,177,280-N(0-127)个数位上。N(0-127)表示前127个桶的数据量之和。然后把第128个文件中的整数读入内存。(平均而言,每个文件的大小估计在10G/128=80M左右,当然也不一定,但是超过2G的可能性很小)。

代价:(1)循环计算255个桶中的数据量累加,需要O(M)的代价,其中m<255。(2)读入一个大概80M左右文件大小的IO代价。

注意,变态的情况下,这个需要读入的第128号文件仍然大于2G,那么整个读入仍然可以按照第一步分批来进行读取。

第三步:继续以内存中的整数的次高8bit进行桶排序(23-16)。过程和第一步相同,也是255个桶。

第四步:一直下去,直到最低字节(7-0bit)的桶排序结束。我相信这个时候完全可以在内存中使用一次快排就可以了。

 

 

整个过程的时间复杂度在O(n)的线性级别上(没有任何循环嵌套)。但主要时间消耗在第一步的第二次内存-磁盘数据交换上,即10G数据分255个文件写回磁盘上。一般而言,如果第二步过后,内存可以容纳下存在中位数的某一个文件的话,直接快排就可以了。关于快排的效率,可以看看我博客中的数据《基于比较的内部排序总结 》。

### 回答1: 我可以给你一个用Java写的反转三位数整数的示例代码:import java.util.Scanner;public class ReverseNumber { public static void main(String[] args) { Scanner cin = new Scanner(System.in); System.out.print("请输入一个三位数整数:"); int num = cin.nextInt(); int b = num/100; int s = (num-b*100)/10; int g = num%10; System.out.println("反转后的结果为:" + g + s + b); } } ### 回答2: 要用JAVA写一个程序从键盘输入一个三位数整数,然后将其逆序输出,我们可以按照以下步骤进行: 1. 首先,我们需要导入Java中用于读取输入的Scanner类。可以在文件开头添加以下代码。 ```java import java.util.Scanner; ``` 2. 接下来,我们需要创建一个Scanner对象来读取输入。可以在main函数中添加以下代码。 ```java Scanner scanner = new Scanner(System.in); ``` 3. 然后,我们需要提示用户输入一个三位数整数,并将其存储在一个整型变量中。可以添加以下代码。 ```java System.out.print("请输入一个三位数整数:"); int number = scanner.nextInt(); ``` 4. 接下来,我们需要将输入的整数逆序输出。为了实现这一点,我们可以使用循环和取余操作。可以添加以下代码。 ```java int reverse = 0; while (number != 0) { int digit = number % 10; reverse = reverse * 10 + digit; number /= 10; } System.out.println("逆序输出:" + reverse); ``` 5. 最后,我们需要关闭Scanner对象,这可以通过添加以下代码实现。 ```java scanner.close(); ``` 整个程序的完整代码如下所示: ```java import java.util.Scanner; public class ReverseNumber { public static void main(String[] args) { Scanner scanner = new Scanner(System.in); System.out.print("请输入一个三位数整数:"); int number = scanner.nextInt(); int reverse = 0; while (number != 0) { int digit = number % 10; reverse = reverse * 10 + digit; number /= 10; } System.out.println("逆序输出:" + reverse); scanner.close(); } } ``` 这样,当用户运行程序时,它将提示用户输入一个三位数的整数,然后将该整数逆序输出。 ### 回答3: 可以使用Java的Scanner类来实现从键盘输入一个三位数整数,并通过转换成字符串和字符数组的方式来将其逆序输出。 首先,我们需要导入java.util.Scanner类来实现键盘输入。然后,创建Scanner对象,并使用nextInt()方法读取一个整数。 接下来,将读取的整数转换成字符串,使用String类的valueOf()方法即可实现。然后,再将字符串转换成字符数组,使用toCharArray()方法即可实现。 最后,我们使用一个for循环从后向前遍历字符数组,并输出每个字符即可实现逆序输出。 下面是代码示例: ```java import java.util.Scanner; public class ReverseNumber { public static void main(String[] args) { Scanner scanner = new Scanner(System.in); System.out.print("请输入一个三位数整数:"); int number = scanner.nextInt(); String strNumber = String.valueOf(number); char[] charArray = strNumber.toCharArray(); System.out.print("逆序输出结果:"); for (int i = charArray.length - 1; i >= 0; i--) { System.out.print(charArray[i]); } } } ``` 执行上述代码后,程序会提示用户输入一个三位数整数,然后将逆序输出该整数
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值