【问题标题】:Troubles with STL list iteratorsSTL 列表迭代器的问题
【发布时间】:2010-06-20 16:55:21
【问题描述】:

经过一千次使用指针的谷歌/绕过尝试后,我决定自己将这个问题发布给你们。

问题是:我正在尝试从我之前制作的图表中创建最小生成树。为此,我使用了 Kruscal 算法,即检查从短到长的每条弧,并获取我错过的顶点。

为此,我使用 stl::map 作为邻接矩阵来实现我的图。该地图由以下对组成:(双距离,对顶点*,顶点*-)。

该算法要求您区分一对您没有完全区分的对,其中一个您只需要一个顶点:前者需要您创建另一个集合,您必须通过获取弧线逐渐连接所有这些集合将它们连接起来(这些弧当然是在一组中有 1 个顶点,在另一个中有 1 个顶点)。

我决定以这种方式实现 Kruscal:我的 MST(最小生成树)本身就是一个 stl::map,所以每个子集都是。它们被组织在一个地图列表中(我键入了 map_t):每次我得到一个我错过了 2 个顶点的节点时,就会将一棵树添加到列表中,然后将那个节点放入其中。这些连接将使我的 MST 进入列表的第一个节点。

代码对我来说似乎没问题,但列表迭代器不会对此感到满意。代码如下:

map_t Grafo::createKruscalMST() {

    mapIterator_t iterator = adjmatrix.begin();
    mapIterator_t end = adjmatrix.end()--;

    list<map_t> MST;
    list<map_t>::iterator listend = MST.end(); // Per puntare alla fine della lista devo fare end()-1 perché end() è il primo dopo la fine

    //MST.resize(1);
    bool zeromatch = true;
    list<map_t>::iterator memo1 = MST.end(); // Valore che non c'è: MST.end() punta al primo elemento dopo la fine della lista
    int common;

    list<map_t>::iterator j = MST.begin();
    MST.resize(1);
    //++j;
    *j = setUnion(*j, iterator); // Inserisco in automatico il primo nodo

    while (iterator != adjmatrix.end() ) 
    {
        ++iterator;
        zeromatch = true;
        memo1 = MST.end();
        for (j = MST.begin(); j != MST.end(); ++j) 
        {
            common = howManyInCommon(*j, iterator);
            if (common == 2) zeromatch = false; 
            if (common == 1) 
            {
                zeromatch = false;
                if (memo1 == MST.end() ) memo1 = j;  // Se nessun altro prima di me aveva 1 e un solo match, mi ricordo della posizione
                else 
                { 
                    *memo1 = treeMerge(*memo1, *j); // Se c'era un altro prima di me, lo copio tutto nel precedente e poi cancello l'altra occorrenza.
                    MST.erase(j);           // Questo farà affiorare l'MST nel nodo di testa, alla lunga.
                    *memo1 = setUnion(*memo1, iterator); // Includo anche il collegamento tra i due semialberi.
                    memo1 = MST.end();  // Fatto ciò, provvedo a resettare l'iteratore di appoggio

                } 
            }
        }
        if (memo1 != MST.end() ) 
            *memo1 = setUnion(*memo1, iterator);
        if (zeromatch == true ) 
        {
            //MST.resize(MST.size()+1);
            //listend = MST.end()--;
            MST.push_back( setUnion(MST.back(), iterator) );
        }
    }
    return MST.front();
}

int howManyInCommon(map_t disjset, mapIterator_t vertexptr) {
int j = 0;  // Parto da 0 e conto direttamente quanti ne ho in comune (molto meglio di una concatenazione di if)
if (vertexptr->second.first->getRepresenter() == disjset.begin()->second.first->getRepresenter() ) 
    j++;
if (vertexptr->second.second->getRepresenter() == disjset.begin()->second.first->getRepresenter() )
    j++;
return j;
}

