2011-10-28 17 views
6

He creado una estructura de datos "Coordinar" personalizada que define la posición de un objeto según un sistema determinado.¿Cómo puedo hacer un código hash para una estructura de datos personalizada?

una coordenada se define como sigue:

public class Coordinate 
{ 
    public int X; 
    public int Y; 
    private int face; 
    public int Face 
    { 
     get { return face; } 
     set 
     { 
      if (value >= 6 | value < 0) 
       throw new Exception("Invalid face number"); 
      else 
       face = value; 
     } 
    } 
    private int shell; 
    public int Shell 
    { 
     get { return shell; } 
     set 
     { 
      if (value < 0) 
       throw new Exception("No negative shell value allowed"); 
      else 
       shell = value; 
     } 
    } 

    public Coordinate(int face, int x, int y, int shell) 
    { 
     this.X = x; 
     this.Y = y; 
     this.face = face; 
     this.shell = shell; 
    } 

    public static Coordinate operator +(Coordinate a, Coordinate b) 
    { 
     return new Coordinate(a.Face + b.Face, a.X + b.X, a.Y + b.Y, a.Shell + b.Shell); 
    } 

    public override bool Equals(object obj) 
    { 
     Coordinate other = (obj as Coordinate); 
     if (other == null) 
      return false; 
     else 
      return (Face == other.Face && Shell == other.Shell && X == other.X && Y == other.Y); 
    } 
} 

O, para resumir, que contiene una cara int (0 a 5), ​​un int X, int Y, e INT Shell. X, Y y Shell están todos vinculados a continuación en 0 (inclusive).

No tengo ninguna experiencia en absoluto en los códigos hash. Necesito compararlos para ver si son iguales. Intenté esto:

private const int MULTIPLIER = 89; 

[...] 

int hashCode = 1; 
hashCode = MULTIPLIER * hashCode + obj.X.GetHashCode(); 
hashCode = MULTIPLIER * hashCode + obj.Y.GetHashCode(); 
hashCode = MULTIPLIER * hashCode + obj.Face.GetHashCode(); 
hashCode = MULTIPLIER * hashCode + obj.Shell.GetHashCode(); 
return hashCode; 

Saliendo algo que encontré mientras buscaba en Google. Pero cuando intento compilar el código con este método, estoy bastante seguro de que se encuentra con colisiones, ya que nunca termina de construirse. Probablemente metiéndose en todo tipo de bucles desordenados, pensando que un montón de coordenadas son las mismas o algo así.

Lamento que esta pregunta sea bastante elemental, pero por alguna razón estoy perplejo. Solo estoy buscando consejos sobre cómo escribir este código hash para que no colisione.

+2

No hay ningún problema si los códigos hash colisionan. Es preferible no tener colisiones, pero no es necesario (y matemáticamente tampoco es posible). – Jon

+0

http://msdn.microsoft.com/en-us/library/system.object.gethashcode%28v=vs.71%29.aspx - "Las clases derivadas deben anular GetHashCode con una implementación que devuelve un código hash único. " –

+1

@MattFenwick Debido al principio del casillero, no existe un código hash único para la mayoría de los tipos.* Ese artículo es un poco inexacto. Quitaron esa línea en las siguientes versiones. * - 'int.GetHashCode()' es probablemente único para cada número. –

Respuesta

11

Si bien esta no es la mejor manera, puede ser una buena aproximación suficiente:

public override int GetHashCode() 
{ 
    return string.Format("{0}-{1}-{2}-{3}", X, Y, Face, Shell).GetHashCode(); 
} 

Actualización: Tome un vistazo a este artículo: http://ericlippert.com/2011/02/28/guidelines-and-rules-for-gethashcode/

+0

Esto se ve muy bien, gracias. Traté de multiplicar cada componente por 100000, 10000, 1000 y 1 antes de obtener esto, pero esto es más limpio y extensible. –

+0

Bueno, todavía no se construye ... Guardaré este código hash y haré algunas pruebas unitarias para ver si estoy haciendo algo diferente. –

+0

Debería haber dicho "todavía se atasca", no "no construye". No hay errores de compilador El juego simplemente se queda atascado en un bucle que usa los códigos hash. –

2

Básicamente, cuando se escribe código hash funciones, debe asegurarse de que:

  • no tiene códigos hash rancios (es decir, el estado del objeto no debe cambio después de un código hash ha sido generado, de manera que el código hash cambiaría si regenerado)
  • objetos con valores iguales devuelven los mismos hashcodes
  • el mismo objeto siempre devuelve el mismo código hash (si no es modificada) - deterministas

Además, es muy bueno, pero no es necesario, si:

  • sus hashcodes se dispersan de manera uniforme sobre los valores posibles (fuente: Wikipedia)

Usted no necesita asegurarse de que los diferentes objetos devuelvan códigos hash diferentes. Solo está mal visto porque puede disminuir el rendimiento de cosas como Hashtables (si tienes muchas colisiones).

Sin embargo, si aún desea que su función de código hash devuelva valores únicos, querrá saber acerca de perfect hashing.

Cuestiones relacionadas