@@ -3555,4 +3555,239 @@ public object VisitUsingExpression(UsingExpressionAst usingExpressionAst)
3555
3555
return null ;
3556
3556
}
3557
3557
}
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
+ }
3558
3793
}
0 commit comments