edited by
32,661 views
126 126 votes

In an adjacency list representation of an undirected simple graph $G=(V, E)$, each edge $(u, v)$ has two adjacency list entries: $[v]$ in the adjacency list of $u$, and $[u]$ in the adjacency list of $v$. These are called twins of each other. A twin pointer is a pointer from an adjacency list entry to its twin. If $|E|=m$ and $|V|=n$, and the memory size is not a constraint, what is the time complexity of the most efficient algorithm to set the twin pointer in each entry in each adjacency list?

  1. $\Theta\left(n^{2}\right)$
  2. $\Theta\left(n+m\right)$
  3. $\Theta\left(m^{2}\right)$
  4. $\Theta\left(n^{4}\right)$

10 Answers

Best answer
81 81 votes

We can take extra array of size $V^2$ as memory is not a constraint.

Do the BFS traversal and for each edge $u-v$ in advance list in graph store the $v$ node address in $a[i][j].$

For e.g., if we find $1\to 2$ as an edge, then store node $2$ node address in location $a[i][j].$

Now once we have stored all the edge $(u-v)$ addresses, then do BFS again.

Now when we encounter $1\to 2,$ then goto $a[2][1]$ which is having twin address and set this twin pointer for node $2$ in list $1.$

Do for all edges similarly.


Remember, we have not initialized memory as we will use only slots we need. If we initialize memory it can take $O(V^2)$ time. We can also use one hash table per node to store the node address while doing first traversal.The key to has table for Node $u$ is the vertex $v$ (for edge $u-v$ means in $u$ table it has edge to $v$ and  we are storing $v$ address) and value will be $v$ address.

Correct Answer: $B$

selected by
91 91 votes

Applying BFS on undirected graph gives you twin pointer. Visit every vertex level-wise. For every vertex, fill adjacent vertex in the adjacency list. BFS takes $\Theta\left(n+m\right)$ time.

Take extra field for storing number of linked lists for particular vertex. Take extra $m+n$ time( $m$ vertex and $n$ edges).

So, option B is the answer.

edited by
13 13 votes

I have read all comments and students have many doubts:

Let me clear it for you.

Doubt 1: visualization of twin pointers

Doubt 2: optimized algorithm with extra space as space is not a constraint.

X 106 108 110
101 X 109 111
102 104 X 112
103 105 107 X

 

Lets us take an example of a complete graph ‘G’ with 4 nodes. The above diagram shows the linked list representation of G.

initialize a matrix add[1 to 4][1 to 4]  keep a record of the address of each node while traversing for the first time.

Ex: If are starting from 1 then store ‘101’ in add[2][1]. Similarly, do for all nodes.

The time complexity of doing this step is O(m+n).

Now do 2nd traversing, and fill the address of twins for each node by using matrix.

Ex: for a node with 101 address fill the twin pointer with add[1][2] i.e 106.

The time for doing this will be O(n+m).

Overall time complexity = O(n+m)

Note: Here we are not traversing the matrix but only directly accessing specific elements of the matrix.

Doubt 3: Many students are using BFS and DFS. Honestly speaking you can use anything BFS, DFS, or simple traversing like I have used it. It will give the same time complexity.

Use of BFS is done to reduce the number of traversing of adjacency list as while filling the matrix u can fill twin pointers too at the same time.

4 4 votes
Can we use this approach not sure about this?

We will consider a directed graph with every undirected edge is replaced by two directed edges one forward and one backward. Then we do DFS-like traversal on this graph and set the twin pointer of as it's parent pointer. So the time complexity will be $ \theta(m+n)$
3 3 votes

We are given an undirected simple graph $ G = (V, E) $ with $ n = |V| $ vertices and $ m = |E| $ edges, stored as an adjacency list. Since the graph is undirected, each edge $ \{u, v\} $ appears twice: once as $ v $ in $ u $’s list and once as $ u $ in $ v $’s list. These two entries are called twins, and the goal is to set a twin pointer from each entry to its twin.

A brute-force method searching for the twin by scanning the neighbor’s list could take $ O(\deg(v)) $ per entry, leading to $ O(m^2) $ time in the worst case. However, we can achieve optimal performance using a hash table.

 

