C# – 使用自定义键定义hashset

我在C#中使用HashSetDictionary来实现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覆盖EqualsGetHashCode (为简单起见可能是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 } 

…然后覆盖GetHashCodeEquals并在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将使用GetHashCodeEquals来确定相等性。

这就是为什么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 } }