11,428,497 members (66,359 online)

# Finding non-cyclical paths between arbitrary pairs of nodes

, 7 Jun 2012 Public Domain
 Rate this:
A recursive algorithm to find all paths between communicating network nodes.

## Introduction

This problem I once had to tackle when working on the design and implementation of routing optimization algorithms for telecommunication networks. Given that a wide area network with nodes and interconnecting links can be modeled as a graph with vertices and edges, a frequently occurring problem is to discover all possible path combinations (containing no cycles) between any pair of communicating end nodes. Please note that this is not a problem of just finding the shortest path between a pair of nodes, for which Dijkstra’a algorithm can be readily employed.

An additional factor is that the algorithm should be able to handle both graphs with uni-directional (one-way) edges and graphs whose edges are assumed to be bi-directional.

Source code and similar C++ algorithm implementations are available at the here.

## Background

The National Institute of Standards and Technology (NIST) online Dictionary of Algorithms and Data Structures describes this particular problem as “all simple paths” and recommends a depth-first search to find all non-cyclical paths between arbitrary pairs of nodes.

## Modeling the Networks

The link connectivity is modeled using the following Link class with which to identify the end nodes of individual links:

{
public:

Link( int source, int target )
{
sourceNode = source;
targetNode = target;
}

void GetSourceTargetNodes( int& source, int& target )
{
source = sourceNode;
target = targetNode;
}

protected:
int sourceNode;
int targetNode;
};

Here is the Network class with which to store the topology information and perform basic operations such as adding new links, checking the existence of links, and setting the bi-directional status of the network:

class Network
{
private:

bool bi_direction;

public:

Network();
~Network();

void Reset();
void SetBiDirection( bool bi );

bool LinkExists( int sourceID, int targetID );
bool BiDirectional();

std::vector< int > GetAdjNodeIDs( int n );
};

A standard STL map is used to house all the network links: the key value consisting of a std::pair uniquely identifies each link element, and are mapped to pointers to Link objects:

Unlike sequence containers, such as a std::vector, an associative container such as a std::map is particularly efficient at accessing its elements by their key. Perhaps for very large networks, some kind of hash table may result in further improvements in efficiency, but I’ve stuck with the std::map for now.

If the bi-direction status value is set to true, then a link between end nodes [a,b] would be treated the same as if the link’s end nodes were [b,a].

## The Depth-First Search Algorithm

As can be seen from the code sample, beginning from the start node, the algorithm examines all outgoing links and progresses by expanding the first child node of the search tree that appears, searching progressively deeper until a target node is found, or until it encounters a node that has no children. The search then backtracks, returning to the most recent node it hasn’t finished exploring:

// Algorithm to recursively search network for paths
void DepthFirst( Network* network,
std::vector<int>& visited,
int end )
{
int back = visited.back();

for ( std::vector<int>::iterator node_it = adjNode.begin();
node_it++ )
{
int node = (*node_it);
if ( ContainsNode( visited, node ) ) continue;

if ( node == end )
{
visited.push_back( *node_it );

int hops = (int) visited.size();

for ( int i = 0; i < hops; i++ )
{
std::cout << visited[ i ] << " ";
}
std::cout << std::endl;

int n = (int) visited.size() - 1;
visited.erase( visited.begin() + n );

break;
}
}

for ( std::vector<int>::iterator node_it = adjNode.begin();
node_it++ )
{
int node = (*node_it);

if ( ContainsNode( visited, node ) || node == end )
continue;

visited.push_back( node );

DepthFirst( network, visited, end );

int n = (int) visited.size() - 1;
visited.erase( visited.begin() + n );
}
}

## Example 1: A Directed Graph

Here is the graphical representation of a 5-node directed graph. For example, a directed edge exists between nodes [1,3], but not nodes [3,1], hence the single arrow between the node [1,3] pair:

In the main program loop, the network was set to having directed edges, i.e., the bi-direction status is set to false. Individual links are inserted by using calls to the Network object’s AddLink method:

nw.SetBiDirection( false );

To find all the possible combinations of paths between nodes [2,5] for example, we simply specify the start and target nodes and feed the DepthFirst method with them:

int start  = 2;
int target = 5;

std::vector<int> visited;
visited.push_back( start );
DepthFirst( &nw, visited, target );

To give the following output showing all combinations of paths between nodes 2 and 5:

Here is a graphical representation of an 8 node network containing non-directed (bi-directional) links only. For bi-directional links, I dispense with the use of links with arrows for clarity, since traffic in both directions would be permissible:

nw.SetBiDirection( true );

to give the following output showing all possible combinations of paths between nodes 2 and 5 for this 8-node network containing bi-directional links only:

## Share

Software Developer http://technical-recipes.com
United Kingdom
Software Engineer who has worked on projects in telecommunications, industrial robotics and image processing.

 First Prev Next
 Can you give me this in a proper order? shel8820-May-14 2:09 shel88 20-May-14 2:09
 My vote of 3 Mic7-Aug-13 15:02 Mic 7-Aug-13 15:02
 2 Directed vs 1 Bidirectional - Distinction w/o Difference DanielSBlack21-Nov-11 8:34 DanielSBlack 21-Nov-11 8:34
 Re: 2 Directed vs 1 Bidirectional - Distinction w/o Difference AndyUk0621-Nov-11 12:34 AndyUk06 21-Nov-11 12:34
 Excellent article Flaviu213-Nov-11 22:03 Flaviu2 13-Nov-11 22:03
 Re: Excellent article AndyUk0614-Nov-11 3:33 AndyUk06 14-Nov-11 3:33
 Using boost::graph geoyar29-Oct-11 10:17 geoyar 29-Oct-11 10:17
 Re: Using boost::graph AndyUk0629-Oct-11 11:20 AndyUk06 29-Oct-11 11:20
 My vote of 5 studleylee24-Oct-11 9:09 studleylee 24-Oct-11 9:09
 Re: My vote of 5 AndyUk0624-Oct-11 9:28 AndyUk06 24-Oct-11 9:28
 Re: My vote of 5 studleylee24-Oct-11 9:53 studleylee 24-Oct-11 9:53
 Re: My vote of 5 AndyUk0625-Oct-11 0:59 AndyUk06 25-Oct-11 0:59
 Re: My vote of 5 studleylee25-Oct-11 8:51 studleylee 25-Oct-11 8:51
 Last Visit: 31-Dec-99 19:00     Last Update: 3-May-15 1:38 Refresh 1