一组缩短的整数

时间:2011-12-20 00:44:56

标签: c# memory collections compression

为了避免发明热水,我在这里问......

我有一个包含大量数组的应用程序,而且内存不足。

所以我的想法是将List<int>压缩到其他东西,这将具有相同的接口(例如IList<T>),但我可以使用更短的整数代替int

例如,如果我的值范围是0 - 100.000.000,我只需要ln2(1000000)= 20位。因此,不是存储32位,而是可以减少多余的内存并将内存需求降低12/32 = 37.5%。

你知道这种数组的实现吗? c ++和java也可以,因为我可以很容易地将它们转换为c#。

附加要求(因为每个人都开始让我理解这个想法):

  • 列表中的整数是唯一的
  • 它们没有特殊属性,因此它们不能以任何其他方式压缩,然后减少位数
  • 如果值范围是一百万例如,列表的大小将是2到1000个元素,但会有很多,所以没有BitSets
  • 新数据容器应该像可重新调整大小的数组(关于方法O() - ness)

编辑:

请不要告诉我不要这样做。对此的要求经过深思熟虑,并且它是唯一的选择。

此外,1M的值范围和20位仅为示例。我的案例具有所有不同的范围和整数大小。

另外,我甚至可以有更短的整数,例如7位整数,然后打包

00000001
11111122
22222333
33334444
444.....

表示前4个元素,打包成5个字节。


几乎完成编码 - 将很快发布......

4 个答案:

答案 0 :(得分:3)

由于你只能在字节量子中分配内存,所以你实际上是在询问是否/如何使用3个字节而不是4个字符来拟合整数(但请参见下面的#3)。这不是一个好主意

  1. 由于没有3字节大小的整数类型,您需要在其位置使用其他内容(例如,不透明的3字节缓冲区)。这将要求您在执行转换的代码中包装对列表内容的所有访问权限,以便您仍然可以将“ints”放入并拉出“ints”。
  2. 根据体系结构和内存分配器的不同,请求3字节块可能根本不会影响程序的内存占用(可能只是在堆中乱丢1个字节的“漏洞”)。
  3. 从头开始重新实现列表以使用不透明的字节数组作为其后备存储将避免前两个问题(并且它还可以让你挤压每一个内存而不是整个字节),但这是一个很高的顺序并且很容易出错。
  4. 您可能希望尝试以下方式:

    • 不会将所有这些数据同时保存在内存中。每个int 4个字节,在内存耗尽之前,你需要达到数亿个整数。为什么你需要同时使用所有这些?
    • 如果可能,通过不存储重复项来压缩数据集。如果你达到数亿,那肯定会有一些。
    • 如果可能,更改数据结构以便存储连续值(增量)之间的差异。这可能不是很难实现,但是你只能实际地期望在50%的改进(可能还不够)的情况下做出一些事情并且它将完全破坏你在索引列表中的能力恒定的时间。

答案 1 :(得分:1)

从32位到24位的一个选项是创建一个存储3字节内的整数的自定义结构:

public struct Entry {
    byte b1; // low
    byte b2; // middle
    byte b3; // high

    public void Set(int x) {
        b1 = (byte)x;
        b2 = (byte)(x >> 8);
        b3 = (byte)(x >> 16);
    }

    public int Get() {
        return (b3 << 16) | (b2 << 8) | b1;
    }
}

然后,您只需创建List<Entry>

var list = new List<Entry>();
var e = new Entry();
e.Set(12312);
list.Add(e);
Console.WriteLine(list[0].Get()); // outputs 12312

答案 2 :(得分:1)

这让我想起了base64和类似的binary-to-text encoding。 它们占用8位字节,然后进行一些bit-fiddling将它们打包成4位,5位或6位可打印字符。 这也让我想起了Zork标准信息交换代码(ZSCII),它将3个字母打包成2个字节,每个字母占5位。 听起来你想要取一堆10位或20位整数并将它们打包成8位字节的缓冲区。

源代码可用于处理单个位的打包数组的许多库 (a b c d e)。

也许你可以 (a)下载该源代码并修改源代码(从某些BitArray或其他打包编码开始),重新编译以创建一个新的库来处理打包和解包10位或20位整数而不是单个位。 它可能需要更少的编程和测试时间 (b)编写一个库,从外部看起来像(a)一样,但在内部它将20位整数分成20个独立的位,然后使用(未修改的)BitArray类存储它们。

答案 3 :(得分:0)

编辑:鉴于您的整数是唯一的,您可以执行以下操作:存储唯一的整数,直到您存储的整数数量是最大数量的一半。然后切换到存储您没有的整数。这将使存储空间减少50%。

在尝试使用20位整数之前,可能值得探索其他简化技术。

如何处理重复的整数?如果有大量重复项,则可以通过将整数存储在Dictionary<int, int>中来减少存储大小,其中键是唯一的整数,值是相应的计数。请注意,这假设您不关心整数的顺序。

你的整数是否都是唯一的?也许你在0到100 mil的范围内存储了很多独特的整数。在这种情况下,您可以尝试存储您没有的整数。然后在确定您是否有整数i时,只询问它是否在您的收藏中。