准确的问题描述:
输入:一个最多包含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); } }