C++ 半边孪晶
我已经实现了一个用于加载3d对象的半边数据结构。我发现指定双/对边的部分需要最长的计算时间(特别是对于具有数十万条半边的对象)。原因是我使用嵌套循环来实现这一点。有没有更简单有效的方法? 下面是我写的代码。他是半边数据结构。Hear是包含所有半边的向量。vert是起始顶点,end是结束顶点。谢谢C++ 半边孪晶,c++,data-structures,C++,Data Structures,我已经实现了一个用于加载3d对象的半边数据结构。我发现指定双/对边的部分需要最长的计算时间(特别是对于具有数十万条半边的对象)。原因是我使用嵌套循环来实现这一点。有没有更简单有效的方法? 下面是我写的代码。他是半边数据结构。Hear是包含所有半边的向量。vert是起始顶点,end是结束顶点。谢谢 HE *e1,*e2; for(size_t i=0;i<hearr.size();i++){ e1=hearr[i]; for(size_t j=1;j<hearr.si
HE *e1,*e2;
for(size_t i=0;i<hearr.size();i++){
e1=hearr[i];
for(size_t j=1;j<hearr.size();j++){
e2=hearr[j];
if((e1->vert==e2->end)&&(e2->vert==e1->end)){
e1->twin=e2;
e2->twin=e1;
}
}
}
HE*e1,*e2;
对于(大小i=0;iend)和(e2->vert==e1->end)){
e1->twin=e2;
e2->twin=e1;
}
}
}
我使用了一些简单的关键字,比如break和continue,还将内部循环中j的值设置为j=I。这大大提高了速度。早些时候,我花了403秒来获取一组数据。现在是11秒。这些就是变化。欢迎提出任何意见。谢谢
for(size_t i=0;i<hearr.size();i++){
e1=hearr[i];
if(e1->twin!=0)
continue;
for(size_t j=i;j<hearr.size();j++){
e2=hearr[j];
if(e2->twin!=0)
continue;
if((e1->vert==e2->end)&&(e2->vert==e1->end)){
e1->twin=e2;
e2->twin=e1;
break;
}
}
}
for(大小i=0;itwin!=0)
继续;
对于(尺寸j=i;jtwin!=0)
继续;
如果((e1->vert==e2->end)和&(e2->vert==e1->end)){
e1->twin=e2;
e2->twin=e1;
打破
}
}
}
更好的解决方案是对数组排序,然后执行二进制搜索,提供您自己的比较。或者考虑散列每个节点,然后执行查找,同时提供自定义比较这是一个解决方案。我还没有编译
基本思想是按(垂直然后结束)和(结束然后垂直)对范围进行排序。每一项都需要nlgn时间
然后,我们并行遍历这两个列表,查找垂直主排序列表的结束与结束主排序列表的结束相等的范围
如果我们有这些范围,我们称之为DoTwins
。这将遍历所讨论的范围,查找垂直主列表的结束与结束主列表的垂直匹配的位置。然后我检查是否有多条完全相等的边(如果有,事情就糟了,所以我断言),然后连接双胞胎
每个循环(内部循环或外部循环)的每次迭代都以1为单位在列表中进行分析,而每个外部循环都不会回头。这就是O(n)
请注意,DoTwins
循环和调用DoTwins
的循环基本上遵循相同的逻辑,但测试略有不同。重构该逻辑可能会改进代码
免责声明:代码并没有被编译(或运行,或调试),只是从头开始编写的,所以可能会有打字错误。但基本理念应该是合理的
// A procedure to solve a subproblem -- the actual assignment of the
// twin variables. The left range's "vert" field should equal the
// right range's "end" field before you call this function. It proceeds
// to find the subsets where the left "end" equals the right "vert",
// and sets their twin field to point to each other. Note that things
// go squirrly if there are multiple identical edges.
template< typename HEPtrRange >
void DoTwins( HEPtrRange EqualVertRange, HEPtrRange EqualEndRange )
{
auto it1 = EqualVertRange.first;
auto it2 = EqualEndRange.first;
while( it1 != EqualVertRange.second && it2 != EqualEndRange.second )
{
Assert((*it1)->vert == (*it2)->end);
if ((*it1)->end > (*it2)->vert)
{
++(*it2);
continue;
}
if ((*it1)->end < (*it2)->vert)
{
++(*it1);
continue;
}
Assert((*it1)->end == (*it2)->vert);
// sanity check for multiple identical edges!
auto it3 = it1;
while (it3 != EqualVertRange.second && (*it3)->end == (*it1)->end)
++it3;
auto it4 = it2;
while (it4 != EqualVertRange.second && (*it4)->end == (*it2)->end)
++it4;
// the range [it1, it3) should have its twin set to the elements
// in the range [it2, it4). This is impossible unless they
// are both of size one:
Assert( it3 - it1 == 1 );
Assert( it4 - it2 == 1 );
for (auto it = it1; it != it3; ++it)
(*it)->twin = it2;
for (auto it = it2; it != it4; ++it)
(*it)->twin = it1;
it1 = it3;
it2 = it4;
}
}
//解决子问题的过程——子问题的实际赋值
//双变量。左侧范围的“垂直”字段应等于
//在调用此函数之前,右范围的“结束”字段。它继续进行
//要查找左“端点”等于右“顶点”的子集,
//并将它们的孪生场设置为相互指向。注意
//如果有多条相同的边,则快速移动。
模板
void DoTwins(heptrange EqualVertRange,heptrange equalendange)
{
auto it1=相等范围。第一;
auto it2=相等的初始值;
while(it1!=EqualVertRange.second&&it2!=EqualEndRange.second)
{
断言((*it1)->vert==(*it2)->end);
如果((*it1)->结束>(*it2)->垂直)
{
++(*it2);
继续;
}
如果((*it1)->结束<(*it2)->垂直)
{
++(*it1);
继续;
}
断言((*it1)->end==(*it2)->vert);
//检查多条相同边的完整性!
自动it3=it1;
while(it3!=EqualVertRange.second&(*it3)->end==(*it1)->end)
++it3;
自动it4=it2;
while(it4!=EqualVertRange.second&(*it4)->end==(*it2)->end)
++it4;
//范围[it1,it3]应将其孪生元素设置为
//在[it2,it4]范围内。这是不可能的,除非他们
//都是一号的:
断言(it3-it1==1);
断言(it4-it2==1);
用于(自动it=it1;it!=it3;++it)
(*it)->twin=it2;
用于(自动it=it2;it!=it4;++it)
(*it)->twin=it1;
it1=it3;
it2=it4;
}
}
其他地方:
// A vector of the edges sorted first by vert, then by end:
std::vector<HE*> vertSorted(&hearr[0], (&hearr[0]).size());
std::sort(vertSorted.begin(), vertSorted.end(),
[](HE* e1, HE* e2)
{
if (e1->vert != e2->vert)
return e1->vert < e2->vert;
return e1->end < e2->end;
}
);
// A vector of the edges sorted first by end, then by vert:
std::vector<HE*> endSorted = vertSorted;
std::sort(endSorted.begin(), endSorted.end(),
[](HE* e1, HE* e2)
{
if (e1->end != e2->end)
return e1->end < e2->end;
return e1->vert < e2->vert;
}
);
// iterate over both at the same time:
auto it1 = vertSorted.begin();
auto it2 = endSorted.begin();
while(it1 != vertSorted.end() && it2 != endSorted.end())
{
// we are looking for cases where left->vert == right->end.
// advance the one that is "lagging behind":
if ((*it1)->vert > (*it2)->end)
{
++it2;
continue;
}
if ((*it1)->vert < (*it2)->end)
{
++it1;
continue;
}
Assert( (*it1)->vert == (*it2)->end );
// Find the end of the range where left->vert == right->end
auto it3 = it1;
while (it3 != vertSorted.end() && (*it3)->vert == (*it1)->vert)
{
++it3;
}
auto it4 = it2;
while (it4 != endSorted.end() && (*it4)->vert == (*it2)->vert)
{
++it4;
}
auto EqualVertRange = std::make_pair(it1, it3);
auto EqualEndRange = std::make_pair(it2, it4);
// Delegate reverse lookups and assignment of twin variable to a subprocedure:
DoTwins( EqualVertRange, EqualEndRange );
it1 = it3;
it2 = it4;
}
//先按顶点排序,然后按端点排序的边向量:
std::vector(&hear[0],(&hear[0]).size();
std::sort(vertsorded.begin(),vertsorded.end(),
[](他*e1,他*e2)
{
如果(e1->vert!=e2->vert)
返回e1->vertvert;
返回e1->endend;
}
);
//先按端点排序,然后按顶点排序的边向量:
std::vector endSorted=vertSorted;
排序(endSorted.begin(),endSorted.end(),
[](他*e1,他*e2)
{
如果(e1->end!=e2->end)
返回e1->endend;
返回e1->vertvert;
}
);
//同时迭代这两个步骤:
自动it1=vertSorted.begin();
auto it2=endSorted.begin();
while(it1!=vertsorded.end()&&it2!=endSorted.end())
{
//我们正在寻找左->垂直==右->结束的情况。
//推进“落后者”:
如果((*it1)->vert>(*it2)->结束)
{
++it2;
继续;
}
如果((*it1)->垂直<(*it2)->结束)
{
++it1;
继续;
}
断言((*it1)->vert==(*it2)->end);
//查找范围的结尾,其中left->vert==right->end
自动it3=it1;
while(it3!=vertsorded.end()&&(*it3)->vert==(*it1)->vert)
{
++it3;
}
自动it4=it2;
while(it4!=endSorted.end()&&(*it4)->vert==(*it2)->vert)
{
++it4;
}
auto EqualVertRange=std::组成配对(it1,it3);
auto Equalendange=std::make_pair(it2,it4);
//将反向查找和双变量赋值委托给子过程:
DoTwins(相等范围、相等范围);
it1=it3;
it2=it4;
}
谢谢你的代码和详细的注释!我会尝试你的方法。我也想到了二进制搜索。谢谢!我会尝试让你知道它是如何进行的。