非冗余对列表中对象的索引
Indices of objects in a list of non-redundant pairs
我正在实现一种碰撞检测算法,该算法将所有对象之间的距离存储在单个八叉树节点中。例如,如果节点中有4个对象,则对象1&2、1&3、1&4、2&3、2&4和3&4.对总数的公式为t=n*(n-1)/2,其中t是对总数,n是节点中对象的数量。
我的问题是,如何将列表中的一个位置转换为一对对象。例如,使用上面的对列表,3将返回对2&3.
为了节省内存空间,该列表只是距离的浮动列表,而不是包含距离和指向2个对象的指针。
我不确定如何用数学方法将单个列表索引转换为一对数字。任何帮助都会很棒。我希望能够将其分解为两个函数,第一个返回对中的第一个对象,第二个返回第二个,这两个函数都有两个变量,一个是索引,另一个是节点中的总对象。如果可能的话,我想制作一个没有任何循环或递归函数的函数,因为这将为我的碰撞检测算法实时运行。
更好的排序
我建议使用colexiographical顺序,因为在这种情况下,您不必提供对象的总数。像这样订购你的鞋:
0: 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: …
0&1, 0&2, 1&2, 0&3, 1&3, 2&3, 0&4, 1&4, 2&4, 3&4, 0&5, 1&5, 2&5, 3&5, …
您可以将这个列表扩展到无限长,这样您就可以在不知道项数的情况下知道任何一对的索引。这样做的好处是,当您向数据结构中添加新项时,您只需要追加到数组中,而不需要重新定位现有项。我已经将索引调整为零基索引,因为您将问题标记为C++,所以我认为您将使用零基索引。我下面的所有答案都假设是这种排序。
您还可以像这样可视化colex排序:
a: 0 1 2 3 4 5 …
b:
1 0
2 1 2 index of
3 3 4 5 a&b
4 6 7 8 9
5 10 11 12 13 14
6 15 16 17 18 19 20
⋮ ⋮ ⋱
成对到单个索引
让我们先把一对变成一个索引。诀窍是,对于每一对,你看第二个位置,想象所有在这个位置上数量较少的对。例如,对于2&4
对,首先计算第二个数字小于4的所有对。这是从一组4(即数字0到3)中选择两个项目的可能方法的数量,因此您可以将其表示为二项式系数4C2。如果你对它进行评估,你最终会得到4(4−1)/2=6。再加上第一个数字,因为这是索引较低但第二位数字相同的对数。对于2&4
,这是2,因此2&4
的总索引为4(4−1)/2+2=8。
通常,对于一对a&b索引将为b−1)/2+a。
int index_from_pair(int a, int b) {
return b*(b - 1)/2 + a;
}
要配对的单个索引
将单个索引i变回一对数字的一种方法是增加b直到b(b+1)/2>i,即b下一个值将导致索引大于i。然后,您可以找到a作为差值a=i−b(b-1)/2。这种通过一次递增b一个的方法涉及到使用循环。
pair<int, int> pair_from_index(int i) {
int a, b;
for (b = 0; b*(b + 1)/2 <= i; ++b)
/* empty loop body */;
a = i - b*(b - 1)/2;
return make_pair(a, b);
}
您也可以将b(b−1)/2=i解释为二次方程,可以使用平方根求解。你需要的真正的b是浮点b的底,你会得到这个二次方程的正解。由于在这种方法中可能会遇到舍入误差导致的问题,因此您可能需要检查b(b+1)/2>i。如果不是这样,请像在循环方法中那样递增b。一旦有了b,a的计算就保持不变。
pair<int, int> pair_from_index(int i) {
int b = (int)floor((sqrt(8*i + 1) + 1)*0.5);
if (b*(b + 1)/2 <= i) ++b; // handle possible rounding error
int a = i - b*(b - 1)/2;
return make_pair(a, b);
}
顺序访问
请注意,您只需要将索引转回成对,即可随机访问列表。当在所有对上迭代时,一组嵌套循环会更容易。所以不是
for (int = 0; i < n*(n - 1)/2; ++i) {
pair<int, int> ab = pair_from_index(i);
int a = ab.first, b = ab.second;
// do stuff
}
你最好写
for (int i = 0, b = 1; b != n; ++b) {
for (int a = 0; a != b; ++a) {
// do stuff
++i;
}
}
根据我对这个问题的理解,有一种方法可以得到一对a&b(在你的例子中是基于1,2&3)和对象数量n(在你例子中是4)是:
t = n * (n - 1) / 2;
a = n - floor((1 + sqrt(1 + 8 * (t - index - 1))) / 2);
b = index + (n - a) * (n - a + 1) / 2 - t + a + 1;
部分学分http://oeis.org/A002024
基于位置和http://saliu.com/bbs/messages/348.html,但它们似乎涉及在循环中计算组合。
编辑:更好的a公式(来自同一来源):
a = n - floor(0.5 + sqrt(2 * (t - index)));
- 如何查找哪个类对象位于数组的特定索引上(多态性)
- 排序谓词没有传递对索引对象的引用?
- 重载运算符 [] 用于从对象数组中给出特定索引
- 如何检索由带通配符的字符串索引的对象
- 如何从 boost::container::vector<std::string>::iterator 访问索引和对象?
- 如何确保在 FATFS 中倒带目录对象的读取索引?
- 使用对象的索引从矢量中删除对象
- 在对象上运行,运算符重载 () 与索引
- 通过查找重复顶点从 vec3 对象的向量计算索引
- 从对象创建矢量包装器,该对象只允许使用索引访问向量
- 将指针分配给字符串对象的第一个也是最后一个索引
- 为对象指针数组的每个空索引创建新对象
- 如何获得具有多个索引的对象列表
- 具有成员变量的对象 Const 数组 = 先前索引成员变量的总和
- 通过索引从向量中删除对象
- 非冗余对列表中对象的索引
- 在带有智能指针的大量对象中创建多个索引
- C :通过索引从列表中获取对象无效
- 操纵网格对象中的索引
- 使用 -> 从对象索引数组访问虚函数