2

3D オブジェクトをロードするためのハーフエッジ データ構造を実装しました。ツイン/ペア エッジを割り当てる部分が最も長い計算時間を要することがわかりました (特に、何十万ものハーフ エッジを持つオブジェクトの場合)。その理由は、ネストされたループを使用してこれを達成するためです。これを行うためのより簡単で効率的な方法はありますか? 以下は私が書いたコードです。HE はハーフエッジ データ構造です。hiter はすべてのハーフ エッジを含むベクトルです。vert は開始頂点で、end は終了頂点です。ありがとう!!

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;
        }
    }
}

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;
            }
        }
}
4

2 に答える 2

1

これが解決策です。私はそれをコンパイルしていません。

基本的な考え方は、範囲を (vert の次に end) および (end の次に vert) でソートすることです。これらのそれぞれに 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;
  }
}

他の場所:

// 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;
}
于 2012-11-07T06:01:02.437 に答える
0

より良い解決策は、配列をソートしてから、独自の比較を提供するバイナリ検索を実行することです。または、各ノードをハッシュしてから、カスタム比較を提供しながらルックアップを実行することを検討してください

于 2012-11-07T05:24:05.473 に答える