C# – 使用自定义键定义hashset
我在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(); _VertexEdgeMapping = new Dictionary<Vertex, LinkedList>(); } private HashSet _Vertexes; private Dictionary<Vertex, LinkedList> _VertexEdgeMapping; }
问题是,当我有相同的顶点并且我想将它们添加到图形时,它们会被复制。 如何定义HashSet
理解顶点唯一性的方法?
选项:
- 在
Vertex
覆盖Equals
和GetHashCode
(为简单起见可能是Point
),很可能实现[IEquatable][1]
- 创建自己的
IEqualityComparer
实现,并将其传递给HashSet
的构造函数
第一个选项可能是最简单的,但我强烈建议您首先使Point
不可变:可变类型(或包含可变类型的类型)不能生成好的哈希键。 我也许会把它变成一个struct
:
public struct Point : IEquatable { 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 == px && y == py; } // TODO: Consider overloading the == and != operators }
…然后覆盖GetHashCode
和Equals
并在Vertex
实现IEquatable<>
,例如
// Note: sealed to avoid oddities around equality and inheritance public sealed class Vertex : IEquatable { 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); } }
正如其他人所说,覆盖Vertex
类的GetHashCode()
。
还要覆盖.Equals
方法。 Dictionary将使用GetHashCode
和Equals
来确定相等性。
这就是为什么Dictionary
不替换顶点的原因。 就Dictionary
而言,具有相同坐标的顶点仍然根本不同。
我不会用另一个源代码示例污染你的问题,因为Jon和gzaxx已经提供了2个非常好的例子。
覆盖Vertex
类的GetHashCode()
和Equals()
方法。
下面是示例,但您应该使用比我更好的哈希算法:)
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 } }