如何给大数据量的磁盘文件排序

来源:互联网 发布:python 抓到的源码不对 编辑:程序博客网 时间:2024/05/20 02:26

本文是学习 july博客中的如何给 10^7个数据量的磁盘文件排序,这一文章的学习文章。

July博客

问题:

输入:给定一个文件,里面有 最多n个不重复的正整数,其中每个数都小于等于n, n= 10^7

输出:得到按小到大升序排列的包含所有输入的整数的列表

条件:1M内存空间,时间5分钟以下,10s最佳


分析:

解法1 : 编程猪机上说的 位图法
java代码实现如下:

由于1 M 有 8 388 068 bit,代表放不下,所以要分开两部分。

当中需要使用java bitset类 , 为什么要用BitSet

import java.io.BufferedReader;import java.io.BufferedWriter;import java.io.File;import java.io.FileReader;import java.io.FileWriter;import java.util.BitSet;public class bitsetuse {static int max_each_scan = 5000000;public static void main(String[] args) throws Exception{BitSet bs = new BitSet(max_each_scan);    BufferedReader bis = new BufferedReader(new FileReader("dataMy.txt"));String str=null;while((str=bis.readLine())!=null){String[] arrStr = str.split(" ");int[] arrInt = new int[arrStr.length];for(int i=0;i<arrStr.length;i++){// 转为 整形arrInt[i] = Integer.parseInt(arrStr[i]);// 如果是 小于 max_each_scan setif(arrInt[i]<max_each_scan){bs.set(arrInt[i],true);}}}String path = "/home/administrator/workspace/HelloWorld/dataoutputMy.txt";File f = new File(path);BufferedWriter bw = new BufferedWriter(new FileWriter(f));for(int i=0;i < max_each_scan;i++){if(bs.get(i)){System.out.print(i+" ");bw.write(i+" ");}}bs.clear();bw.flush();bis.close();bis = new BufferedReader(new FileReader("dataMy.txt"));while((str=bis.readLine())!=null){String[] arrStr = str.split(" ");int[] arrInt = new int[arrStr.length];for(int i=0;i<arrStr.length;i++){arrInt[i] = Integer.parseInt(arrStr[i]);// 如果是 大于 max_each_scan的整形,if(arrInt[i] >= max_each_scan){bs.set(arrInt[i]-max_each_scan,true);}}}System.out.println();for(int i=0;i < max_each_scan;i++){if(bs.get(i)){System.out.print(i+max_each_scan+" ");bw.write(i+max_each_scan+" ");}}// 原来本来一直都忘记 flush或者close来刷新缓冲区bw.flush();bw.close();}}
在对于io的各种不认识情况下,算是了解和写好了代码。

今日学习,毕。


下面研究如何用java生成1000W不重复的数据量

由于是从C++的程序中改过来的,所以先要了解一些C++的method以及它们在java中的实现

C++中rand  srand的用法

rand()在每次运行的时候都是和上一次相同,srand就是用来更改rand的随机数种子。

JAVA获取随机数

package javaio;import java.util.Random;public class javarandom {/** * @param args */public static void main(String[] args) {// 下面程序是获得指定范围内的重复随机数int[] intRet = new int[6];  int intRd = 0; //存放随机数int count = 0; //记录生成的随机数个数int flag = 0; //是否已经生成过标志while(count<6){// 每次的种子都不一样,这个好像没必要,本来就不一样Random rdm = new Random(System.currentTimeMillis());// 获得一个指定范围的随机数,1到6的随机数intRd = Math.abs(rdm.nextInt())%6+1;//第一次不会执行for(int i=0;i<count;i++){// 从第二次开始,如果生成了重复的随机数目// flag == 1 ,抛弃这个随机数,再生成一个,直到生成足够的随机数if(intRet[i]==intRd){flag = 1;break;}else{flag = 0;}}// 第一次执行后 count == 1 if(flag==0){intRet[count] = intRd;count++;}}// 显示所有随机数for(int t=0;t<6;t++){System.out.println(t+"->"+intRet[t]);}}}

以下是写入文件中的 一定范围内的不重复随机数的生成程序

package javaio;import java.io.BufferedWriter;import java.io.FileWriter;import java.util.Random;public class javarandom {/** * @param args */public static void main(String[] args) throws Exception{final int size = 1000;// 下面程序是获得指定范围内的重复随机数int[] intRet = new int[size];  int intRd = 0; //存放随机数int count = 0; //记录生成的随机数个数int flag = 0; //是否已经生成过标志while(count<size){// 每次的种子都不一样,这个好像没必要,本来就不一样Random rdm = new Random(System.currentTimeMillis());// 获得一个指定范围的随机数,1到6的随机数intRd = Math.abs(rdm.nextInt())%size+1;//第一次不会执行for(int i=0;i<count;i++){// 从第二次开始,如果生成了重复的随机数目// flag == 1 ,抛弃这个随机数,再生成一个,直到生成足够的随机数if(intRet[i]==intRd){flag = 1;break;}else{flag = 0;}}// 第一次执行后 count == 1 if(flag==0){intRet[count] = intRd;count++;}}// 显示所有随机数//for(int t=0;t<size;t++){//System.out.println(t+"->"+intRet[t]);//}BufferedWriter bs = new BufferedWriter(new FileWriter("dataRandom.txt"));// 写入文件中for(int t=0;t<size;t++){bs.write(intRet[t]+" ");if(t%100 == 0 && t!=0){bs.write("\n");}//System.out.println(t+"->"+intRet[t]);}bs.close();}}

接下来就进行 多路归并

多路归并与一般归并的区别,一般归并是2路归并,多路归并是k路归并

归并的有序表有两个,叫做二路归并,归并的有序表有k个,称为k路归并

归并的算法分析:

1. 稳定性: 归并排序是一种稳定的排序。

2.  存储结构要求:可以顺序,也可以链表

3. 时间复杂度:无论是最好还是最环都是O(nlgn)

4. 空间复杂度:O(n) 不是就地排序

注意:若是用单链表做存储结构,很容易给出就地的归并排序


在链表排序中,归并排序很受欢迎,在基于比较的排序法中,时间复杂度为0(nlgn)的排序算法中唯一稳定的排序


多路归并的C++实现转为Java实现,开始:

对Java IO不熟悉,这段代码无法写出,惭愧。

总结:

位图和多路归并两种方案的时空间复杂度比较:

         时间空间位图O(N)0.625M多路归并O(Nlogn)1M

多路归并的时间还要加上读写磁盘的时间,以上只是简化的时间复杂度


由于位图只能对只出现一次的特殊情况,所以虽然多路归并败者树比较浪费时间,但是当数据有重复的时候还是有用。程序是写不出了,可以看看败者树,熟悉理论。

bit-map的适用范围:

数据的快速查找,判重(这个相当重要,因为bit-map的不重复特性导致,去重复还可以选用hash),删除。

本章学习,毕,留下任务:多路归并理论,败者树。










0 0