unordered_map插入正在创建瓶颈

时间:2018-04-28 06:04:48

标签: string performance c++11 graph unordered-map

所以在这里我试图创建一个Graph数据结构,其中我必须根据它们的id来跟踪边缘。所以我在字符串数据结构中创建边缘ID为eid:sourceid_destinationid

using namespace std;

class Edge{

public:
    bool operator==(const Edge* &obj) const
    {
        return eid==obj->eid;
    }

    std::string eid;
    set<int> rrids;
    int sourceid;
    int destid;
    int strength;

public:
    Edge(std::string eid,int from,int to);
    std::string getId();
    void addRRid(int rrid);
    void removeRRid(int rrid);
    void setRRid(set<int> rrids);
    void setId(std::string eid);
};

这是我用来添加和删除边缘的另一个类。 HPP-文件

使用namespace std;

class RRassociatedGraph{

public:
    unordered_map<int,vertex*> vertexMap;
    std::unordered_map<std::string,Edge*> EdgeMap;
    int noOfEdges;

public:
    RRassociatedGraph();
    unordered_set<vertex> getVertices();
    int getNumberOfVertices();
    void addVertex(vertex v);
    vertex* find(int id);
    Edge* findedge(std::string id);
    void addEdge(int from, int to, int label);
    void removeEdge(int from, int to,int rrSetID);
};

当我调试代码时,我发现在函数中添加边缘这里我正在做的地方EdgeMap.insert执行不会转到下一行。它保留在哈希表中,用于某些桶条目的循环。我无法经常调试此代码,因为我必须等待3个小时才能解决此问题。代码与小图完美配合。但对于较大的图形,edgeMap必须存储800k边缘。它进入这个哈希表无限循环。我没有得到这个哈希表代码。但是我创建Edgemap的数据结构有问题吗?

#include "RRassociatedGraph.hpp"
RRassociatedGraph::RRassociatedGraph() {
    noOfEdges=0;
}

void RRassociatedGraph::addVertex(vertex v) {
    vertexMap.insert(pair<int,vertex*>(v.getId(), &v));
}

vertex* RRassociatedGraph::find(int id) {
    unordered_map<int,vertex*>::const_iterator got=vertexMap.find(id);
    if(got != vertexMap.end() )
        return got->second;
    return nullptr;
}

Edge* RRassociatedGraph::findedge(std::string id){
    unordered_map<std::string,Edge*>::const_iterator got=EdgeMap.find(id);
    if(got != EdgeMap.end() )
        return got->second;
    return nullptr;
}

void RRassociatedGraph::addEdge(int from, int to, int label) {

    vertex* fromVertex = find(from);
    if (fromVertex == nullptr) {
        fromVertex = new vertex(from);
        vertexMap.insert(pair<int,vertex*>(fromVertex->getId(), fromVertex));
    }

    vertex* toVertex = find(to);
    if (toVertex == nullptr) {
        toVertex = new vertex(to);
        vertexMap.insert(pair<int,vertex*>(toVertex->getId(), toVertex));
    }

    if(fromVertex==toVertex){
       // fromVertex->outDegree++;
        //cout<<fromVertex->getId()<<" "<<toVertex->getId()<<"\n";
        return;
    }
    std::string eid=std::to_string(from);
    eid+="_"+std::to_string(to);
    Edge* edge=findedge(eid);
    if(edge==nullptr){
        edge=new Edge(eid,from,to);
        edge->addRRid(label);
        fromVertex->addOutGoingEdges(edge);
        EdgeMap.insert(pair<std::string,Edge*>(edge->getId(), edge));
        noOfEdges++;
    }
    else{
        edge->addRRid(label);
        fromVertex->outDegree++;
    }

}


void RRassociatedGraph::removeEdge(int from, int to,int rrSetID) {
    vertex* fromVertex = find(from);
    std::string eid=std::to_string(from);
    eid+="_"+std::to_string(to);
    if(EdgeMap.count(eid)==1){
        Edge* e=EdgeMap.find(eid)->second;
        if(fromVertex->removeOutgoingEdge(e,rrSetID)){
            EdgeMap.erase(eid);
            delete e;
        }
    }
}

这是继续进入for循环的地方。地图的插入时间应该非常少,但这会在我的代码中造成瓶颈。

template <class _Tp, class _Hash, class _Equal, class _Alloc>
void
__hash_table<_Tp, _Hash, _Equal, _Alloc>::__rehash(size_type __nbc)
{
#if _LIBCPP_DEBUG_LEVEL >= 2
    __get_db()->__invalidate_all(this);
#endif  // _LIBCPP_DEBUG_LEVEL >= 2
    __pointer_allocator& __npa = __bucket_list_.get_deleter().__alloc();
    __bucket_list_.reset(__nbc > 0 ?
                      __pointer_alloc_traits::allocate(__npa, __nbc) : nullptr);
    __bucket_list_.get_deleter().size() = __nbc;
    if (__nbc > 0)
    {
        for (size_type __i = 0; __i < __nbc; ++__i)
            __bucket_list_[__i] = nullptr;
        __next_pointer __pp = __p1_.first().__ptr();
        __next_pointer __cp = __pp->__next_;
        if (__cp != nullptr)
        {
            size_type __chash = __constrain_hash(__cp->__hash(), __nbc);
            __bucket_list_[__chash] = __pp;
            size_type __phash = __chash;
            for (__pp = __cp, __cp = __cp->__next_; __cp != nullptr;
                                                           __cp = __pp->__next_)
            {
                __chash = __constrain_hash(__cp->__hash(), __nbc);
                if (__chash == __phash)
                    __pp = __cp;
                else
                {
                    if (__bucket_list_[__chash] == nullptr)
                    {
                        __bucket_list_[__chash] = __pp;
                        __pp = __cp;
                        __phash = __chash;
                    }
                    else
                    {
                        __next_pointer __np = __cp;
                        for (; __np->__next_ != nullptr &&
                               key_eq()(__cp->__upcast()->__value_,
                                        __np->__next_->__upcast()->__value_);
                                                           __np = __np->__next_)
                            ;
                        __pp->__next_ = __np->__next_;
                        __np->__next_ = __bucket_list_[__chash]->__next_;
                        __bucket_list_[__chash]->__next_ = __cp;

                    }
                }
            }
        }
    }
}

我有很多文件,所以我不能把整个代码。我在c ++方面不是那么好。如果我必须以其他方式实施,请告诉我。我必须使用hashMap,因为我还需要更快的搜索。

1 个答案:

答案 0 :(得分:0)

您可能在插入时遇到重新哈希。 Unordered_map有多个桶。填充最差时,插入时间为O(size())。 http://en.cppreference.com/w/cpp/container/unordered_map/insert 仅当新元素数大于max_load_factor()* bucket_count()时才会发生重新散列。

您可以使用当前设置执行的操作是: 1.程序初始化的增长映射,因为通常桶的数量不会缩小。 2.从std :: unordered_map更改为Boost :: intrusive_map,您可以在其中手动管理多个存储桶。