http://hi.baidu.com/qq350884961/blog/item/8eeafd4583308d89b2b7dc2c.html
对远远大于内存的数据进行外排序,在多路比较的时候用败者树效率会更高。
这个算法可以在建立倒排索引的时候使用
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://hi.baidu.com/qq350884961
*/
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;// 每个文件的记录数1
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();
}
}
分享到:
相关推荐
- 在多路平衡归并排序中,数据被划分为多个段,每个段分别在内存中进行排序,然后进行多路归并。 - 归并路数 k 决定了每次归并的段数,从而影响总的读写次数 d。k 越大,d 可能越小,但同时也可能增加内部归并的...
外部排序的一个经典案例是多路归并排序,它将数据划分为多个块,先对每个块进行内部排序,然后将这些已排序的块进行多路归并,最终得到完全排序的结果。 综上所述,排序及其基本算法是计算机科学中的核心内容,每种...
外部排序通常涉及到多路归并等技术。 2. **冒泡排序**: - 冒泡排序是最简单的排序算法之一。它通过重复遍历数组,比较相邻元素并交换位置,使较大的元素逐渐“冒”到数组末尾。每一轮遍历(称为一趟)会确保最大...
总结来说,要在1 GB内存中对100 GB数据进行排序,需要采用外部排序算法,通过磁盘与内存的交互进行数据的分块、内存内排序、多路合并等步骤,同时考虑优化策略以降低磁盘I/O成本。通过学习和实践,我们可以利用各种...
7. **B树的生成.swf**:B树是一种自平衡的多路搜索树,适合大量数据的磁盘存储。它保持数据有序,支持快速的查找、插入和删除操作。B树的高度相对较低,可以减少磁盘I/O操作。 8. **邻接表表示的图的广度优先遍历....
4. **外部排序**:当内存不足以一次性加载所有数据时,可以使用外部排序技术,将数据分块加载到内存,然后对每一块进行排序,最后再进行多路归并,找出前100个元素。这种方法适合处理远大于内存的大型数据集。 在...
13. **字节多路通道**:字节多路通道的数据宽度是不定长数据块,这意味着它能传输不同长度的数据块。 14. **存储器分段**:若每个段最多可存储32K字(16位二进制),则表示段内字节地址的二进制位数应为15位(2^15 ...
- **归并排序**:稳定排序,时间复杂度为O(n log n)。 ### UML - **概念**:统一建模语言,用于软件工程的设计和文档化。 - **用途**:包括类图、序列图、用例图等。 ### Linux常用命令 - **基本命令**:`ls`、`...
14. 排序方法的选择:在待排序文件已基本有序的前提下,归并排序是效率较高的排序方法。 15. 操作系统资源管理:操作系统对每一种资源的管理包括记录资源的使用状况、确定资源分配策略、实施资源分配、收回分配出去...
- 插入排序、快速排序、堆排序在每一趟排序结束时都会确定一个元素的最终位置,而二路归并排序在每次合并过程中并不会直接确定任何元素的最终位置。 **10. 特殊情况下的排序效率** - **选项分析**: - 当待排序的...
- **B树**:多路平衡查找树,适用于磁盘等慢速存储设备。 - **B+树**:B树的变体,所有数据都存储在叶子节点上。 **9. 红黑树** 红黑树是一种自平衡的二叉查找树,通过维护五个简单的性质来保证查找的高效性。 ##...