具有高效“删除”功能的数据结构

时间:2012-07-19 12:39:28

标签: c++ algorithm data-structures stl

我正在寻找改善代码性能瓶颈的方法。 在我的代码中,我构建了一个图形,其中每个顶点都保持传出和传入边缘的列表。而杀死我的代码性能的原因是这些边缘经常从列表中删除。

目前,我的实现是使用C ++的STL库中提供的列表。所以我想知道是否有任何数据结构提供了有效的删除功能。

下面是删除顶点的代码的部分。你可以看到 在外部for循环的每次迭代中    (* inedge_it) - > src-> out_edges.remove(* inedge_it)被调用以从传入边列表中删除(* inedge_it)。 同样在内部for循环中   (* outedge_it) - > tgt-> in_edges.remove(* outedge_it被调用以从传出边列表中删除(* outedge_it)。

int dag_vertex::eliminate( int & edge_counter )
{
    int nMults = 0;

    list<dag_edge*>::iterator inedge_it;
    list<dag_edge*>::iterator outedge_it;

    int m = in_edges.size();
    int n  = out_edges.size();

    for( inedge_it=in_edges.begin() ; inedge_it!=in_edges.end() ; inedge_it++ )
    {
        (*inedge_it)->src->out_edges.remove(*inedge_it);

        for( outedge_it=out_edges.begin() ; outedge_it!=out_edges.end() ; outedge_it++ )
        {
            (*outedge_it)->tgt->in_edges.remove(*outedge_it);

            double cij = (*inedge_it)->partial*(*outedge_it)->partial;

            nMults++;

            dag_edge * direct_link = NULL;

            list<dag_edge*>::reverse_iterator src_outedge_it;

            for( src_outedge_it=(*inedge_it)->src->out_edges.rbegin() ; src_outedge_it!=(*inedge_it)->src->out_edges.rend() ; src_outedge_it++ )
            {
                if( (*src_outedge_it)->tgt==(*outedge_it)->tgt )
                {
                    direct_link = (*src_outedge_it);
                    break;
                }
            } 

            if(direct_link)
            {
                direct_link->partial += cij;
            }else
            {
                (*outedge_it)->tgt->add_in_edge( (*inedge_it)->src , cij );
                edge_counter++;
            }
        }

        delete (*inedge_it);    
    }

    for( outedge_it=out_edges.begin() ; outedge_it!=out_edges.end() ; outedge_it++ )
    {   
        delete (*outedge_it);
    }

    in_edges.clear();
    out_edges.clear();

    edge_counter -= (m+n);

    return nMults;
}

以下是添加传入边缘的功能的定义

dag_edge* dag_vertex::add_in_edge(dag_vertex* src , double partial)
{
    dag_edge* the_in_edge= new dag_edge(src, this, partial);
    in_edges.push_back(the_in_edge);
    src->out_edges.push_back(the_in_edge);
    return the_in_edge;
}

以下是dag_edge的定义。

dag_edge::dag_edge(class dag_vertex* s, class dag_vertex* t, double cij) : 
src(s), tgt(t), partial(cij),alive(true)
{

}

dag_edge::~dag_edge()
{
     //std::cout<<"~dag_edge("<<src->idx<<","<<tgt->idx<<")"<<std::endl;
}

dag_vertex* dag_edge::getsrc()
{
    return src;
}

dag_vertex* dag_edge::gettgt()
{
    return tgt;
}

void dag_edge::dump_to_dot(FILE* file)
{
    fprintf(file,"%d->%d [label=\"%f\"]\n",src->idx, tgt->idx, partial); 
}

void dag_edge::display() 
{

}

3 个答案:

答案 0 :(得分:2)

delete \ compare \ {{{}} \ {{{}}}使用HashTables的最有效方式。在STL中有一个insert。然后,您需要两个search个对象,而不是#include <map>。实现类似,但是当您执行比较时,它会更容易,而且您只能有一个循环。您的代码目前为Map,最多只会减少到vectors,最坏情况下会减少为O(n^3)

答案 1 :(得分:2)

vector中按值存储边缘可能会更有效率,当您需要删除索引edge处的i时,可以通过替换{{i来实现1}}与vector中的最后一个边缘并弹出最后一个

edges[i] = edges.back();
edges.pop_back();

如果move semantics

使用edge,效果会更高

答案 2 :(得分:1)

您实际上正在调用删除超过必要的内容:

for( inedge_it=in_edges.begin() ; inedge_it!=in_edges.end() ; inedge_it++ )
{
    (*inedge_it)->src->out_edges.remove(*inedge_it);

    for( outedge_it=out_edges.begin() ; outedge_it!=out_edges.end() ; outedge_it++ )
    {
        (*outedge_it)->tgt->in_edges.remove(*outedge_it); // This has no dependence on inedge_it

基本上它最终会尝试多次从目标中删除输入边缘,因此它会花费大量时间尝试查找已经删除的边缘。

您可以将其提取到一个单独的循环中:

for( outedge_it=out_edges.begin() ; outedge_it!=out_edges.end() ; outedge_it++ )
{
   (*outedge_it)->tgt->in_edges.remove(*outedge_it);
}

for( inedge_it=in_edges.begin() ; inedge_it!=in_edges.end() ; inedge_it++ )
{
    (*inedge_it)->src->out_edges.remove(*inedge_it);

    for( outedge_it=out_edges.begin() ; outedge_it!=out_edges.end() ; outedge_it++ )
    {
        double cij = (*inedge_it)->partial*(*outedge_it)->partial;