我正在开展一个项目,在某个时刻我需要展示一个月哪些日子仍然可用。有一个函数可以计算可用的天数。我的同事说:“哦,我们知道,你应该返回一个BitVector32
。这在使用布尔列表时效率最高。”我会使用List<bool>
或类似的东西。当你实际使用位时,BitVector32
似乎是低级别的东西。
所以,问题是。如果你需要一些少于32项的布尔值列表,你应该使用BitVector32
,还是只将它用于低级别的东西?
答案 0 :(得分:3)
使用List很容易扩展到其他时间段。假设您想一次显示两个月。哦,这比32大。我需要改变返回类型和它使用的任何地方。大!而BitVector32
甚至没有实施IEnumerable<T>
。
除非它具有紧密的循环可读性和可维护性,否则效率最高。列表分配的开销并不大,除非你每秒做一百万次。
所以我同意你的看法,你应该只将BitVector32用于低级代码。
答案 1 :(得分:2)
BitVector32是一个围绕c#位操作的包装器(或者你可以称之为抽象)。例如,以下两个语句返回相同的结果:
假设有一个包含一些重复数字的整数数组。我们想要找到所有重复项。当然,您只需在Linq中使用GroupBy函数,但让我们假装我们没有Linq。
第一个选项是强力逼近方法,其中每个元素将与给定数组中的每个元素进行比较:
foreach(int i in list)
{
foreach(int j in list)
{
if (i == j)
{
// print this or store it in the result list
}
}
}
由于蛮力方法将导致N平方运行时间,这是非常低效的,我们可以考虑使用HashSet,它将提供一个恒定的查找时间或O(1)
HashSet<int> hashSet = new HashSet<int>();
foreach(int i in list)
{
if (hashSet.Contains(i))
{
// print the duplicate or add it to the result list
}
else
{
hashSet.Add(i);
}
}
这种方法将导致线性运行时间或O(n)。但是,它需要额外的n * 4字节内存(假设我们正在讨论32位整数)
第三种方法类似于使用散列集,除了使用布尔数组需要更少的内存
bool[] masks = new bool[list.Length];
for (int i = 0; i < list.length; i++)
{
if (masks[list[i]])
{
// print or add to the result list
}
else
{
masks[list[i]] = true;
}
}
它使用布尔数组而不是HashSet。它具有相同的运行时间,即O(n),但需要1/4量的内存,因为bool类型占用1个字节(8位),而整数占用4个字节(32位)
最后,我们可以使用BitVector32类或本机位移操作来解决这个问题。
int check = 0;
for (int i=0; i < list.Length; i++)
{
int mask = 1 << list[i];
if (check & mask == mask)
{
// print or add list[i] to the result list
}
else
{
check = check | mask;
}
}
它还将导致线性运行时间,总共只有32位内存。所以内存使用量是n / 32。当然,如果数组中的最大值大于32,则不会起作用。我们可以使用64位无符号整数来增加掩码中的插槽数,但它仍然有一个非常短的限制。在这种情况下,如果您创建一个 BitVectory32 数组,则可以将该位移到数组的下一个索引中的 BitVector32 对象。例如,代码将类似于下面的
BitVector32[] bitVectorArray = new BitVector32[maxValue / 32];
bitVectorArray[list[i] / 32] = 1 << list[i] % 32;
这样,您不必限制为32位大小限制。只要内存容量允许,您就可以无限期地增大大面具的大小。所以,把所有东西放在一起:
// This code assumes you know the range of the number in the array
BitVector32[] bitVectorArray = new BitVector32[maxValue / 32];
for (int i=0; i < list.Length; i++)
{
int mask = 1 << list[i] % 32;
if (bitVectorArray[(list[i] - 1)/32][i] & mask == mask)
{
// print or add list[i] to the result list
}
else
{
bitVectorArray[(list[i] - 1)/32] = bitVectorArray[list[i] / 32] | mask;
}
}