我有一个实体列表,为了进行分析,实体可以处于三种状态之一。当然我希望它只有两个州,然后我可以用一个布尔代表那个。
在大多数情况下,将有一个实体列表,其中列表的大小通常为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
答案 0 :(得分:0)
简单的数学说:
3个州的3个实体共有27个组合。 因此,您需要准确的log(27)/ log(2)= ~4.75位来存储该信息。
因为pc只能使用整个位,所以你需要“浪费”~0.25位,每个组合使用5位。
您收集的数据越多,您收集信息的效果就越好,但最终,压缩算法可能会提供更多帮助。
再说一遍:你只询问内存效率,而不是性能。
通常,您可以通过Math.Log计算所需的位数(Math.Ceil(noCombinations),2)。
答案 1 :(得分:0)
我认为你可以按照以下方式解决这个问题:
因此,您似乎可以将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;
}