Reputation: 10583
I have an undirected graph implemented as
vector<int> G[V];
or
list<int> G[V];
, makes me no difference, and I need to delete edges from it in O(1). A matrix of connections is out of the question, ammount of vertecies is 10^5. The problem is as follows:
for(int i = 0; i < G[w].size(); i++)
{
int u = G[w][i];
// erase G[w][i];
// erase the edge (u, w) in G[u] in constant time
}
How do I implement it.
Upvotes: 0
Views: 3999
Reputation: 10583
Sooo, it's been a long time since I asked this question, but seeing it still unanswered I came to supplement a solution I used back then.
So, presuming the edges are stored in an array of adjacency lists
std::list<Edge> G[V];
we can have the Edges defined as follows:
struct Edge {
int vertex;
std::list<Edge>::iterator siblingIterator;
}
And the remove routine is straightforward then
for(auto &edge : G[w]) {
G[edge.vertex].erase(edge.siblingIterator);
}
G[w].clear();
Since remove with a list iterator takes constant time, then erasing one undirected edge (so the directed edge and its sibling with inverted direction) takes O(1).
I'm not going to dwelve into the past and fix all the bad practice things in my limited C++ skills from back then, but the gist of the solution is simple: just keep a reference to the sibling. Case closed.
Upvotes: 1
Reputation: 2524
Mixing C-style arrays and containers of the STL like this
vector<int> G[V];
isn't considered good style. Why not use vector< vector< int > >
?
Regarding your request to have an erase()
-function which is O(1), I think that you are faced with a trade-off: either you have very fast access but frequent modifications of the container are rather expensive (std::vector
), or the other way around (std::map
, std::list
, ...).
The following example offers the requested constant erase()
-functionality, but finding the element that is going to be removed is logarithmic. But maybe it helps you finding what you want:
#include <vector>
#include <set>
typedef int Vertex;
typedef std::vector< Vertex > Vertices;
struct Edge
{
int a;
int b;
Edge( int a, int b ) : a( a ), b( b ) {}
// Needed for std::set.
bool operator< ( const Edge & other ) const
{
if ( a < other.a ) return true;
if ( a > other.a ) return false;
return b < other.b;
}
};
typedef std::set< Edge > Edges;
struct Graph
{
Vertices vertices;
Edges edges;
};
int main( int argc, char ** argv )
{
Graph graph;
// Add vertices.
graph.vertices.push_back( Vertex( 0 ) ); // Vertex 0
graph.vertices.push_back( Vertex( 1 ) ); // Vertex 1
graph.vertices.push_back( Vertex( 2 ) ); // Vertex 2
graph.vertices.push_back( Vertex( 3 ) ); // Vertex 3
// Connect vertices.
graph.edges.insert( Edge( 0, 1 ) ); // Connect vertex 0 and vertex 1.
graph.edges.insert( Edge( 0, 1 ) ); // Connect vertex 1 and vertex 2.
graph.edges.insert( Edge( 1, 2 ) ); // Connect vertex 2 and vertex 3.
graph.edges.insert( Edge( 2, 0 ) ); // Connect vertex 3 and vertex 0.
// Remove the edge between vertices 1 and 2 again.
Edges::iterator it = graph.edges.find( Edge( 1, 2 ) );
if ( it != graph.edges.end() )
graph.edges.erase( it ); // The complexity of erase() is constant, but find() logarithmic.
}
Upvotes: 0