简体   繁体   中英

Efficiently mark nodes in a graph that must no longer be considered

I have a graph and iterate over every node multiple times until i mark it as finished eventually and ignore it in future iterations. This process is repeated until all nodes are marked.
So far, i have a std::vector that stores the status for all nodes: finished[v] = 1 when the node is finished and 0 otherwise. The code looks like this:

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

The problem is that near the end of the computation, only a few nodes are not marked but i still check every single one for finshed[v] == 0 Would it be better to save all node id's in a vector and then remove them until the vector is empty (I heard removing elements in a vector is not really efficient)?
Since I already store the number of finished nodes as a smple integer, I could just move all marked nodes at the end of the vector and cut it (at the position totalNumberOfNodes - numberOfFinishedNodes ) in case moving elements is more efficient than deleting. Or is a vector just inferior to other data structures in this scenario?

If you need them to stay in a particular order: a linked list may be the only efficient solution (you can consider other data structures like "ropes" if you want, but I suspect you won't want to implement them).

If you only need them to stay in sorted order: std::multiset should also work; just remove the elements that you've visited.

If you don't care about order at all: just keep a vector of the indices of all the nodes to be processed, but instead of actually erasing an element from the middle, swap it with the last element and then pop the back of the vector.

Using 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;
        }
    }
}

Using your 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;
        }
    }
}

Regarding elements' removal from std::vector<T> : this operations has O(N) complexity only in case you want to preserve the original order of elements. This operation can be optimized if the order of elements after removal does not need to be the same:

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 }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM