1

ハッシュテーブルに入れたい頂点がいくつかあります。互いに非常に近い頂点は、同じ頂点と見なされます。私の C# 頂点クラスは次のようになります。

public class Vertex3D
{
    protected double _x, _y, _z;
    public static readonly double EPSILON = 1e-10;

    public virtual double x 
    {
        get { return _x;}
        set { _x = value; }
    }

    public virtual double y
    {
        get { return _y; }
        set { _y = value; }
    }

    public virtual double z
    {
        get { return _z; }
        set { _z = value; }
    }

    public Vertex3D(double p1, double p2, double p3)
    {
        this._x = p1;
        this._y = p2;
        this._z = p3;
    }

    public override bool Equals(object obj)
    {
        var other = obj as Vertex3D;

        if (other == null)
        {
            return false;
        }
        double diffx = this.x - other.x;
        double diffy = this.y - other.y;
        double diffz = this.z - other.z;
        bool eqx = diffx > -EPSILON && diffx < EPSILON;
        bool eqy = diffy > -EPSILON && diffy < EPSILON;
        bool eqz = diffz > -EPSILON && diffz < EPSILON;
        return eqx && eqy && eqz;
    }

    public override int GetHashCode()
    {
        return this.x.GetHashCode() ^ this.y.GetHashCode() ^ this.z.GetHashCode();
    }

    public override string ToString()
    {
        return "Vertex:" + " " + x + " " + y + " " + z;
    }

次の 2 つの頂点をディクショナリに入れたとします (ディクショナリは、null キーを許可しないハッシュテーブルです)。

    Dictionary<Vertex3D, Vertex3D> vertexList = new Dictionary<Vertex3D, Vertex3D>();
    Vertex3D v0 = new Vertex3D(0.000000000000000037842417475065449, -1,   0.00000000000000011646698526992202));
    Vertex3D v1 = new Vertex3D(0, -1, 0));
    vertexList.Add(v0, v0);
    vertexList.Add(v1, v1);

問題は、equals と hashcode の実装に問題があることです。上記の 2 つの頂点は、互いの距離が EPSILON よりも小さいため、等しいと見なされます。しかし、それらは同じハッシュコードを返しません。

equals と hashcode を正しく実装するにはどうすればよいですか?

4

2 に答える 2

1

一般に、変更可能なものへの参照は、両方が同じオブジェクトを参照している場合にのみ同等と見なされます。不変のものへの参照のみが、他の同等の定義を使用する必要があります。Object2 つの参照が別々のオブジェクトによって保持されており、どちらもそれを変更する可能性のあるものへの参照を公開しないというシナリオで、等価性をテストするための仮想関数が含まれていると便利です。残念ながら、可変型の事実上の不変インスタンス パターンは非常に一般的ですが (たとえば、ほとんどすべての不変コレクションは、配列などの可変型オブジェクトを 1 つ以上使用してデータを保持します)、標準パターンはありません。それとの同等性テスト。

Object.Equals等値テストに使用するディクショナリに頂点を格納する場合は、不変型である必要があります。別の方法として、辞書で使用するためのカスタムを定義することもできますが、完全な一致を見つけるためにのみ使用するIEqualityComparer<T>必要があることに注意してください。特定のポイント内にある任意のポイントを見つけられるようにする場合は、丸められた値を正確な値のリストにマップする を使用する必要があります (値は、イプシロンの少なくとも 2 倍の 2 のべき乗に丸められる必要があります)。ポイント内の一部またはすべての座標から EPSILON を加算または減算すると、丸めが異なる場合、そのポイントをディクショナリに含めて、可能な限りすべての方法で丸める必要があります。DictionaryEPSILON

于 2013-07-11T16:54:45.547 に答える