我在C#中使用HashSet
和Dictionary
来实现Graph结构。当HashSet
键是自定义类时,HashSet
元素的唯一性存在问题。我在这里:
public class Point
{
public int x { get; set; }
public int y { get; set; }
}
public class Vertex
{
public Vertex(Point point)
{
VertexLabel = point;
}
public Point VertexLabel { get; private set; }
}
public class Edge
{
public Edge(Vertex to, Vertex from, double weight)
{
FromVertex = from;
ToVertex = to;
Weight = weight;
}
public Vertex FromVertex { get; private set; }
public Vertex ToVertex { get; private set; }
public double Weight { get; private set; }
}
public class Graph
{
public Graph()
{
_Vertexes = new HashSet<Vertex>();
_VertexEdgeMapping = new Dictionary<Vertex, LinkedList<Edge>>();
}
private HashSet<Vertex> _Vertexes;
private Dictionary<Vertex, LinkedList<Edge>> _VertexEdgeMapping;
}
问题在于,当我有相同的顶点并且我想将它们添加到图形时,它们会被复制。如何定义HashSet
理解顶点唯一性的方法?
答案 0 :(得分:26)
选项:
Equals
中的GetHashCode
和Vertex
(为简单起见可能Point
),很可能会随时实施IEquatable<T>
IEqualityComparer<Vertex>
实现并将其传递给HashSet<Vertex>
第一个选项很可能是最简单的,但是我强烈 强烈推荐你先使Point
不可变:可变类型(或包含可变类型的类型)不能很好哈希键。我也许会把它变成struct
:
public struct Point : IEquatable<Point>
{
private readonly int x, y;
public int X { get { return x; } }
public int Y { get { return y; } }
public Point(int x, int y)
{
this.x = x;
this.y = y;
}
public override int GetHashCode()
{
return 31 * x + 17 * y; // Or something like that
}
public override bool Equals(object obj)
{
return obj is Point && Equals((Point) obj);
}
public bool Equals(Point p)
{
return x == p.x && y == p.y;
}
// TODO: Consider overloading the == and != operators
}
...然后覆盖GetHashCode
和Equals
并在IEquatable<>
中实施Vertex
,例如。
// Note: sealed to avoid oddities around equality and inheritance
public sealed class Vertex : IEquatable<Vertex>
{
public Vertex(Point point)
{
VertexLabel = point;
}
public Point VertexLabel { get; private set; }
public override int GetHashCode()
{
return VertexLabel.GetHashCode();
}
public override bool Equals(object obj)
{
return Equals(obj as Vertex);
}
public bool Equals(Vertex vertex)
{
return vertex != null && vertex.VertexLabel.Equals(VertexLabel);
}
}
答案 1 :(得分:4)
正如其他人所说,覆盖GetHashCode()
类的Vertex
。
同时覆盖.Equals
方法。字典将使用GetHashCode
和Equals
来确定相等。
这就是Dictionary
没有替换顶点的原因。就Dictionary
而言,具有相同坐标的顶点仍然根本不同。
我不会用另一个源代码示例污染你的问题,因为Jon和gzaxx已经提供了2个非常好的例子。
答案 2 :(得分:3)
覆盖GetHashCode()
类的Equals()
和Vertex
方法。
下面是示例,但您应该使用比我更好的哈希算法:)
public class Vertex
{
public Vertex(Point point)
{
VertexLabel = point;
}
public Point VertexLabel { get; private set; }
public override int GetHashCode()
{
return VertexLabel.X + VertexLabel.Y;
}
public override bool Equals(object obj)
{
//your logic for comparing Vertex
}
}