Efficient Algorithm Using a Hash Table:

We process each of the $ 2m $ adjacency list entries exactly once. For an entry representing the directed pair $ (u, v) $, we create a canonical key for the undirected edge:
$$
k = (\min(u,v),\ \max(u,v))
$$
This ensures that both $ (u,v) $ and $ (v,u) $ map to the same key.

We maintain a hash table that maps each key $ k $ to the first adjacency-list node seen for that edge. When we encounter the second occurrence (the twin), we link the two nodes with twin pointers.

The steps are:

  • Initialize an empty hash table $ H $.
  • For each vertex $ u \in V $:
  •   For each neighbor $ v $ in $ u $’s adjacency list:
    •   Let $ k = (\min(u,v), \max(u,v)) $.
    •   If $ k \notin H $, store a pointer to this list node in $ H[k] $.
  •   Else, retrieve the stored node from $ H[k] $, and set mutual twin pointers between the two nodes.

Each operation (hash lookup, insertion, pointer assignment) takes $ O(1) $ expected time. The total number of entries processed is $ 2m $, and we also iterate over $ n $ vertices to access their lists.

Thus, the total time complexity is $ \Theta(n + m) $.

Example of Hash Table Usage

Consider a graph with edges $ \{1,2\}, \{2,3\} $. The adjacency lists are:

  1. Vertex 1: [2]  
  2. Vertex 2: [1, 3]  
  3. Vertex 3: [2]

As we process each entry, the hash table evolves as follows:

$$
\begin{array}{|c|c|c|}
\hline
\text{Step} & \text{Entry Processed} & \text{Hash Table } H \\
\hline
1 & (1,2) & \{ (1,2) \mapsto \text{node}_{1\to2} \} \\
2 & (2,1) & \text{Twin found! Link } \text{node}_{2\to1} \leftrightarrow \text{node}_{1\to2} \\
3 & (2,3) & \{ (1,2) \mapsto \cdots,\ (2,3) \mapsto \text{node}_{2\to3} \} \\
4 & (3,2) & \text{Twin found! Link } \text{node}_{3\to2} \leftrightarrow \text{node}_{2\to3} \\
\hline
\end{array}
$$

After processing all entries, every adjacency list node has its twin pointer correctly set.

The algorithm runs in linear time relative to the input size, which is $ \Theta(n + m) $. This is optimal, as we must examine every vertex and every edge at least once.

$$
\boxed{\text{B. } \Theta(n + m)}
$$

0 0 votes

Do BFS traversal and create Adjaceny List(or Dictionary) with key having Vertex and item with Node address like
1->100
2->200
3->300....

Here 100 is address of node 1, 200 is address of node 2,etc

Now, do BFS on adjaceny List of graph and if node 1 has neighbor like 3,5,6 then add address of node 1 i.e 100 (which we got using our created Dictionary) and add it to 3,5,6 and then go to node 2 and add address of node 2 i.e 200 for all its neighbor and so on.

Here also TC=V+E

Answer:
Position:
Show:

Related questions

71 71 votes
10 answers 10 answers
24.0k
24.0k views
Akash Kanase asked Feb 12, 2016
24,023 views
Breadth First Search (BFS) is started on a binary tree beginning from the root vertex. There is a vertex $t$ at a distance four from the root. If $t$ is the $n^{\text{th}...
53 53 votes
8 answers 8 answers
37.0k
37.0k views
Akash Kanase asked Feb 12, 2016
37,006 views
Let $A_{1}, A_{2}, A_{3}$ and $A_{4}$ be four matrices of dimensions $10 \times 5, 5 \times 20, 20 \times 10$ and $10 \times 5$, respectively. The minimum number of scala...
86 86 votes
3 answers 3 answers
29.5k
29.5k views
Akash Kanase asked Feb 12, 2016
29,507 views
The given diagram shows the flowchart for a recursive function $A(n)$. Assume that all statements, except for the recursive calls, have $O(1)$ time complexity. If the wor...
64 64 votes
4 answers 4 answers
25.0k
25.0k views
Akash Kanase asked Feb 12, 2016
25,046 views
Assume that the algorithms considered here sort the input sequences in ascending order. If the input is already in the ascending order, which of the following are TRUE?Qu...