有效地标记图表中必须不再被考虑的节点

时间:2014-08-23 11:21:36

标签: c++ graph

我有一个图表并多次遍历每个节点,直到我将其标记为最终完成并在将来的迭代中忽略它。重复此过程,直到标记所有节点 到目前为止,我有一个std::vector存储所有节点的状态:节点完成时为finished[v] = 1,否则为0。代码如下所示:

for every node v {
    if finished[v] == 0 {
        [...]
    }
}

问题是,在计算结束时,只有少数节点没有被标记,但我仍然检查finshed[v] == 0的每一个节点 将所有节点ID保存在向量中然后将其移除直到向量为空(我听说向量中移除元素并不是非常有效)会更好吗? 由于我已经将已完成节点的数量存储为一个宽整数,我可以移动向量末尾的所有标记节点并将其剪切(位于totalNumberOfNodes - numberOfFinishedNodes),以防移动元素比删除更有效。或者这个场景中的向量是否仅低于其他数据结构?

2 个答案:

答案 0 :(得分:0)

如果您需要它们保持特定的顺序:链接列表可能是唯一有效的解决方案(您可以考虑其他数据结构,如"绳索和#34;如果您愿意,但我怀疑您赢了&#39 ; t想要实现它们。)

如果您只需要它们保持排序顺序:std::multiset也应该有效;只需删除您访问过的元素。

如果您根本不关心订单:只需保留要处理的所有节点的vector个索引,而不是实际擦除中的元素中间,用最后一个元素交换它,然后弹出向量的背面。

答案 1 :(得分:0)

使用std::list<T>

#include <list>

std::list<int> unvisited_nodes;

// fill in unvisited_nodes with all nodes' ids

loop of you algorithm
{
    // iterate only over unvisited nodes
    for (auto it = unvisited_nodes.begin(); it != unvisited_nodes.end(); )
    { 
        visit(*it);

        if (shouldNotBeVisitedAgain(*it))
        {
            unvisited_nodes.erase(it++);
        }
        else
        {
            ++it;
        }
    }
}

使用您的std::vector<T>

#include <vector>

std::vector<int> unvisited_nodes;

// fill in unvisited_nodes with all nodes' ids

loop of you algorithm
{
    // iterate only over unvisited nodes
    for (int i = 0; i < unvisited_nodes.size(); )
    { 
        visit(unvisited_nodes[i]);

        if (shouldNotBeVisitedAgain(unvisited_nodes[i]))
        {
            std::swap(unvisited_nodes[i], unvisited_nodes.back());
            unvisited_nodes.pop_back();
        }
        else
        {
            ++i;
        }
    }
}

关于从std::vector<T>删除元素的方法:此操作只有O(N)复杂度,以防您希望保留元素的原始顺序。如果删除后元素的顺序不需要相同,则可以优化此操作:

std::vector<int> v = { 1, 2, 3, 4, 5, 6, 7 } ;
// now, let's remove element under index 3, v[3] == 4:
std::swap(v[3], v.back());
v.pop_back();
// now v == { 1, 2, 3, >7<, 5, 6 }