`
iwindyforest
  • 浏览: 235046 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

利用归并排序算法对大文件进行排序

阅读更多

 

归并排序算法介绍,请参照Wikipeida

zh.wikipedia.org/wiki/%E5%BD%92%E5%B9%B6%E6%8E%92%E5%BA%8F

基本思想:

大文件分割成行数相等的两个子文件,递归(归并排序)两个子文件,直到递归到分割成的子文件低于限制行数

低于限制行数的子文件直接排序

两个排序好的子文件归并到父文件

直到最后所有排序好的父文件归并到输入的大文件并返回

 

之前看了网上很多示例代码,写的很不简洁, 引入了过多的临时变量i, j, k等等, 导致程序基本没法看,

只好自己写了一个,没有很关心执行效率, 只求够用,以后有机会再优化一下吧。

 

Performance:

输入999999行 on
Intel(R) Core(TM)2 Duo CPU @ 2.66GHz 硬盘 5400转

cost: 8951 MILLISECONDS

cost: 8 MICROSECONDS per line

 

JDK要求

Java 8

 

package com.java.sort.merge;

import com.google.common.base.Charsets;
import com.google.common.base.Stopwatch;
import com.google.common.base.Strings;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterators;
import com.google.common.collect.PeekingIterator;
import com.google.common.io.Files;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.io.filefilter.AndFileFilter;
import org.apache.commons.io.filefilter.PrefixFileFilter;
import org.apache.commons.io.filefilter.SuffixFileFilter;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;

import java.io.*;
import java.util.Iterator;
import java.util.TreeSet;
import java.util.concurrent.TimeUnit;
import java.util.stream.Stream;


public class FileMergeSort {
    private static final Logger log = LogManager.getLogger();
    private static final long total = 999999L;
    private static final int limit = 99999;

    private static void cleanTempFiles() {
        FilenameFilter filter = new AndFileFilter(ImmutableList.of(new PrefixFileFilter("sort"), new SuffixFileFilter(".part")));
        ImmutableList.copyOf(FileUtils.getTempDirectory().listFiles(filter)).forEach(File::delete);
    }

    private static long lineNumber(File input) throws IOException {
        try (Stream<String> stream = Files.newReader(input, Charsets.UTF_8).lines()) {
            return stream.count();
        }
    }

    private static File split(File input, long from, long to) throws IOException {
        File part = File.createTempFile("sort", ".part");
        long lineNumber = 0L;
        String line = null;
        try (Stream<String> stream = Files.newReader(input, Charsets.UTF_8).lines();
             Writer writer = Files.newWriter(part, Charsets.UTF_8)) {
            Iterator<String> lineIterator = stream.iterator();
            while (lineIterator.hasNext() && lineNumber <= to) {
                line = lineIterator.next();
                if (lineNumber >= from) {
                    writer.write(line.concat(IOUtils.LINE_SEPARATOR));
                }
                lineNumber++;
            }
        }
        return part;
    }

    private static File merge(File source, File left, File right) throws IOException {
        try (Stream<String> leftStream = Files.newReader(left, Charsets.UTF_8).lines();
             Stream<String> rightStream = Files.newReader(right, Charsets.UTF_8).lines();
             Writer writer = Files.newWriter(source, Charsets.UTF_8)) {
            PeekingIterator<String> leftPeekingIterator = Iterators.peekingIterator(leftStream.iterator());
            PeekingIterator<String> rightPeekingIterator = Iterators.peekingIterator(rightStream.iterator());
            String leftLine, rightLine;
            writer.write("");
            while (leftPeekingIterator.hasNext() && rightPeekingIterator.hasNext()) {
                leftLine = leftPeekingIterator.peek();
                rightLine = rightPeekingIterator.peek();
                if (leftLine.compareTo(rightLine) < 0) {
                    writer.append(leftLine.concat(IOUtils.LINE_SEPARATOR));
                    leftPeekingIterator.next();
                } else {
                    writer.append(rightLine.concat(IOUtils.LINE_SEPARATOR));
                    rightPeekingIterator.next();
                }
            }
            while (leftPeekingIterator.hasNext()) {
                writer.append(leftPeekingIterator.next().concat(IOUtils.LINE_SEPARATOR));
            }
            while (rightPeekingIterator.hasNext()) {
                writer.append(rightPeekingIterator.next().concat(IOUtils.LINE_SEPARATOR));
            }
        }
        return source;
    }

    private static File inMemorySort(File input) throws IOException {
        TreeSet<String> lines = new TreeSet<>(String::compareTo);
        try (BufferedReader reader = Files.newReader(input, Charsets.UTF_8);) {
            String line;
            while ((line = reader.readLine()) != null) {
                lines.add(line);
            }
        }
        FileUtils.writeLines(input, lines);
        return input;
    }

    public static File mergeSort(File input) throws IOException {
        long total = lineNumber(input);
        if (total <= limit) {
            return inMemorySort(input);
        }
        long half = total / 2L;
        File left = mergeSort(split(input, 0, half));
        File right = mergeSort(split(input, half + 1, total));
        return merge(input, left, right);
    }


    @BeforeClass
    public static void init() throws IOException {
        cleanTempFiles();
        int minLength = String.valueOf(total).length();
        try (Writer writer = Files.newWriter(new File("z:\\long.txt"), Charsets.UTF_8)) {
            writer.write("");
            for (long i = total; i > 0L; i--) {
                writer.append(Strings.padStart(String.valueOf(i), minLength, '0').concat(IOUtils.LINE_SEPARATOR));
            }
        }
    }

    @AfterClass
    public static void clean() {
        cleanTempFiles();
    }

    @Test
    public void testSort() throws IOException {
        Stopwatch watch = Stopwatch.createStarted();
        File sorted = mergeSort(new File("z:\\long.txt"));
        watch.stop();
        log.info(String.format("cost: %s MILLISECONDS", watch.elapsed(TimeUnit.MILLISECONDS)));
        log.info(String.format("cost: %s MICROSECONDS per line", watch.elapsed(TimeUnit.MICROSECONDS) / total));
    }

}

 

 

 

 

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.java.app</groupId>
    <artifactId>sample</artifactId>
    <version>1.0-SNAPSHOT</version>

    <dependencies>
        <dependency>
            <groupId>commons-io</groupId>
            <artifactId>commons-io</artifactId>
            <version>2.4</version>
        </dependency>       
        <dependency>
            <groupId>com.google.guava</groupId>
            <artifactId>guava</artifactId>
            <version>18.0</version>
        </dependency>        
        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-api</artifactId>
            <version>2.1</version>
        </dependency>
        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-core</artifactId>
            <version>2.1</version>
        </dependency>
        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-jcl</artifactId>
            <version>2.1</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>
    </dependencies>
</project>

 

1
0
分享到:
评论

相关推荐

    C++实现希尔、快速、堆排序、归并排序算法

    本文将详细介绍C++中实现的希尔排序、快速排序、堆排序和归并排序这四种经典排序算法。 希尔排序,由Donald Shell于1959年提出,是一种改进的插入排序。它的基本思想是通过设置一个增量序列,将待排序的元素按照...

    归并排序算法实现(排序算法系列1)

    归并排序是一种高效的、稳定的排序算法,由著名计算机科学家John W. Backus在1946年提出。它是基于分治策略的一种经典算法,适用于处理大量数据。在本系列的第一部分,我们将深入探讨归并排序的基本原理、实现过程...

    归并排序算法实现

    归并排序是一种经典的排序算法,采用分治法的思想,将待排序数组分为若干个子序列,这些子序列是已排序的,然后再按照一定的方式合并这些子序列得到最终排序后的数组。归并排序在实际应用中非常广泛,尤其在处理大...

    四种算法实现排序

    这里我们将详细讨论四种常见的排序算法:冒泡排序、简单选择排序、归并排序和堆排序,以及它们在C#语言中的实现。 1. **冒泡排序**: 冒泡排序是一种简单的交换排序,它通过不断比较相邻元素并交换位置来逐步排序...

    7大排序算法实现程序(快速排序,冒泡排序,选择排序,归并排序,插入排序,希尔排序,堆排序)

    本资源提供了七大经典排序算法的实现程序,包括快速排序、冒泡排序、选择排序、归并排序、插入排序、希尔排序和堆排序。下面将逐一详细介绍这些排序算法及其原理。 1. 快速排序:由C.A.R. Hoare提出,是一种采用...

    数据结构堆排序 快速排序 归并排序

    首先,堆排序是一种基于比较的排序算法,利用了二叉堆的数据结构。二叉堆是一个完全二叉树,可以分为最大堆或最小堆,其中每个父节点的值都大于或等于其子节点。堆排序的过程包括构建初始堆和调整堆。首先,将无序...

    根号n段归并排序算法

    根号n段归并排序是一种优化过的归并排序算法,主要针对大数组的排序场景,其核心思想是将数组分成更小的段,每段的大小大约为根号n(向下取整)。这个方法旨在减少合并操作的次数,因为归并排序在合并过程中通常会...

    快速排序与归并排序的算法比较实验报告

    这篇实验报告将深入探讨两种经典的排序算法——快速排序和归并排序,通过对它们在Java环境中的实现和性能测试,揭示它们在处理不同规模数据时的效率差异。 **快速排序(Quick Sort)** 快速排序由C.A.R. Hoare在...

    归并排序(Merge sort)(台灣譯作:合併排序)是建立在归并操作上的一种有效的排序算法。该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。

    归并排序(Merge Sort)是一种基于分治策略的高效排序算法,由计算机科学家John W. Backus于1945年提出。它的工作原理可以分为三个主要步骤:分解、解决和合并。 1. 分解:将原始数据序列分成两个相等(或接近相等...

    MATLAB实现插入排序、二分归并排序、归并排序.rar

    在本资源中,我们主要关注的是使用MATLAB编程语言实现三种经典的排序算法:插入排序、二分归并排序以及归并排序。这些算法是计算机科学基础中的重要组成部分,特别是在算法设计与分析领域。MATLAB是一种强大的数值...

    C语言二路归并排序算法

    归并排序是一种高效的排序算法,其基本思想是采用分治法(Divide and Conquer),将一个数组分成两个子数组,然后递归地对这两个子数组进行排序,最后将两个有序的子数组合并成一个有序数组。本篇介绍一种具体的实现...

    7种常用排序算法实现(C++)(冒泡排序、选择排序、直接插入排序、希尔排序、堆排序、归并排序以及快速排序)

    在计算机科学中,排序算法是数据处理的重要组成部分,它们用于将一组无序的数据按照特定顺序进行排列。这里我们将深入探讨七种常用的排序算法,并通过C++语言实现它们。这七种算法分别是:冒泡排序、选择排序、直接...

    归并排序算法(计算机算法与分析)

    总的来说,归并排序算法是一种基于分治策略的排序方法,它通过递归或迭代的方式将数组分为两半,对每一半进行排序,然后将结果合并。其时间复杂度为O(n log n),适用于处理大数据量的排序任务。程序中的实现清晰地...

    快速排序算法以及归并算法

    根据给定的文件信息,我们将深入探讨两种经典的排序算法——快速排序和归并排序,并结合Java语言实现进行详细解析。 ### 快速排序算法 快速排序是一种高效的排序算法,采用分而治之的策略,其核心思想是选择一个...

    数据库系统实现-两阶段多路归并排序算法的C实现

    然后,对每个块进行内部排序,可以使用快速排序、插入排序等简单的排序算法。接着,将相邻的已排序块两两合并,形成更大的已排序块。这个过程持续进行,直到只剩下一个包含所有数据的大块。 2. **第二阶段:多路...

    算法设计实验报告-快速排序和归并排序

    **算法设计实验报告** 在计算机科学中,排序是数据处理中的基本...通过本实验报告,读者不仅能掌握快速排序和归并排序的基本原理,还能通过实践提升对算法设计与分析的理解,为进一步深入学习和应用排序算法奠定基础。

    直接插入排序 冒泡排序 快速排序 直接选择排序 堆排序 二路归并排序 C#源代码

    直接插入排序、冒泡排序、快速排序、直接选择排序、堆排序和二路归并排序是计算机科学中经典的排序算法,它们在数据处理和算法学习中占有重要地位。这些排序算法各有特点,适用场景不同,下面将逐一详细介绍,并结合...

    给定一个数列,用归并排序算法把它排成升序。

    ### 归并排序算法知识点...- 在分布式计算环境中对多个节点上的数据进行合并排序。 - 文件系统中的排序操作等。 综上所述,归并排序是一种非常实用且高效的排序算法,在计算机科学和软件工程领域有着广泛的应用前景。

Global site tag (gtag.js) - Google Analytics