map_t setUnion(map_t Tree, mapIterator_t i) {
        if (Tree.empty() ) {
        Tree.insert(*i);
        Tree.begin()->second.second->setRepresenter(Tree.begin()->second.first->getRepresenter() ); // Il rappresentante del secondo nodo diventa uguale a quello del primo
    } 
    else {
        i->second.first->setRepresenter(Tree.begin()->second.first->getRepresenter() );
        i->second.second->setRepresenter(Tree.begin()->second.first->getRepresenter() );
        // Nodo della mappa - Nodo con pair <double, pair<Nodo*,Nodo*> - Devo lavorare sul secondo del pair esterno, dunque.
        Tree.insert(*i);
    }
    return Tree;
}

map_t treeMerge(map_t Dest, map_t Source) {
    mapIterator_t srciterator = Source.begin();
    while (srciterator != Source.end() ) {
        Dest = setUnion(Dest, srciterator);
        ++srciterator;
    }
    return Dest;
}

【问题讨论】:

  • 首先,不要将迭代器变量命名为“迭代器”,因为它可能与 stl 类型名迭代器冲突。
  • 我们能否确定这个人的名字是“Kruskal”,而不是“Kruscal”?

标签: c++ list stl iterator


【解决方案1】:

您定义了一个问题,但问题在哪里?

我不明白你为什么要这样做。在实现 Kruskal 时,通常使用弧的排序列表和Union-Find 结构来表示树。

【讨论】:

    【解决方案2】:

    我没有直接的答案给你,但更多的是一个问题。你为什么做这个?如果要玩,我想那很好。如果对于某些应用程序,为什么不使用包含 Kruscal 算法实现的 boost 图?

    http://www.boost.org/doc/libs/1_43_0/libs/graph/doc/index.html

    当然,boost graph 的文档有点奇怪,学习这个库可能有点棘手,但是一旦你学会了它就很好了。

    也就是说,我用它做的唯一有用的事情是编写一个框架,用于将某些数据的一个版本转换为另一个版本。碰巧版本是节点,而翻译器本身是边缘。为了翻译,我们找到从一个节点到另一个节点的路径,并沿路径调用每个翻译器。无论如何,使用 boost graph 开发该系统的代码几乎是微不足道的。

    【讨论】:

    • 我第二次使用 Boost Graph 来处理这些事情。它的 API 有点不寻常,但灵活性是存在的,而且比手工操作要短得多。
    【解决方案3】:

    当前代码的一个问题是您实际上是在取消引用结束迭代器:

    list<map_t> MST;
    // ...
    list<map_t>::iterator j = MST.begin(); // `MST` is empty, so `MST.begin() == MST.end()`.
    MST.resize(1);
    *j = setUnion(*j, iterator); // oops. `j` still equals `MST.end()`.
    

    尝试将MST 的大小调整为1 之前j 设置为MST.begin()

    另一个问题是您可能需要重新阅读有关如何在 C++ 中指定范围的材料。这一行:

    mapIterator_t end = adjmatrix.end()--;

    本质上是危险的。示例:

    mapIterator_t iterator = adjmatrix.begin(),
        end = adjmatrix.end()--;
    for (; iterator != end; ++iterator) { // might not terminate if `iterator == adjmatrix.end()` at the start. Also, the `for` loop body will likely dereference invalid iterators.
    }
    

    【讨论】:

      【解决方案4】:

      ty 支持 =)

      @Craig:我正在为一个大学项目做这件事,这迫使我停留在 STL 边界之间并自己编写所有内容(不幸的是 =P )。我们可以称之为“玩”(我不能说它没有乐趣)......但是用火! =D

      @Daniel:明白了,虽然我不明白为什么我需要将 end 传递给 setUnion:它的目的只是添加一个节点,在添加时设置代表的指针。 外部“while”(假设我设置了正确的边界)应该告诉 setUnion 何时停止,不是吗?

      顺便说一句,我可以再补充一个问题吗? setUnion 最初的想法是让它接收指针并将节点直接添加到指向的树中。即使有指针我也无法让它修改数据,它仍然在制作他自己的副本,不知道为什么。 我现在不在家,我会尽快把使用指针的代码贴给你

      【讨论】:

      • 关于setUnion,我弄错了。您是正确的,您不需要传递结束迭代器,因为该函数仅添加一个节点。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-07-19
      • 1970-01-01
      • 2013-09-23
      • 2011-05-01
      • 2011-02-24
      • 2012-11-05
      • 2016-07-21
      相关资源
      最近更新 更多