在C#中存储/比较x三元(?)值的内存有效方法

时间:2017-03-01 13:49:21

标签: c# performance processing-efficiency

我有一个实体列表,为了进行分析,实体可以处于三种状态之一。当然我希望它只有两个州,然后我可以用一个布尔代表那个。

在大多数情况下,将有一个实体列表,其中列表的大小通常为100< n< 500.

我正在分析实体和州的组合的影响。

所以如果我有1个实体,那么我可以有3个组合。如果我有两个实体,我可以有六个组合,依此类推。

由于组合的数量,暴力强制这将是不切实际的(它需要在单个系统上运行)。我的任务是找到可行的优秀但不一定是最优的解决方案。我不需要测试所有可能的排列,我只需要找到一个有效的排列。这是一个实现细节。

我需要做的是为我当前的数据集注册可能的组合 - 这基本上是为了避免重复分析每个组合的工作。每当一个进程到达某个组合配置时,它需要检查该组合是否已经在工作,或者它是否已在过去解决。

因此,如果我有三个三态值,那么在内存中存储和比较它的有效方法是什么?我意识到这里会有局限性。只是尽量提高效率。

我想不出更有效的存储单元然后是两位,其中四个“位状态”中的一个未被使用。但我不知道如何提高效率。我是否需要在优化存储大小或性能方面做出选择?

这样的事情如何在C#中建模,浪费最少的资源,并且当一个进程需要询问“这三个状态值的特定组合是否已经过测试?”时,仍然表现相对较好? / p>

编辑:举个例子,假设我只有3个实体,状态由一个简单的整数1,2或3表示。然后我们会有这个组合列表:

111 112 113 121 122 123 131 132 133 211 212 213 221 222 223 231 232 233 311 312 313 321 322 323 331 332 333

3 个答案:

答案 0 :(得分:0)

简单的数学说:

3个州的3个实体共有27个组合。 因此,您需要准确的log(27)/ log(2)= ~4.75位来存储该信息。

因为pc只能使用整个位,所以你需要“浪费”~0.25位,每个组合使用5位。

您收集的数据越多,您收集信息的效果就越好,但最终,压缩算法可能会提供更多帮助。

再说一遍:你只询问内存效率,而不是性能。

通常,您可以通过Math.Log计算所需的位数(Math.Ceil(noCombinations),2)。

答案 1 :(得分:0)

我认为你可以按照以下方式解决这个问题:

  1. 您有一组N个实体,每个实体可以有三种不同的状态之一。
  2. 鉴于这N个实体的状态有一个特定的排列,你 我想要记住你已经处理了这种排列。
  3. 因此,您似乎可以将N个实体视为3位数的基数3。

    当考虑N个实体的一组特定状态时,可以将其存储为N个字节的数组,其中每个字节的值可以是0,1或2,对应于三种可能的状态。

    这不是一种以内存效率的方式存储某个特定排列的状态,但这样做没问题,因为您不需要存储该数组。你只需要在与该排列相对应的位置存储一个位。

    因此,您可以做的是将字节数组转换为基数为10的数字,您可以将其用作BitArray的索引。然后使用BitArray来记住是否已处理特定的状态排列。

    要将表示基数为3的字节数组转换为十进制数,可以使用以下代码:

    public static int ToBase10(byte[] entityStates)  // Each state can be 0, 1 or 2.
    {
        int result = 0;
    
        for (int i = 0, n = 1; i < entityStates.Length; n *= 3, ++i)
            result += n * entityStates[i];
    
        return result;
    }
    

    鉴于您有numEntities个不同的实体,您可以像这样创建BitArray

    int numEntities = 4;
    int numPerms = (int)Math.Pow(numEntities, 3);
    BitArray states = new BitArray(numPerms);
    

    然后states可以为所有实体的每种可能的状态排列存储一点。

    假设您有4个实体A,B,C和D,并且您具有状态排列(将为0,1或2),如下所示:A2 B1 C0 D1。也就是说,实体A具有状态2,B具有状态1,C具有状态0并且D具有状态1。

    您可以将其表示为类似的布尔数组:

    byte[] permutation = { 2, 1, 0, 1 };
    

    然后您可以将其转换为基数为10的数字,如下所示:

    int asBase10 = ToBase10(permutation);
    

    然后你可以检查是否已经像这样处理了这种排列:

    if (!bits[permAsBase10])
    {
        // Not processed, so process it.
    
        process(permutation);
    
        bits[permAsBase10] = true; // Remember that we processed it.
    }
    

答案 2 :(得分:0)

不要过度使用算法和数据结构,并假设您的三态值可以用字符串表示,并且没有容易确定的修复最大值。即。 “111”,“112”等(或甚至“1:1:1”,“1:1:2”)然后一个简单的SortedSet可能最终效率很高。

作为奖励,它不关心您集合中的值的数量。

SortedSet<string> alreadyTried = new SortedSet<string>();

if(!HasSetBeenTried("1:1:1"){   
    // do whatever  
}

if(!HasSetBeenTried("500:212:100"){   
    // do whatever  
}

public bool HasSetBeenTried(string set){
    if(alreadyTried.Contains(set)) return false;
    alreadyTried.Add(set);
    return true;
}