- 浏览: 47455 次
- 性别:
- 来自: 广州
文章分类
最新评论
-
wdl111:
好文章!
java 数组复制:System.arrayCopy 深入解析 -
threestone1026:
ibm-web-bnd.xmi 这东西有何用处
WebSphere6.1 for oracle数据源配置
纯Java实现的多路归并快速排序算法,占用内存极少,速度很快,能处理上亿条的海量数据,无任何依赖.
[代码] 纯Java实现的多路归并快速排序算法
package wjw.PreTrans; import java.io.*; import java.util.*; import org.apache.commons.io.*; public class MergeSort { private static FastQSortAlgorithm<String> QQ = new FastQSortAlgorithm<String>(); private MergeSort() { } /** * 得到指定文件的行数 * @param fileC String * @return int * @throws IOException */ private static int getFileLineSize(String fileC) throws IOException { Reader fC = null; try { fC = new FileReader(fileC); LineIterator it = IOUtils.lineIterator(fC); int lineSize = 0; while(it.hasNext()) { it.nextLine(); lineSize++; } return lineSize; } finally { IOUtils.closeQuietly(fC); } } /** * 得到下一行的内容,如果已到文件末尾返回NULL * @param iterator LineIterator * @return String */ private static String nextLine(LineIterator iterator) { if(iterator.hasNext()) { return iterator.nextLine(); } else { return null; } } /** * 读指定行数的字符串到缓冲区列表里 * @param iterator LineIterator * @param bufList List * @param lines int */ private static void readLines(LineIterator iterator, List<String> bufList, int lines) { for(int i = 0; i < lines; i++) { if(!iterator.hasNext()) { break; } bufList.add(iterator.nextLine()); } } /** * 扫描fileC中的归并段并把它们交替分别送到文件fileA和fileB中, * 本次归并段的大小为k*blockSize * @param fileA String * @param fileB String * @param fileC String * @param k int * @param blockSize int */ private static void split(String fileA, String fileB, String fileC, int k, int blockSize) throws FileNotFoundException, IOException { boolean useA = true; int i = 0; List<String> bufList = new ArrayList<String>(blockSize); //大小为blockSize的缓冲区 Writer fA = null; Writer fB = null; Reader fC = null; try { fA = new BufferedWriter(new FileWriter(fileA)); fB = new BufferedWriter(new FileWriter(fileB)); fC = new FileReader(fileC); LineIterator itC = IOUtils.lineIterator(fC); while(itC.hasNext()) { //->读入数据块 bufList.clear(); readLines(itC, bufList, blockSize); //<-读入数据块 if(useA) { IOUtils.writeLines(bufList, "\n", fA); } else { IOUtils.writeLines(bufList, "\n", fB); } if(++i == k) { i = 0; useA = !useA; } } } finally { bufList.clear(); IOUtils.closeQuietly(fA); IOUtils.closeQuietly(fB); IOUtils.closeQuietly(fC); } } /** * n为当前归并段大小(k*blockSize);将文件fX的后续归并段拷入到fY,变量currRunPos为当前归并段的索引 * @param fileX String * @param fileY String * @param currRunPos int * @param n int * @return int 当前归并段的索引 */ private static int copyTail(LineIterator fileX, Writer fileY, int currRunPos, int n) throws IOException { //从当前位置到归并段结束,拷贝每个数据 while(currRunPos <= n) { //若没有更多的数据项,则文件结束且归并段结束 if(!fileX.hasNext()) { break; } //修改当前归并段位置并将数据项写入fY currRunPos++; IOUtils.write(fileX.nextLine() + "\n", fileY); } return currRunPos; } /** * 将文件fA和fB中长度为n(k*blockSize)的归并段合并回fC中 * @param fileA String * @param fileB String * @param fileC String * @param n int * @throws IOException */ private static void merge(String fileA, String fileB, String fileC, int n) throws IOException { //currA和currB表示在当前归并段中的位置 int currA = 1; int currB = 1; //分别从fA和fB中读出的数据项 String dataA, dataB; Reader fA = null; Reader fB = null; Writer fC = null; try { fA = new FileReader(fileA); fB = new FileReader(fileB); fC = new BufferedWriter(new FileWriter(fileC)); LineIterator itA = IOUtils.lineIterator(fA); LineIterator itB = IOUtils.lineIterator(fB); dataA = nextLine(itA); dataB = nextLine(itB); for(; ; ) { //若(dataA<=dataB),则将dataA拷贝到fC并修改当前归并段的位置 if(dataA.compareTo(dataB) <= 0) { IOUtils.write(dataA + "\n", fC); //从fA中取下一归并段,若不存在,则已到文件尾,应将fB的后续归并段拷入到fC; //若当前位置>n,则已将所有fA的归并段拷完,应拷贝fB的后续归并段 dataA = nextLine(itA); currA++; if(dataA == null || currA > n) { IOUtils.write(dataB + "\n", fC); currB++; currB = copyTail(itB, fC, currB, n); //fA的大小>=fB的大小;若在fA的文件尾,则结束 if(dataA == null) { break; } else { //否则,应在新的归并段中,重置当前位置 currA = 1; } //取fB中的下一项.若不存在,则只有fA中剩余的部分要拷贝到fC, //退出循环前将当前归并段写入fC dataB = nextLine(itB); if(dataB == null) { IOUtils.write(dataA + "\n", fC); currA = 2; break; } else { //否则,重置fB中当前归并段 currB = 1; } } } else { //否则(dataA>dataB) IOUtils.write(dataB + "\n", fC); //从fB中取下一归并段,若不存在,则已到文件尾,应将fA的后续归并段拷入到fC; //若当前位置>n,则已将所有fB的归并段拷完,应拷贝fA的后续归并段 dataB = nextLine(itB); currB++; if(dataB == null || currB > n) { IOUtils.write(dataA + "\n", fC); currA++; currA = copyTail(itA, fC, currA, n); //若fB中没有更多项,则置fA的当前位置,准备拷贝fA中的最后归并段到fC中 if(dataB == null) { currA = 1; break; } else { //否则,置fB的当前位置,并从fA中读入数据 currB = 1; if((dataA = nextLine(itA)) == null) { break; } else { currA = 1; } } } } } //<- end for(; ;) //将fA中可能存在的剩余的归并段写入fC中(注:fA的长度时>=fB的) if(dataA != null && dataB == null) { currA = copyTail(itA, fC, currA, n); } } finally { IOUtils.closeQuietly(fA); IOUtils.closeQuietly(fB); IOUtils.closeQuietly(fC); } } /** * 用指定的blockSize块大小,排序指定的文件fileC * @param fileC String * @param blockSize int * @throws IOException */ /** * 用指定的blockSize块大小,排序指定的文件fileSource,排序后的文件是fileOut * @param fileSource String * @param fileOut String * @param blockSize int * @param removeDuple * @throws IOException */ public static void sort(String fileSource,String fileOut, int blockSize,boolean removeDuple) throws IOException { String fileA = File.createTempFile("wjw", null).getAbsolutePath(); String fileB = File.createTempFile("wjw", null).getAbsolutePath(); int mergeIndex = 1; int lineSize = getFileLineSize(fileSource); int k = 1; int n = k * blockSize; boolean useA = true; List<String> list = new ArrayList<String>(blockSize); Writer fA = null; Writer fB = null; Reader fC = null; try { fA = new BufferedWriter(new FileWriter(fileA)); fB = new BufferedWriter(new FileWriter(fileB)); fC = new FileReader(fileSource); LineIterator itC = IOUtils.lineIterator(fC); if(lineSize <= blockSize) { //对于小文件,从fC读入数据,直接排序后写回文件中 readLines(itC, list, lineSize); Collections.sort(list); IOUtils.closeQuietly(fC); FileUtils.writeLines(new File(fileOut), "GBK", list, "\n"); list.clear(); if(removeDuple) { removeDuple(fileOut); } return; } //->第一次分割,合并 System.out.println("第:"+mergeIndex+"分割,合并"); while(itC.hasNext()) { list.clear(); readLines(itC, list, blockSize); Collections.sort(list); if(useA) { IOUtils.writeLines(list, "\n", fA); } else { IOUtils.writeLines(list, "\n", fB); } useA = !useA; } list.clear(); IOUtils.closeQuietly(fA); IOUtils.closeQuietly(fB); IOUtils.closeQuietly(fC); merge(fileA, fileB, fileOut, blockSize); mergeIndex++; //<-第一次分割,合并 //->将当前归并段大小加倍,循环进行 k = k * 2; n = k * blockSize; while(n < lineSize) { //当n>=文件大小时,fC仅剩一个已排好序的归并段 System.out.println("第:"+mergeIndex+"分割,合并"); split(fileA, fileB, fileOut, k, blockSize); merge(fileA, fileB, fileOut, n); mergeIndex++; k = k * 2; n = k * blockSize; } //->将当前归并段大小加倍,循环进行 } finally { IOUtils.closeQuietly(fA); IOUtils.closeQuietly(fB); IOUtils.closeQuietly(fC); (new File(fileA)).delete(); (new File(fileB)).delete(); } if(removeDuple) { removeDuple(fileOut); } } /** * 删除已经排好序的文件中重复的数据 * @param fileC String * @throws IOException */ private static void removeDuple(String fileC) throws IOException { System.out.println("去重"); Reader fC = null; Writer fTemp = null; File tempFile = File.createTempFile("wjw", null); try { fC = new FileReader(fileC); fTemp = new BufferedWriter(new FileWriter(tempFile)); String tmpA = ""; String tmpB = ""; LineIterator itC = IOUtils.lineIterator(fC); while(itC.hasNext()) { tmpB = itC.nextLine(); if(tmpB.compareTo(tmpA) != 0) { IOUtils.write(tmpB + "\n", fTemp); tmpA = tmpB; } } } finally { IOUtils.closeQuietly(fTemp); IOUtils.closeQuietly(fC); } File cFile = new File(fileC); if(cFile.delete()) { if(tempFile.renameTo(cFile)) { tempFile.delete(); } } } public static String formatSecond(long seconds) { long h = seconds /(60*60); StringBuffer sb = new StringBuffer(); sb.append(h+"小时"); seconds = seconds%(60*60); long c = seconds /60; sb.append(c+"分"); sb.append(seconds %60+"秒"); return sb.toString(); } public static void main(String args[]) { try { String fileName = "d:/ESort.txt"; int blockSize = 100000; long c1 = System.currentTimeMillis(); MergeSort.sort(fileName,fileName + "_SORT", blockSize,true); long c2 = (System.currentTimeMillis() - c1) / 1000; System.out.println("耗时:"+formatSecond(c2)); } catch(IOException ex) { ex.printStackTrace(); } } }
相关推荐
JAVA中实现基数排序可以使用多路归并,先按个位排序,再按十位,直至最高位,其时间复杂度为O(kn),其中k是数字的最大位数。 5. **选择排序**:选择排序每次找到当前未排序部分的最小(或最大)元素,放到已排序...
这里我们将深入探讨一些简单的排序算法的Java实现,包括它们的基本思想、工作原理以及如何在实际代码中应用。 1. **冒泡排序**(Bubble Sort) 冒泡排序是一种基础的排序算法,通过不断交换相邻的不正确顺序的元素...
然后,为每种排序算法创建一个实现类,如`BubbleSortStrategy`、`BinarySortStrategy`(可能是快速排序或二路归并排序)和`HeapSortStrategy`。这些实现类将包含具体的排序逻辑。接着,你可以有一个`Sorter`类,它...
在Java中,我们可以使用内置的`Arrays.sort()`方法进行排序,它使用了一种称为Timsort的混合排序算法,结合了插入排序、归并排序和双路插入排序的优点,具有较好的性能保证和稳定性。 对于学习和实现排序算法,理解...
若将两个有序表合并成一个有序表,称为二路归并。时间复杂度O(n log n) 。 (6)堆排序 利用堆积树(堆)这种数据结构所设计的一种排序算法,它是选择排序的一种。可以利用数组的特点快速定位指定索引的元素。
一种常见的外部排序算法是多路归并排序(Multi-Pass Merge Sort),它通过多次的划分、排序和合并步骤,逐步减少需要排序的数据量,直到所有数据都排好序。 在Java中实现外部排序,可以创建一个BufferedReader或...
#### 4.2 Java在算法实现中的优势 - **丰富的类库**:Java拥有强大的标准类库,支持各种复杂的数据结构和算法。 - **跨平台性**:Java编写的程序可以在任何安装了Java虚拟机(JVM)的平台上运行。 - **面向对象**:...
稀疏数组、单向队列、环形队列、单向链表、双向链表、环形链表、约瑟夫...快速排序、归并排序、希尔排序、基数排序(桶排序)、堆排序、排序速度分析、二分查找、插值查找、斐波那契查找、散列、哈希表、二叉树、二叉树...
3. **排序与搜索**:排序算法包括插入排序、选择排序、交换排序(快速排序、归并排序)、堆排序、计数排序、桶排序、基数排序等,以及更高级的排序技巧如Timsort。搜索算法则有顺序搜索、二分搜索、哈希搜索等。这些...
1. **排序算法**:包括插入排序、选择排序、快速排序、归并排序、堆排序等,深入讲解了每种算法的工作原理、时间复杂度和空间复杂度,以及它们之间的比较和优化。 2. **查找算法**:介绍了线性查找、二分查找、哈希...
外部排序通常涉及到多路归并等技术。 2. **冒泡排序**: - 冒泡排序是最简单的排序算法之一。它通过重复遍历数组,比较相邻元素并交换位置,使较大的元素逐渐“冒”到数组末尾。每一轮遍历(称为一趟)会确保最大...
直接插入排序和折半插入排序是两种常见的简单...在实际应用中,通常会选择更高效的排序算法,如快速排序、归并排序或堆排序,尤其对于大规模数据。然而,这些基本排序算法对理解排序原理和算法设计思想具有重要意义。
书中会详细讨论各种排序算法(如冒泡排序、插入排序、快速排序、归并排序、堆排序等)和搜索算法(如线性搜索、二分搜索、哈希表搜索等),并分析它们的性能特性。 3. **图算法篇**:这部分会涉及图论的基础知识,...
本讨论主要聚焦于最常用的8个排序算法,包括它们的原理、优化以及在Java中的具体实现。以下是这些算法的详细介绍: 1. **插入排序**: - 基本思想:将未排序的元素逐个插入到已排序的部分,每次插入时找到合适的...
例如,在实际应用中,可以采用多路归并排序来处理大文件排序,或者通过多线程并行排序来加速排序过程。同时,还需要关注数据的特性,如是否存在大量重复数据、数据是否已经部分排序等,根据这些特性来选择或者调整...
在给定的`MergeSort.java`文件中,可能包含了实现双路归并排序算法的Java代码。通常,Java代码会定义一个类,包含分割文件、对子文件排序以及合并文件的方法。这些方法可能会使用到文件I/O操作,如`java.io`包中的`...