这是用于在向量矢量中搜索和计算对象对的最佳数据结构

时间:2017-02-03 12:32:31

标签: c++ algorithm stl set std-pair

我已定义class elementclass node

班级元素

class element
{
    int id;
    std::vector<node> m_nodes;   // An element consist of 4 nodes.
    public:
    getnode(int)    // return n-th node;       
}

班级节点

class node
{
    int id;
    // other members
}

class model由整个nodeelement个对象组成。 class element对象由四个node个对象的向量组成。一对两个连续(相邻)node个对象称为face。

示例:
elem1:{1,2,3,4}
elem2:{3,5,6,4}
elem1和elem2是两个element个对象,数组中的整数表示四个节点对象的id 1-2,2-3,3-4和4-1是elem1的面。 3-5和5-6,6-4和4-3是elem2的面。 面3-4和面4-3是相同的,因此由两个元素共享

边界元素是由至少一个面构成的元素,其不被其他元素共享。在上面的例子中,elem1和elem2都是边界元素。边界元素的矢量也在模型类中定义。

班级模型

class model    
{    
    std::vector<node> m_nodes;
    std::vector<element>m_elements;
    std::vector<element>m_boundary;

    public:
    void set_boundary_elements();
}

问题:如何初始化边界元素的向量
这是set_boundary_elements()函数的伪代码。

void model::set_boundary_elements()
{
     std::vector <std::pair<std::set<int> , int >> faces;
     std::set<int> s;
     for(auto iter::m_elements)
     {
         //initialise  face.
         for(int i=1; i<5; ++i)
         {
             if(i != 4)
              {
                  s.insert(iter.getnode(i));
                  s.insert(iter.getnode(i+1));
              }
              else 
              {
                  s.insert(iter.getnode(4));s.insert(iter.getnode(1));   
              }
              for(auto it: faces)
              {
                  if(s== it.first)
                       (it.second)++; break;
              }
              faces.push_back(s,1);
         }
         //then push_back the elements which have nonshared faces, into m_boundary.
     }
}             

我认为我的算法效率很低,因为每次我必须遍历所有面时添加一个面。在stl / algorithm中是否有任何有用的方法可以有效地解决我的问题?

2 个答案:

答案 0 :(得分:3)

正如你对帖子的评论所说,使用std :: array作为静态大小的向量,并在for循环中使用const引用,这将避免副本并帮助优化:

 for (const auto &iter: m_elements)

 for(auto &it: faces)

如果您有很多元素(&gt; 50),我认为您还应该将用于面孔的容器从 std :: vector 更改为 std :: map ,这样:

          for(auto it: faces)
          {
              if(s== it.first)
                   (it.second)++; break;
          }
          faces.push_back(s,1);

将成为:

         auto &it = faces.find(s);
         if (it != faces.end())
             it.second++;
         else
             faces.insert(std::make_pair(s, 1));

答案 1 :(得分:3)

重新考虑你的设计。目前,元素并不真正共享节点。应该共享节点的两个元素每个都存储恰好具有相同id的不同数据集。这意味着如果某个东西改变了一个节点,系统可能会不一致。

这是我的建议(没有构造函数,getter,setter等等,假设你可以轻松填写​​):

class Model {

    class Node;
    class Element;

private:

    vector<Node> nodes;
    vector<Element> elements;

}

class Model::Element {
private:
    Element(); //only to be created by Model
    vector<unsigned int> incident_nodes;
}

class Model::Node {
private:
    Node(); //only to be created by Model
    vector<unsigned int> incident_elements;
}

请注意,Node和Element都存储事件项,并且它们使用整数在模型中的向量中引用其id。 Model负责创建和修改节点和元素,这些方法将负责保持数据的一致性。 Element或Node上的所有公共方法都是常量。

这将为您提供一个稳定的系统,该系统在两个方向都有参考。如果您想知道元素是否在边界上,则代码为

//returns all entries that are in both vectors
inline vector<unsigned int> intersection(const vector<unsigned int>& vector_a,
    const vector<unsigned int>& vector_b);

typedef vector<unsigned int> Face; //defined in model, a pair of node ids

//number = 0..3, returns the corresponding face
Model::Face Model::get_face(const unsigned int element_id,
    const unsigned int number);

vector<unsigned int> Model::incident_elements(const Face& face){
    return intersection(nodes[face[0]].incident_elements,
        nodes[face[1]].incident_elements);
}

bool Model::is_boundary(const unsigned int element_id){

    //check if it has a face that is boundary
    for (unsigned int i=0; i<4;i++){
        Face face = get_face(element_id, i); 
        if(incident_elements(face).size() == 1){
            return true;
        }
    }
    return false;
}

(所有引用的方法和函数都应该是不言自明的,Face可以转换为结构或类,可能使用方法Face :: incident_elements {return intersection(...);},特别是如果你想做的话更多的东西在脸上,但可能是Face对象是临时的,因为它们可以很容易地提取出来)

这种方式允许您清理操作,当然每个节点都需要存储事件元素向量,这需要更多内存。但是我怀疑你没有这样的东西就能有效地工作,特别是因为我认为你会想做更多这样的操作。

可以用静态大小的东西替换Node和Element中的向量,但我不认为这是一个很大的交易,特别是因为它们只能在Model中访问。

该体系结构的缺点是删除效率低下(更改所有id存储)或在内存中留下漏洞(尽管如果存储未使用的ID列表也不会太糟糕)