外排序(大文件内存不够无法一次加载)

简介: 对远远大于内存的数据进行外排序,在多路比较的时候用败者树效率会更高。这个算法可以在建立倒排索引的时候使用package my.sort;import java.io.BufferedInputStream;import java.io.BufferedOutputStream;import java.io.BufferedWriter;import java.io.Dat



对远远大于内存的数据进行外排序,在多路比较的时候用败者树效率会更高。

这个算法可以在建立倒排索引的时候使用



package my.sort;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedWriter;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.Random;

/**
 * 基于大数据量的外排序算法,分为二路归并和多路归并
 * @author java2king
 * @link http://blog.csdn.net/Java2King
 *
 */
public class ExternalSort {

    public static int ITEM_COUNT = 10000000; //总数 

    public static int BUFFER_SIZE = 1024*4*1000;// 一次缓冲读取
    
    public static int FILE_COUNT = 1024*1000*1*4;// 每个文件的记录数
    
    public static File MAIN_FILE = new File("mainset");//要排序的文件

    /**
     * 二路归并
     * @param file
     * @return
     * @throws IOException
     */
    public File sort(File file) throws IOException {
        ArrayList<File> files = split(file);
        return process(files);
    }
    /**
     * 多路归并
     * @param file
     * @throws IOException
     */
    public void mSort(File file) throws IOException{
        ArrayList<File> files = split(file);
        multipleMerge(files);
        
    }

    // recursive method to merge the lists until we are left with a
    // single merged list
    private File process(ArrayList<File> list) throws IOException {
        if (list.size() == 1) {
            return list.get(0);
        }
        ArrayList<File> inter = new ArrayList<File>();
        for (Iterator<File> itr = list.iterator(); itr.hasNext();) {
            File one = itr.next();
            if (itr.hasNext()) {
                File two = itr.next();
                inter.add(merge(one, two));
            } else {
              //  return one;
                inter.add(one);
            }
        }
        return process(inter);
    }
    /**
     * Splits the original file into a number of sub files. 
     */
    private ArrayList<File> split(File file) throws IOException {
        ArrayList<File> files = new ArrayList<File>();
        int[] buffer = new int[FILE_COUNT];
        FileInputStream fr = new FileInputStream(file);
        BufferedInputStream bin = new BufferedInputStream(fr,BUFFER_SIZE);
        DataInputStream din=new DataInputStream(bin);  
        boolean fileComplete = false;
        
        while (!fileComplete) {
            int index = buffer.length;
            for (int i = 0; i < buffer.length && !fileComplete; i++) {
                try {
                     buffer[i] = din.readInt();
                } catch (Exception e) {
                    fileComplete = true;
                    index = i;
                }
            }
            if (index != 0 && buffer[0] > -1) {
                Arrays.sort(buffer, 0, index);
                File f = new File("set" + new Random().nextInt());
         //       File temp = File.createTempFile("josp", ".tmp", f);   
                FileOutputStream writer = new FileOutputStream(f);
                BufferedOutputStream bOutputStream = new BufferedOutputStream(writer);
             
                DataOutputStream dout=new DataOutputStream(bOutputStream); 
                for (int j = 0; j < index; j++) {
                    dout.writeInt(buffer[j]);
                }
                dout.close();
                bOutputStream.close();
                writer.close();
                files.add(f);
               
            }

        }
        din.close();
        bin.close();
        fr.close();
        return files;
    }
    /**
     * 多路归并
     * @param list
     * @throws IOException
     */
    private void multipleMerge(ArrayList<File> list) throws IOException {
        
        int fileSize = list.size();
        
        if(fileSize == 1){
            return;
        }
        
        ArrayList<DataInputStream> dinlist = new ArrayList<DataInputStream>();
        
        int[] ext = new int[fileSize];//比较数组

    //    File output = new File("multipleMerged");
        FileOutputStream os = new FileOutputStream(MAIN_FILE);
        BufferedOutputStream bout = new BufferedOutputStream(os);
        DataOutputStream dout = new DataOutputStream(bout);

        for (int i = 0; i < fileSize; i++) {
            try {
                dinlist.add(i, new DataInputStream(new BufferedInputStream(
                        new FileInputStream(list.get(i)), BUFFER_SIZE)));
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        int index = 0;

        for (int i = 0; i < fileSize; i++) {
            try {
                ext[i] = dinlist.get(i).readInt();
            } catch (Exception e) {
                System.err.println("file_" + i + "为空");
                ext[i] = -1;
            }
        }
        int count = fileSize;
        int[] sum = new int[fileSize];
        
        while (count > 1) {

            index = getMinIndex(ext);
            dout.writeInt(ext[index]);
            sum[index]++;
            try {
                ext[index] = dinlist.get(index).readInt();
            } catch (Exception e) {
                ext[index] = -1;
                count--;
                dinlist.get(index).close();
        //        System.err.println(index + "空,写进:" +sum[index]);
                
            }
        }
        int sIndex = getSIndex(ext);
        dout.writeInt(ext[sIndex]);
        while (true) {
            try {
                dout.writeInt(dinlist.get(sIndex).readInt());
            } catch (Exception e) {
                dinlist.get(sIndex).close();
                break;
            }
        }
        dout.close();
    }
    //找到剩下的最后一个文件输入流
    public int getSIndex(int[] ext){
        int result = 0;
        for (int i = 0; i < ext.length; i++) {
            if(ext[i]!= -1){
                result = i;
                break;
            }
        }
        return result;
    }
    //找到数据中最小的一个
    public int getMinIndex(int[] ext){
        int min = 2147483647;
        int index = -1;
        for (int i = 0; i < ext.length; i++) {
            if(ext[i] != -1 && ext[i] < min){
                min = ext[i];
                index = i;
            }
        }
        return index;
    }
    /**
     * 二路归并
     * 
     * @param one
     * @param two
     * @return
     * @throws IOException
     */
    private File merge(File one, File two) throws IOException {
        FileInputStream fis1 = new FileInputStream(one);
        FileInputStream fis2 = new FileInputStream(two);
        BufferedInputStream bin1 = new BufferedInputStream(fis1,BUFFER_SIZE);
        BufferedInputStream bin2 = new BufferedInputStream(fis2,BUFFER_SIZE);
        
        DataInputStream din1=new DataInputStream(bin1);  
        DataInputStream din2=new DataInputStream(bin2);  
        
        File output = new File("merged" + new Random().nextInt());
        FileOutputStream os = new FileOutputStream(output);
        BufferedOutputStream bout = new BufferedOutputStream(os);
        DataOutputStream dout=new DataOutputStream(bout); 
   
        int a = -1;//= din1.readInt();
        int b = -1;//= din2.readInt();
        
        boolean finished = false;
        boolean emptyA = false;//
        int flag = 0;
        while (!finished) {

            if (flag != 1) {
                try {
                    a = din1.readInt();
                } catch (Exception e) {
                    emptyA = true;
                    break;
                }
            }
            if (flag != 2) {
                try {
                    b = din2.readInt();
                } catch (Exception e) {
                    emptyA = false;
                    break;
                }
            }
            if(a > b){
                dout.writeInt(b);
                flag = 1;
            }else if( a < b){
                dout.writeInt(a);
                flag = 2;
            }else if(a == b){
                dout.write(a);
                dout.write(b);
                flag = 0;
            }
        }
        finished = false;
        if(emptyA){
            dout.writeInt(b);
            while(!finished){
                try {
                    b = din2.readInt();
                } catch (Exception e) {
                    break;
                }
                dout.writeInt(b);
            }
        }else{
            dout.writeInt(a);
            while(!finished){
                try {
                    a = din1.readInt();
                } catch (Exception e) {
                    break;
                }
                dout.writeInt(a);
            }
        }
        dout.close();
        os.close();
        bin1.close();
        bin2.close();
        bout.close();
        return output;
    }

 

  

    /**
     * @param args
     * @throws IOException
     */
    public static void main(String[] args) throws IOException {
              
        Random random = new Random(System.currentTimeMillis());
        FileOutputStream fw = new FileOutputStream(MAIN_FILE);
        BufferedOutputStream bout = new BufferedOutputStream(fw);
        DataOutputStream dout=new DataOutputStream(bout);  
        
        for (int i = 0; i < ITEM_COUNT; i++) {
            int ger = random.nextInt();
            ger = ger < 0 ? -ger : ger;
            dout.writeInt(ger);

        }
        dout.close();
        bout.close();
        fw.close();
        ExternalSort sort = new ExternalSort();
        System.out.println("Original:");

        long start = System.currentTimeMillis();
        sort.mSort(MAIN_FILE);
       
        
        long end = System.currentTimeMillis();
        System.out.println((end - start)/1000 + "s");
        recordFile((end - start)/1000 ,true);
    }

    private static void recordFile(long time,boolean isBuffer)
            throws FileNotFoundException, IOException {
        BufferedWriter bw = new BufferedWriter(new FileWriter("log",true));
        bw.write("FILE_COUNT = "+FILE_COUNT+";对"+ ITEM_COUNT + "条数据 "+ ITEM_COUNT*4/(1024*1204) +"MB排序耗时:" + time + "s ");
        if(isBuffer){
            bw.write("  使用缓冲:"+BUFFER_SIZE*4/(1024*1204) +"MB");
        }
        bw.newLine();
        bw.close();
    }

}



另一篇采用新IO实现的

http://www.oschina.net/code/snippet_1386372_48711#70574


目录
相关文章
|
5月前
|
Unix 程序员 Linux
【OSTEP】动态内存开辟 | 内存API常见错误 | UNIX: brk/sbrk 系统调用 | mmap创建匿名映射区域 | mmap创建以文件为基础的映射区域
【OSTEP】动态内存开辟 | 内存API常见错误 | UNIX: brk/sbrk 系统调用 | mmap创建匿名映射区域 | mmap创建以文件为基础的映射区域
175 0
|
3月前
|
存储 缓存 Java
释放C盘空间:释放Windows休眠文件和关闭虚拟内存
在 Windows 11 专业版中,可以通过以下步骤来释放休眠文件(Hibernate File),以释放磁盘空间。休眠文件是系统休眠(Hibernate)功能所需要的文件,它保存了系统的当前状态,以便在休眠状态下恢复。如果你不使用休眠功能,如果因为C盘空间不足,可以考虑释放这个文件来腾出磁盘空间。
3544 0
|
6月前
|
Linux Go API
MemoryModule内存反射DLL加载探索
MemoryModule内存反射DLL加载探索
|
3月前
|
人工智能 算法 BI
【经典问题】给两个文件,分别有100亿个整数,我们只有1G内存,如何找到两个文件交集?
【1月更文挑战第26天】【经典问题】给两个文件,分别有100亿个整数,我们只有1G内存,如何找到两个文件交集?
|
3月前
|
存储 编译器 C语言
learn_C_deep_10 extern在多文件下的理解、struct 关键字的理解与柔性数组、union 的内存级布局理解、enum 关键字的基本理解、typedef 的理解与分类、关键字总结
learn_C_deep_10 extern在多文件下的理解、struct 关键字的理解与柔性数组、union 的内存级布局理解、enum 关键字的基本理解、typedef 的理解与分类、关键字总结
|
3月前
|
移动开发 安全 图形学
如何绕过某讯手游保护系统并从内存中获取Unity3D引擎的Dll文件
如何绕过某讯手游保护系统并从内存中获取Unity3D引擎的Dll文件
28 0
|
9月前
|
Linux C++
C++可执行目标文件内存分区
我们知道链接器可以将多个目标文件合并成一个可执行目标文件,其中可执行目标文件又可以分为很多个段,本期将简单讲解Linux下C++的内存分段及各段所存放的内容。
C++可执行目标文件内存分区
|
4月前
|
移动开发 安全 图形学
如何绕过某讯手游保护系统并从内存中获取Unity3D引擎的Dll文件
通过动态分析了它的保护方法,通过改源码刷机的方法绕过了它的保护方案(也可通过hook libc.so中的execve函数绕过保护),接下来就可以直接使用GameGuardain这个神奇附加上去进行各种骚操作了。这里主要讲一下如何去从内存中获取Assembly-CSharp.dll 和 Assembly-CSharp-fristpass.dll文件。
|
5月前
|
存储 缓存 NoSQL
轻松突破文件IO瓶颈:内存映射mmap技术
轻松突破文件IO瓶颈:内存映射mmap技术
|
5月前
|
缓存 Java 数据库
Springboot项目启动时加载数据库数据到内存
Springboot项目启动时加载数据库数据到内存

热门文章

最新文章