Reputation: 43553
This is a restatement of a question that has now been deleted. I think it is an interesting question. The input of the problem is an array of two-element tuples, each one representing an abstract edge that connects two abstract vertices. The desired output is an array of connected vertices. A vertex can be of any type, not necessarily a point in space, hence the "abstract" designation. The array is not expected to be ordered in any way. Actually the types are not even comparable. We are only allowed to compare them for equality.
Samples of input and output:
var input = new[] { ('a', 'b'), ('c', 'b'), ('a', 'c') };
var output = new[] { 'a', 'b', 'c' };
var input = new[] { ("a", "b"), ("a", "b") };
var output = new[] { "a", "b" };
var input = new[] { (true, true) };
var output = new[] { true };
var input = new[] { (1, 2), (4, 3), (3, 2), (1, 4) };
var output = new[] { 1, 2, 3, 4 };
var input = new[] { (1, 2), (2, 3), (3, 4) };
var output = new InvalidDataException(
"Vertices [1, 4] are not connected with exactly 2 other vertices.");
var input = new[] { (1, 2), (2, 1), (3, 4), (4, 3) };
var output = new InvalidDataException(
"Vertices [3, 4] are not connected with the rest of the graph.");
Method signature:
public static T[] GetVerticesFromEdges<T>((T, T)[] edges,
IEqualityComparer<T> comparer);
Upvotes: 0
Views: 387
Reputation: 3018
class EqualityComparerExtensions
that will return a value indicating if two edges are neighbors.
static class EqualityComparerExtensions
{
internal static bool Neighbours<T>(this IEqualityComparer<T> comparer,
Tuple<T, T> a, Tuple<T, T> b)
{
return comparer.Equals(a.Item1, b.Item1)
|| comparer.Equals(a.Item1, b.Item2)
|| comparer.Equals(a.Item2, b.Item1)
|| comparer.Equals(a.Item2, b.Item2);
}
}
Then the algorithm would be:
public static T[] GetVerticesFromEdges<T>(Tuple<T, T>[] edges,
IEqualityComparer<T> comparer)
{
var array = edges.Clone() as Tuple<T, T>[];
var last = array.Length - 1;
for (int i = 0; i < last; i++)
{
var c = 0;
for (int j = i + 1; j < array.Length; j++)
{
if (comparer.Neighbours(array[i], array[j]))
{
var t = array[i + 1];
array[i + 1] = array[j];
array[j] = t;
c++;
}
}
if (c > 2 || c == 0)
{
throw new ArgumentException($"{nameof(edges)} is not a Polygon!");
}
}
if (!comparer.Neighbours(array[last], array[0]))
{
throw new ArgumentException($"{nameof(edges)} is not a Polygon!");
}
for (int i = 0, j = 1; j < array.Length; i++, j++)
{
if (!comparer.Equals(array[i].Item2, array[j].Item1))
{
if (comparer.Equals(array[i].Item2, array[j].Item2))
{
array[j] = Tuple.Create(array[j].Item2, array[j].Item1);
}
else
{
array[i] = Tuple.Create(array[i].Item2, array[i].Item1);
}
}
}
if (!comparer.Equals(array[last].Item2, array[0].Item1))
{
throw new ArgumentException($"{nameof(edges)} is not a Polygon!");
}
return array.Select(a => a.Item1).ToArray();
}
Upvotes: 1
Reputation: 43553
Here is my solution.
public static T[] GetVerticesFromEdges<T>((T, T)[] edges,
IEqualityComparer<T> comparer)
{
if (edges.Length == 0) return new T[0];
var vertices = new Dictionary<T, List<T>>(comparer);
void AddVertex(T vertex, T connectedVertex)
{
if (!vertices.TryGetValue(vertex, out var connectedVertices))
{
connectedVertices = new List<T>();
vertices[vertex] = connectedVertices;
}
connectedVertices.Add(connectedVertex);
}
foreach (var edge in edges)
{
AddVertex(edge.Item1, edge.Item2);
AddVertex(edge.Item2, edge.Item1);
}
var invalid = vertices.Where(e => e.Value.Count != 2).Select(e => e.Key);
if (invalid.Any())
{
throw new InvalidDataException(
"Vertices [" + String.Join(", ", invalid) +
"] are not connected with exactly 2 other vertices.");
}
var output = new List<T>();
var currentVertex = vertices.Keys.First();
while (true)
{
output.Add(currentVertex);
var connectedVertices = vertices[currentVertex];
vertices.Remove(currentVertex);
if (vertices.ContainsKey(connectedVertices[0]))
{
currentVertex = connectedVertices[0];
}
else if (vertices.ContainsKey(connectedVertices[1]))
{
currentVertex = connectedVertices[1];
}
else
{
break;
}
}
if (vertices.Count > 0)
{
throw new InvalidDataException(
"Vertices [" + String.Join(", ", vertices.Keys) +
"] are not connected with the rest of the graph.");
}
return output.ToArray();
}
Upvotes: 0
Reputation: 1605
You trying to find connected components of an undirected graph. Strictly speaking, not connected components in general, but one component special case.
You can find more about them in Wikipedia page and/or take a look at an example implementation in C#
Upvotes: 0