【发布时间】:2014-05-14 07:49:32
【问题描述】:
我有一个 512 个字符的字符串,其中仅包含 0、1。我试图将其表示为可以节省空间的数据结构。 BitArray 是最有效的方式吗?
我也在考虑使用 16 int32 来存储数字,那么它将是 16 * 4 = 64 字节。
【问题讨论】:
-
为什么不把它解析成
BigInteger?
我有一个 512 个字符的字符串,其中仅包含 0、1。我试图将其表示为可以节省空间的数据结构。 BitArray 是最有效的方式吗?
我也在考虑使用 16 int32 来存储数字,那么它将是 16 * 4 = 64 字节。
【问题讨论】:
BigInteger?
最有效的方法是拥有八个 UInt64/ulong 或 Int64/long 类型变量(或单个数组),尽管这对于查询/设置可能不是最佳的。实际上,解决此问题的一种方法是使用BitArray(它基本上是前一种方法的包装,包括额外的开销[1])。无论是方便使用还是高效存储都是一个选择问题。
如果这还不够,您始终可以选择应用压缩,例如 RLE 编码或各种其他广泛可用的编码方法(gzip/bzip/等...)。不过,这将需要额外的处理能力。
这取决于你对高效的定义。
[1] 额外的开销,如存储开销。 BitArray 在内部使用Int32-array 来存储值。除此之外,BitArray 还存储其当前的变异版本、“分配”的整数数量和一个同步根。即使少量值的开销可以忽略不计,但如果您将大量这些值保留在内存中,这可能会成为问题。
【讨论】:
BitArray 要求的“额外开销”?您的意思是 BitArray 需要更多内存或存储空间吗?或者操作 BitArray 比使用 long[] 做同样的事情要慢?
使用 .NET 中的 BigInteger。它可以轻松支持 512 位数字以及对这些数字的操作。
BigInteger.Parse("your huge number");
【讨论】:
BitArray(512 位)、byte[64]、int[16]、long[8](或List<> 的变体)或BigInteger 都将比您的String 高效得多。我想说byte[] 通常是表示此类数据的最惯用/典型的方式。例如,ComputeHash 使用byte[] 和Streams 处理byte[]s,如果将此数据作为BLOB 存储在数据库中,byte[] 将是处理该数据的最自然方式。因此,使用它可能是有意义的。
另一方面,如果此数据代表一个数字,您可能会做一些像加法和减法一样的数字运算,您可能希望使用BigInteger。
这些方法的性能大致相同,因此您应该主要根据诸如有意义之类的因素来选择它们,然后再根据您的使用情况进行基准测试。
【讨论】:
最高效可能意味着许多不同的事情......
对于 1 - 使用 byte[64] 或 long[8] - 如果您不进行计算或不介意编写自己的计算。
对于 3 绝对是 BigInteger 是要走的路。您已经定义了数学函数,只需将二进制数转换为十进制表示。
编辑:听起来你不想要 BigInteger 由于大小问题......但我认为你会发现你当然必须将其解析为可枚举/产量组合您一次解析一点,而不是同时将整个数据结构保存在内存中。
话虽如此...我可以帮助您将字符串解析为 Int64 的数组...感谢 King King 提供此 linq 语句的一部分 here。
// convert string into an array of int64's
// Note that MSB is in result[0]
var result = input.Select((x, i) => i)
.Where(i => i % 64 == 0)
.Select(i => input.Substring(i, input.Length - i >= 64 ?
64 : input.Length - i))
.Select(x => Convert.ToUInt64(x, 2))
.ToArray();
如果您决定想要一个不同的数组结构byte[64] 或任何应该易于修改的东西。
编辑 2: 好吧,我觉得无聊,所以我写了一个 EditDifference 函数来取乐……给你……
static public int GetEditDistance(ulong[] first, ulong[] second)
{
int editDifference = 0;
var smallestArraySize = Math.Min(first.Length, second.Length);
for (var i = 0; i < smallestArraySize; i++)
{
long signedDifference;
var f = first[i];
var s = second[i];
var biggest = Math.Max(f, s);
var smallest = Math.Min(f, s);
var difference = biggest - smallest;
if (difference > long.MaxValue)
{
editDifference += 1;
signedDifference = Convert.ToInt64(difference - long.MaxValue - 1);
}
else
signedDifference = Convert.ToInt64(difference);
editDifference += Convert.ToString(signedDifference, 2)
.Count(x => x == '1');
}
// if arrays are different sizes every bit is considered to be different
var differenceOfArraySize =
Math.Max(first.Length, second.Length) - smallestArraySize;
if (differenceOfArraySize > 0)
editDifference += differenceOfArraySize * 64;
return editDifference;
}
【讨论】: