如何有效地获得数百万个未排序的浮点数的排名?

时间:2012-08-22 21:01:36

标签: java c algorithm sorting hash

2亿个花车,可能还有一些是重复的。

什么是有效的方法(例如,内存少于1G)来获取其中每个元素的排名(它们最初都是未排序的)?

像这样:

输入:[3.2,3.2,3.4,7.81,1.0]

输出:[2,2,4,5,1]

我想到了bitmap sort,但在这种情况下它看起来并没有内存效率。

5 个答案:

答案 0 :(得分:1)

我认为你不能在1G中完成所有这些工作。请注意,您的200 Mvalue数据集需要大约763 MiB,只有~261 MiB可用于辅助数据。这排除了任何需要您在与值同时存储索引的方法,因为200个Mvalues的索引至少需要28位。实际上,您真的需要32位,这将占用与原始(可能是32位)浮点值相同的空间。

要考虑的一种方法是在将决策信息记录到位图时对原始数据执行排序,然后使用排名索引替换原始数据并使用日志反转排列。

然而,在最坏的情况下,由此产生的排列将需要至少log2(N!) > N log2(N) - N log2(e)个存储位(因此无法通过使用基数排序或其他东西绕过它)。对于指定的问题,请注意log2(200M)>27,因此日志可能需要超过(200M * 25.5) / (8bits/byte) ~ 608 MiB - 几乎与原始数据集一样大,并且远大于指定的辅助空间。

您可以将决策日志写入磁盘,然后重新读取它以生成答案。但是如果你允许磁盘I / O,你也可以做一个外部排序,这样你就可以解决比内存容量大得多的问题。

答案 1 :(得分:0)

您不希望对数组进行排序,但是您希望得到一个索引数组,其中位置将在排序后进行。它需要超过1 GB的内存,你可能不得不做一些后处理来使相同的元素具有相同的等级,但你应该能够使用这个解决方案作为起点:{{3 }}

答案 2 :(得分:0)

您可以根据int值对浮动范围进行排序,例如Float.floatToRawInt(float)

如果您有1 GB并且每个值存储8个字节,则可以对最多1.28或2 ^ 27个值的组进行排序。这意味着你可以用2 ^ 5或32次传球对它们进行排名。

答案 3 :(得分:0)

您可以按照维基百科上的说明尝试External sorting

在处理浮点数据时尝试使用内存映射文件。

public static void main(String[] args) throws IOException {
    RandomAccessFile raf = new RandomAccessFile("floats.dat", "rw");
    FileChannel fc = raf.getChannel();
    MappedByteBuffer mbb = fc.map(FileChannel.MapMode.READ_WRITE, 0, 1024 * 1024 * 1024);
    FloatBuffer fb = mbb.asFloatBuffer();
    Random random = new Random();
    for (int i = 0; i < 200000000; i++) {
        float rand = random.nextFloat();
        fb.put(rand);
    }
    fb.flip();

    // Read data in chunks, tune the size
    float[] f = new float[100000];
    fb.get(f, 0, f.length);

    // Process the data using some merge strategy
}

据我所知,不应对float数组本身进行排序。使用内存映射文件存储int数组。

答案 4 :(得分:0)

如果你使用标准的Java排序方法和一个浮点数组你可以使用~1.2GB IMO,因为它已经使用了一个非常节省空间和快速(n lg(n))的排序方法(TimSortMergeSort) - 参见Arrays.sort。

为了使它更快,你可以将浮点数转换为整数(但你需要先知道精度),然后应用integer sort或已经提到的基数排序。