我什么时候应该使用BitVector32?

时间:2011-02-23 17:16:04

标签: .net boolean base-class-library bitvector

我正在开展一个项目,在某个时刻我需要展示一个月哪些日子仍然可用。有一个函数可以计算可用的天数。我的同事说:“哦,我们知道,你应该返回一个BitVector32。这在使用布尔列表时效率最高。”我会使用List<bool>或类似的东西。当你实际使用位时,BitVector32似乎是低级别的东西。

所以,问题是。如果你需要一些少于32项的布尔值列表,你应该使用BitVector32,还是只将它用于低级别的东西?

2 个答案:

答案 0 :(得分:3)

使用List很容易扩展到其他时间段。假设您想一次显示两个月。哦,这比32大。我需要改变返回类型和它使用的任何地方。大!而BitVector32甚至没有实施IEnumerable<T>

除非它具有紧密的循环可读性和可维护性,否则效率最高。列表分配的开销并不大,除非你每秒做一百万次。

所以我同意你的看法,你应该只将BitVector32用于低级代码。

答案 1 :(得分:2)

BitVector32是一个围绕c#位操作的包装器(或者你可以称之为抽象)。例如,以下两个语句返回相同的结果:

  • 1&lt;&lt; 1
  • BitVector32.CreateMask(1)

假设有一个包含一些重复数字的整数数组。我们想要找到所有重复项。当然,您只需在Linq中使用GroupBy函数,但让我们假装我们没有Linq。

  1. 第一个选项是强力逼近方法,其中每个元素将与给定数组中的每个元素进行比较:

    foreach(int i in list) 
    {
        foreach(int j in list)
        {
            if (i == j) 
            {
                // print this or store it in the result list
            }
        }
    }
    
  2. 由于蛮力方法将导致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);
        }
    }
    
  3. 这种方法将导致线性运行时间或O(n)。但是,它需要额外的n * 4字节内存(假设我们正在讨论32位整数)

    1. 第三种方法类似于使用散列集,除了使用布尔数组需要更少的内存

      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;
          }
      }
      
    2. 它使用布尔数组而不是HashSet。它具有相同的运行时间,即O(n),但需要1/4量的内存,因为bool类型占用1个字节(8位),而整数占用4个字节(32位)

      1. 最后,我们可以使用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;
            }
        }
        
      2. 它还将导致线性运行时间,总共只有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;
            }
        }