准确的问题描述:
输入:一个最多包含n个正整数的文件,每个数都小于n,其中n=10^7(one million)。在输入文件中没有任何两个 数相同。
输出:按升序排序的输入整数列表。
约束条件:1M的内存空间,有充足的磁盘空间,运行时最多需要几分钟,运行时间为10秒不需要优化。
问题分析:如果每个数字用32位整数来存储,1M的空间可以存储 250,000个整数,失少需要10^7 / 250,000
次排序来完成所有的排序,第一次排序0~249999,第四十次排序 97,5000~999,999。
优点:不必使用中间文件。
缺点:需要读取文件40次。
书中通过位图或者位向量来表示集合,例如集合{1,2,3,5,8,13}
可通过如下的位图来表示:0 1 1 1 0 1 0 0 1 0 0 0 0 1 0 0 0 0 0 0
java可以通过逻辑运算来实现位向量操作:具体代码如下:
package org.mino.perl.sort;
/**
* 位逻辑运算实现位向量
* @author DingJie
*/
public class BitSet {
private static final int BITPERWORD = 32;
private static final int SHIFT = 5;
private static final int MASK = 0x1F;
public static final int N = 10000000;
private static int a[] = new int[1 + N/BITPERWORD];
//设置数组第i位为1
public static void set(int i)
{
a[i>>SHIFT] |= (1<<(i&MASK)); //相应的字节置位,实现对字节的操作
}
//清空数组第i位为0
public static void clr(int i)
{
a[i>>SHIFT] &= ~ (1<<(i&MASK));
}
//查询数组第i位数字 是否为1
public static int test(int i)
{
return a[i>>SHIFT] &(1<<(i&MASK));
}
}
在进行大量数据排序之前需要对随机生成1百万个数据,其方法如下所示:
package org.mino.perl.sort;
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Random;
/**
* 获取随机数
* @author DingJie
*/
public class RandomNum {
/**
* @param args
*/
public static void main(String[] args) {
// RepeatedRandomNumber();
try {
randomNoRepeat(999999,1000000);
} catch (IOException e) {
e.printStackTrace();
}
}
private static int randInt(int i, int j, Random rand) {
if (i < j)
return i + rand.nextInt(j - i + 1);
return i;
}
private static void randomNoRepeat(int m, int n) throws IOException {
int[] array = new int[n];//最大的数组
Random rand = new Random(System.currentTimeMillis());
System.out.println(System.currentTimeMillis());
for (int i = 0; i < n; i++)
array[i] = i + 1; //赋初值,保证不重复
for (int i = 0; i < m; i++) {
int j = randInt(i, n - 1, rand);//返回从i 到n-1之间的任意随机数
int temp = array[j];
array[j] = array[i];
array[i] = temp;
}
FileWriter fw = new FileWriter("D:/randomNoRepeat.txt");
for (int i = 0; i < m; i++) {
System.out.println(array[i]);
fw.write(array[i] + "");
fw.write("\r\n");
fw.flush();
}
if(fw != null) {
fw.flush();
fw.close();
}
}
/**
* 有重复的随机数
*/
private static void RepeatedRandomNumber() {
// TODO Auto-generated method stub
long timeBegin = System.currentTimeMillis();
Random rand = new Random(System.currentTimeMillis());
int bigNum = 1000000;
BufferedWriter bw = null;
try {
bw = new BufferedWriter(new FileWriter("D:/input.txt"));
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
while((--bigNum) > 0) {
int randInt = Math.abs(rand.nextInt(1000000));
String strRand = randInt + "";
try {
bw.write(strRand);
System.out.println(strRand);
bw.newLine();
bw.flush();
} catch (IOException e) {
e.printStackTrace();
}
}
long timeEnd = System.currentTimeMillis();
System.out.println(timeEnd - timeBegin);
}
}
这样就可以对百万数据进行排序,可以使用java自带的BitSet
package org.mino.perl.sort;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.BitSet;
public class BitSortWithUtil {
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
final int N = 10 ^ 7;
BitSet bs = new BitSet(N);
File file = new File("D:/randomNoRepeat.txt");
FileReader fr = null;
BufferedReader bf = null;
int total = 0;
try {
fr = new FileReader(file);
bf = new BufferedReader(fr);
String temp = null;
while((temp = bf.readLine()) != null) {
total ++;
int intTemp = Integer.parseInt(temp.trim());
bs.set(intTemp);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if(bf != null) {
bf.close();
}
if(fr != null) {
fr.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
int count = bs.size();
int not_count = 0;
for(int i = 0; i < count; i++) {
if(bs.get(i)){
// System.out.println(i);
} else {
not_count ++;
System.out.println(i);
}
}
System.out.println("not :" + not_count);
System.out.println("total :" + (count-not_count) + " /" + total);
}
}
自定义位向量
package org.mino.perl.sort;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
/**
* 实现位排序
* @author DingJie
*/
public class BitSort {
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
File file = new File("D:/randomNoRepeat.txt");
FileReader fr = null;
BufferedReader bf = null;
int total = 0;
for(int i=0; i < BitSet.N; i++) {
BitSet.clr(i);
}
try {
fr = new FileReader(file);
bf = new BufferedReader(fr);
String temp = null;
while((temp = bf.readLine()) != null) {
total ++;
int intTemp = Integer.parseInt(temp.trim());
BitSet.set(intTemp);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if(bf != null) {
bf.close();
}
if(fr != null) {
fr.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
int count = 0;
for(int i = 0; i < BitSet.N; i++) {
if(BitSet.test(i) == 1) {
count ++;
System.out.println(i);
}
}
System.out.println("total :" + count + " /" + total);
}
}