2013-08-06 23 views
9

Tôi đang sử dụng HashSet và Dictionary trong C# để triển khai cấu trúc Graph. Tôi gặp vấn đề với tính duy nhất của các phần tử băm khi khóa băm là một lớp được tùy chỉnh. Ở đây tôi có:C# - xác định hashset với khóa tùy chỉnh

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; 
} 

Vấn đề là khi tôi có cùng một đỉnh và tôi muốn thêm chúng vào biểu đồ, chúng sẽ được nhân đôi. làm thế nào tôi có thể xác định một cách mà các HashSet sẽ hiểu được sự độc đáo của các đỉnh của tôi?

+0

Theo định nghĩa, giá trị băm sẽ luôn giống nhau nếu cùng một giá trị được truyền dưới dạng đầu vào. Nếu bạn có hai đỉnh với chính xác cùng một giá trị, chúng sẽ có cùng một giá trị băm. Bạn có chắc chắn muốn sử dụng HashSet không? EDIT: Khi đọc lần hai, có vẻ như bạn muốn tránh các đỉnh trùng lặp giống nhau. Nếu vậy, nếu chúng có cùng điểm bắt đầu và điểm kết thúc, thì có thể có một số biến khác khác. Bạn đã thử sử dụng một cái gì đó giống như một Tuple của các cặp đặt hàng đại diện cho điểm bắt đầu và kết thúc của Vertex? – IllusiveBrian

+1

@Namfuak Điều đó không đúng. Vui lòng tạo hai đối tượng Vertex có cùng giá trị điểm và so sánh GetHashCode. Ví dụ: – Paparazzi

Trả lời

23

Options:

  • Override EqualsGetHashCode trong Vertex (và có lẽ Point vì đơn giản), hoàn toàn có thể triển khai [IEquatable][1]<T> khi bạn đi
  • Tạo triển khai của riêng bạn IEqualityComparer<Vertex> và chuyển đến constructor của HashSet<Vertex>

Tùy chọn đầu tiên có khả năng là đơn giản, nhưng tôi sẽ mạnh khuyên bạn thực hiện Point bất biến đầu tiên: có thể thay đổi các loại (hoặc các loại có chứa các loại có thể thay đổi) không thực hiện băm tốt phím. Tôi có lẽ muốn làm cho nó một struct, quá:

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 
} 

... sau đó ghi đè GetHashCodeEquals và thực hiện IEquatable<> trong Vertex quá, ví dụ

// 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); 
    } 
}  
+5

Đối với những người tự hỏi tại sao anh ta nhân 'x' và' y' bằng hằng số, nó giúp phân phối mã băm hơn. Điều này làm cho một điểm với 'X = 12' và' Y = 13' có một mã băm khác với một điểm với một 'X = 13' và' Y = 12'. –

+2

Tôi nghĩ bạn đã bỏ lỡ từ khóa 'override' trên' public virtual bool Equals (đối tượng obj) ' – Romoku

+0

@Romoku: Yup, xong. –

3

Ghi đè GetHashCode()Equals() phương thức của Vertex lớp.

Dưới đây là ví dụ, nhưng bạn nên sử dụng một chút tốt hơn thuật toán băm hơn tôi :)

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 
    } 
} 
+1

+1.Đó hashcode có lẽ là ví dụ tôi đã cung cấp quá haha. –

4

Như những người khác đã nói, ghi đè GetHashCode() của lớp Vertex.

Cũng ghi đè phương thức .Equals. Từ điển sẽ sử dụng cả hai số GetHashCodeEquals để xác định sự bình đẳng.

Đây là lý do tại sao Dictionary không thay thế đỉnh. Các đỉnh có cùng tọa độ vẫn khác nhau về cơ bản với mức độ liên quan là Dictionary.

Tôi sẽ không gây ô nhiễm câu hỏi của bạn với một ví dụ mã nguồn khác như Jon và gzaxx đã cung cấp 2 ví dụ rất tốt rồi.

Các vấn đề liên quan