@@ -3555,4 +3555,239 @@ public object VisitUsingExpression(UsingExpressionAst usingExpressionAst)
35553555 return null ;
35563556 }
35573557 }
3558+
3559+ /// Class to represent a directed graph
3560+ public class Digraph < T >
3561+ {
3562+ private List < List < int > > graph ;
3563+ private Dictionary < T , int > vertexIndexMap ;
3564+
3565+ /// <summary>
3566+ /// Public constructor
3567+ /// </summary>
3568+ public Digraph ( )
3569+ {
3570+ graph = new List < List < int > > ( ) ;
3571+ vertexIndexMap = new Dictionary < T , int > ( ) ;
3572+ }
3573+
3574+ /// <summary>
3575+ /// Construct a directed graph that uses an EqualityComparer object for comparison with its vertices
3576+ ///
3577+ /// The class allows its client to use their choice of vertex type. To allow comparison for such a
3578+ /// vertex type, client can pass their own EqualityComparer object
3579+ /// </summary>
3580+ /// <param name="equalityComparer"></param>
3581+ public Digraph ( IEqualityComparer < T > equalityComparer ) : this ( )
3582+ {
3583+ if ( equalityComparer == null )
3584+ {
3585+ throw new ArgumentNullException ( "equalityComparer" ) ;
3586+ }
3587+
3588+ vertexIndexMap = new Dictionary < T , int > ( equalityComparer ) ;
3589+ }
3590+
3591+ /// <summary>
3592+ /// Return the number of vertices in the graph
3593+ /// </summary>
3594+ public int NumVertices
3595+ {
3596+ get { return graph . Count ; }
3597+ }
3598+
3599+ /// <summary>
3600+ /// Return an enumerator over the vertices in the graph
3601+ /// </summary>
3602+ public IEnumerable < T > GetVertices ( )
3603+ {
3604+ return vertexIndexMap . Keys ;
3605+ }
3606+
3607+ /// <summary>
3608+ /// Check if the given vertex is part of the graph.
3609+ ///
3610+ /// If the vertex is null, it will throw an ArgumentNullException.
3611+ /// If the vertex is non-null but not present in the graph, it will throw an ArgumentOutOfRangeException
3612+ /// </summary>
3613+ /// <param name="vertex"></param>
3614+ /// <returns>True if the graph contains the vertex, otherwise false</returns>
3615+ public bool ContainsVertex ( T vertex )
3616+ {
3617+ return vertexIndexMap . ContainsKey ( vertex ) ;
3618+ }
3619+
3620+ /// <summary>
3621+ /// Get the neighbors of a given vertex
3622+ ///
3623+ /// If the vertex is null, it will throw an ArgumentNullException.
3624+ /// If the vertex is non-null but not present in the graph, it will throw an ArgumentOutOfRangeException
3625+ /// </summary>
3626+ /// <param name="vertex"></param>
3627+ /// <returns>An enumerator over the neighbors of the vertex</returns>
3628+ public IEnumerable < T > GetNeighbors ( T vertex )
3629+ {
3630+ ValidateVertexArgument ( vertex ) ;
3631+ var idx = GetIndex ( vertex ) ;
3632+ var idxVertexMap = vertexIndexMap . ToDictionary ( x => x . Value , x => x . Key ) ;
3633+ foreach ( var neighbor in graph [ idx ] )
3634+ {
3635+ yield return idxVertexMap [ neighbor ] ;
3636+ }
3637+ }
3638+
3639+ /// <summary>
3640+ /// Gets the number of neighbors of the given vertex
3641+ ///
3642+ /// If the vertex is null, it will throw an ArgumentNullException.
3643+ /// If the vertex is non-null but not present in the graph, it will throw an ArgumentOutOfRangeException
3644+ /// </summary>
3645+ /// <param name="vertex"></param>
3646+ /// <returns></returns>
3647+ public int GetOutDegree ( T vertex )
3648+ {
3649+ ValidateVertexArgument ( vertex ) ;
3650+ return graph [ GetIndex ( vertex ) ] . Count ;
3651+ }
3652+
3653+ /// <summary>
3654+ /// Add a vertex to the graph
3655+ ///
3656+ /// If the vertex is null, it will throw an ArgumentNullException.
3657+ /// If the vertex is non-null but already present in the graph, it will throw an ArgumentException
3658+ /// </summary>
3659+ /// <param name="vertex"></param>
3660+ public void AddVertex ( T vertex )
3661+ {
3662+ ValidateNotNull ( vertex ) ;
3663+ if ( GetIndex ( vertex ) != - 1 )
3664+ {
3665+ throw new ArgumentException (
3666+ String . Format (
3667+ Strings . DigraphVertexAlreadyExists ,
3668+ vertex ) ,
3669+ "vertex" ) ;
3670+ }
3671+
3672+ vertexIndexMap . Add ( vertex , graph . Count ) ;
3673+ graph . Add ( new List < int > ( ) ) ;
3674+ }
3675+
3676+ /// <summary>
3677+ /// Add an edge from one vertex to another
3678+ ///
3679+ /// If any input vertex is null, it will throw an ArgumentNullException
3680+ /// If an edge is already present between the given vertices, it will throw an ArgumentException
3681+ /// </summary>
3682+ /// <param name="fromVertex"></param>
3683+ /// <param name="toVertex"></param>
3684+ public void AddEdge ( T fromVertex , T toVertex )
3685+ {
3686+ ValidateVertexArgument ( fromVertex ) ;
3687+ ValidateVertexArgument ( toVertex ) ;
3688+
3689+ var toIdx = GetIndex ( toVertex ) ;
3690+ var fromVertexList = graph [ GetIndex ( fromVertex ) ] ;
3691+ if ( fromVertexList . Contains ( toIdx ) )
3692+ {
3693+ throw new ArgumentException ( String . Format (
3694+ Strings . DigraphEdgeAlreadyExists ,
3695+ fromVertex . ToString ( ) ,
3696+ toVertex . ToString ( ) ) ) ;
3697+ }
3698+ else
3699+ {
3700+ fromVertexList . Add ( toIdx ) ;
3701+ }
3702+ }
3703+
3704+ /// <summary>
3705+ /// Checks if a vertex is connected to another vertex within the graph
3706+ /// </summary>
3707+ /// <param name="vertex1"></param>
3708+ /// <param name="vertex2"></param>
3709+ /// <returns></returns>
3710+ public bool IsConnected ( T vertex1 , T vertex2 )
3711+ {
3712+ ValidateVertexArgument ( vertex1 ) ;
3713+ ValidateVertexArgument ( vertex2 ) ;
3714+
3715+ var visited = new bool [ graph . Count ] ;
3716+ return IsConnected ( GetIndex ( vertex1 ) , GetIndex ( vertex2 ) , ref visited ) ;
3717+ }
3718+
3719+ /// <summary>
3720+ /// Check if two vertices are connected
3721+ /// </summary>
3722+ /// <param name="fromIdx">Origin vertex</param>
3723+ /// <param name="toIdx">Destination vertex</param>
3724+ /// <param name="visited">A boolean array indicating whether a vertex has been visited or not</param>
3725+ /// <returns>True if the vertices are conneted, otherwise false</returns>
3726+ private bool IsConnected ( int fromIdx , int toIdx , ref bool [ ] visited )
3727+ {
3728+ visited [ fromIdx ] = true ;
3729+ if ( fromIdx == toIdx )
3730+ {
3731+ return true ;
3732+ }
3733+
3734+ foreach ( var vertexIdx in graph [ fromIdx ] )
3735+ {
3736+ if ( ! visited [ vertexIdx ] )
3737+ {
3738+ if ( IsConnected ( vertexIdx , toIdx , ref visited ) )
3739+ {
3740+ return true ;
3741+ }
3742+ }
3743+ }
3744+
3745+ return false ;
3746+ }
3747+
3748+ /// <summary>
3749+ /// Throw an ArgumentNullException if vertex is null
3750+ /// </summary>
3751+ private void ValidateNotNull ( T vertex )
3752+ {
3753+ if ( vertex == null )
3754+ {
3755+ throw new ArgumentNullException ( "vertex" ) ;
3756+ }
3757+ }
3758+
3759+ /// <summary>
3760+ /// Throw an ArgumentOutOfRangeException if vertex is not present in the graph
3761+ /// </summary>
3762+ private void ValidateVertexPresence ( T vertex )
3763+ {
3764+ if ( GetIndex ( vertex ) == - 1 )
3765+ {
3766+ throw new ArgumentOutOfRangeException (
3767+ String . Format (
3768+ Strings . DigraphVertexDoesNotExists ,
3769+ vertex . ToString ( ) ) ,
3770+ "vertex" ) ;
3771+ }
3772+ }
3773+
3774+ /// <summary>
3775+ /// Throw exception if vertex is null or not present in graph
3776+ /// </summary>
3777+ private void ValidateVertexArgument ( T vertex )
3778+ {
3779+ ValidateNotNull ( vertex ) ;
3780+ ValidateVertexPresence ( vertex ) ;
3781+ }
3782+
3783+ /// <summary>
3784+ /// Get the index of the vertex in the graph array
3785+ /// </summary>
3786+ private int GetIndex ( T vertex )
3787+ {
3788+ int idx ;
3789+ return vertexIndexMap . TryGetValue ( vertex , out idx ) ? idx : - 1 ;
3790+ }
3791+
3792+ }
35583793}
0 commit comments