簡體   English   中英

OpenMesh:快速搜索公共相鄰頂點

[英]OpenMesh: fast search of common neighbor vertices

我有一個 function 找到兩個頂點v1v2的公共鄰居,即連接到v1v2的那些頂點:

std::vector<MyMesh::VertexHandle> find_common_neighbors(MyMesh & mesh, MyMesh::VertexHandle & v1, MyMesh::VertexHandle & v2){
    std::vector<MyMesh::VertexHandle> common_neighbors;

    //iterate over neighbors of v1
    for(MyMesh::VertexVertexIter it1 = mesh.vv_iter(v1); it1.is_valid(); ++it1) {
      //neighbors of v2
      for(MyMesh::VertexVertexIter it2 = mesh.vv_iter(v2); it2.is_valid(); ++it2) {
        if ((*it1)==(*it2)){
            common_neighbors.push_back(*it1);     
        }
      }
    }
    return common_neighbors;

function 簡單地遍歷v1v2的鄰域並檢查是否找到出現在兩個鄰域中的任何頂點。 不幸的是,這個 function 似乎是我代碼的瓶頸,因此我的問題是在 OpenMesh 中是否有更優化的方法來完成這個?

我不是 OpenMesh 的專家,但看起來您正在使用相當有效的循環器來查找這些頂點對。

您的 function 唯一明顯的問題是您正在分配和返回std::vector object。

聲明書

std::vector<MyMesh::VertexHandle> common_neighbors;

定義一個空向量(隨后的push_back在內部調用malloc ,這是不可預測的昂貴)。 您在這里至少可以做的是預分配大概預期的頂點數量。

如果您為大量(10000+?)不同的v1, v2對調用此 function,則應將 function 的簽名更改為

std::vector<MyMesh::VertexHandle> find_common_neighbors(MyMesh & mesh,
               MyMesh::VertexHandle & v1, MyMesh::VertexHandle & v2,
               std::vector<MyMesh::VertexHandle>& common_neighbors);

並在那里傳遞預分配的common_neighbors

你可能還應該提供更多上下文(你怎么稱呼這個 function,你實際上對這些頂點做了什么 - 例如,如果你需要一個v3v1v2相鄰,然后制作一個三角形面(v1,v2,v3) ,那么您可能應該只采用v1-v2邊並遍歷相鄰的三角形......)以便提供更多優化。

要考慮的另一個方面是您有一個嵌套循環。 假設common_neighbors是 10 的數量級,那么 v1 和 v2至少有 10 個鄰居。 通過使用unordered_map ,我們可以用兩個單獨的循環來解決這個問題——這意味着 20 次迭代而不是 100 次迭代。 更准確地說是 O(n1 + n2) 而不是 O(n1*n2)。

std::vector<MyMesh::VertexHandle> find_common_neighbors(MyMesh & mesh, MyMesh::VertexHandle & v1, MyMesh::VertexHandle & v2)
{
    std::vector<MyMesh::VertexHandle> common_neighbors;
    std::unordered_map<MyMesh::VertexHandle, bool> candidates;

    for(MyMesh::VertexVertexIter it = mesh.vv_iter(v1); it.is_valid(); ++it) {
        candidates[*it] = true;
    }

    for(MyMesh::VertexVertexIter it = mesh.vv_iter(v2); it2.is_valid(); ++it) {
        if (candidates.find(*it) != candidates.end()) 
            common_neighbors.push_back(*it); 
    }

    return common_neighbors;
}

細節

為了理解我們在這里做什么,讓我們首先考慮一個概念上相似的方法,它使用std::vector<MyMesh::VertexHandle> candidates

  • 第一次循環:將v1的所有鄰居添加到candidates
  • 第二個循環:如果在candidates找到v2的鄰居,則將其添加到common_neighbors

但是,在向量上查找效率低下(與每次迭代候選向量相同)。 這就是我們用unordered_map替換候選向量的原因,它是一個 hash map,平均復雜度為 O(1)(最壞情況是 O(n) - 但實際上,我們可以假設它是 O(1)) .

加緊

如果將對find_common_neighbors的調用分組是有意義的(並且是可行的),例如: ...MyMesh::VertexHandle & v1, std:vector<MyMesh::VertexHandle> & v2) - 然后,請注意第一個循環 ( populating the candidates map) 可以重復用於 v2 中的所有元素。 所以我們得到 O(n1 + m * n2) 而不是 O(m * (n1 + n2)),其中 n1 是 v1 的大小,n2 是 v2 中的平均大小,m 是 v2 中的頂點數。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM