DS&A: Graph
Graph II (Improvement & Debugging)
- Remove duplicated
if (source == null || target == null) return null;inAddEdge()andRemoveEdge() - Fix Id inconsistency problem, or use the
Dictionary<TKey,TValue>collection instead - Replace
Console.WriteLine()inPrintGraph()by overridingToString() - Overload
==and!=(need to be done in pairs), or overrideEquals() - Ghost vertices
In MyBusiness/Program.csproj
using DataStructureLibrary.Graph;
namespace MyBusiness;
class Program
{
static void Main(string[] args)
{
Graph graph = new Graph();
Vertex v1 = graph.AddVertex("Victor");
Vertex v2 = graph.AddVertex("Markus");
Vertex v3 = graph.AddVertex("Yun");
Vertex v4 = graph.AddVertex("Anna");
// graph.RemoveVertex("Yun");
graph.AddEdge(v1, v2);
graph.AddEdge(v1, v3);
graph.AddEdge(v2, v3);
graph.AddEdge(v3, v4);
graph.AddEdge(v3, graph.HasVertex("Victor"));
graph.PrintGraph();
graph.RemoveVertex("Victor");
// graph.RemoveEdge(v1, v3);
graph.PrintGraph();
}
}
$ The total number of vertices is 4
$ The total number of edges is 5
$ ==============================
$ V(0) = Victor
$ V(1) = Markus
$ V(2) = Yun
$ V(3) = Anna
$ ==============================
$ E(0) = V(Victor) -- V(Markus)
$ E(1) = V(Victor) -- V(Yun)
$ E(2) = V(Markus) -- V(Yun)
$ E(3) = V(Yun) -- V(Anna)
$ E(4) = V(Yun) -- V(Victor)
$ ==============================
$ The total number of vertices is 3
$ The total number of edges is 2
$ ==============================
$ V(1) = Markus
$ V(2) = Yun
$ V(3) = Anna
$ ==============================
$ E(2) = V(Markus) -- V(Yun)
$ E(3) = V(Yun) -- V(Anna)
$ ==============================
In DataStructureLibrary/Graph.cs
namespace DataStructureLibrary.Graph;
public class Graph
{
// Fields
// The list of vertices in the graph
// LinkedList is the doubly linked list implementation in C#
private LinkedList<Vertex> _vertices;
private LinkedList<Edge> _edges;
// Constructors
public Graph()
{
// Keeping instiantiation in construcor allows lazy instanciation in later stage
_vertices = new LinkedList<Vertex>();
_edges = new LinkedList<Edge>();
}
// Methods
// Manipulate vertices
public Vertex AddVertex(string name)
{
// Check if the vertex exist
Vertex? v = HasVertex(name);
// If not, add a new vertex
if (v == null)
{
Vertex newV = new Vertex((uint)_vertices.Count, name);
_vertices.AddLast(newV);
return newV;
}
return v;
}
public void RemoveVertex(string name)
{
Vertex? v = HasVertex(name);
if (v != null)
{
// Remove the adjacent edges
// v.1 with run-time error
// Unhandled exception. System.InvalidOperationException:
// Collection was modified after the enumerator was instantiated.
// foreach (Edge e in _edges)
// {
// if (e.Source == v || e.Target == v)
// {
// _edges.Remove(e);
// }
// }
// v.2 with logical error
// for (int i = 0; i < _edges.Count; i++)
// {
// // Equal to source id or target id
// if ((_edges.ElementAt(i).Source == v) || (_edges.ElementAt(i).Target == v))
// {
// _edges.Remove(_edges.ElementAt(i));
// }
// }
// v.3 no error
for (int i = 0; i < _edges.Count; i++)
{
// bool isRemoved = false;
Edge e = _edges.ElementAt(i);
if (e.Source == v || e.Target == v)
{
_edges.Remove(e);
// isRemoved = true;
i--;
}
// if (isRemoved == true) i--;
}
// Remove the vertex from the list
_vertices.Remove(v);
}
}
// Method overloading
public Vertex? HasVertex(string name)
{
foreach (Vertex v in _vertices)
{
if (v.Name == name)
return v;
}
return null;
}
// Method overloading
public Vertex? HasVertex(uint id)
{
foreach (Vertex v in _vertices)
{
if (v.Id == id)
return v;
}
return null;
}
// Manipulate edges
public Edge? AddEdge(Vertex? source, Vertex? target)
{
// Check if the source and target vertices exist
if (source == null || target == null)
{
Console.WriteLine("Source or Target Vertex could not be found. Please add vertices first");
return null;
}
// Check if the edge exists
Edge? e = HasEdge(source, target);
// If not, add a new edge
if (e == null)
{
Edge newE = new Edge((uint)_edges.Count, source, target);
_edges.AddLast(newE);
return newE;
}
return e;
}
public void RemoveEdge(Vertex? source, Vertex? target)
{
if (source == null || target == null) return;
Edge? e = HasEdge(source, target);
if (e != null)
{
_edges.Remove(e);
}
else
{
Console.WriteLine("Edge could not be found. This method does nothing.");
}
}
public Edge? HasEdge(Vertex? source, Vertex? target)
{
if (source == null || target == null) return null;
foreach (Edge e in _edges)
{
if ((e.Source == source) &&
(e.Target == target))
return e;
}
return null;
}
// Graph
public void PrintGraph()
{
Console.WriteLine("The total number of vertices is " + _vertices.Count);
Console.WriteLine("The total number of edges is " + _edges.Count);
Console.WriteLine("==============================");
// Vertex list
foreach (Vertex v in _vertices)
{
Console.WriteLine($"V({v.Id}) = {v.Name}");
}
Console.WriteLine("==============================");
// Edge list
foreach (Edge e in _edges)
{
Console.WriteLine($"E({e.Id}) = V({e.Source.Name}) -- V({e.Target.Name})");
}
Console.WriteLine("==============================");
}
}
In DataStructureLibrary/Vertex.cs
namespace DataStructureLibrary.Graph;
public class Vertex
{
// Fields
public uint Id;
public string Name = "unknownName";
// Constructors
public Vertex(uint id, string name)
{
Id = id;
Name = name;
}
}
In DataStructureLibrary/Edge.cs
namespace DataStructureLibrary.Graph;
public class Edge
{
// Fields
public uint Id;
public Vertex Source;
public Vertex Target;
// Constructors
public Edge(uint id, Vertex source, Vertex target)
{
Id = id;
Source = source;
Target = target;
}
}