2009-04-09 28 views
10

El dominio de interés es la coincidencia de cadenas. Supongamos que tengo una estructura como esta.¿Cómo harías para diseñar una función para un hash perfecto?

typedef struct 
{ 
    char *name, 
    int (*function)(); 

} StringArray 

StringArray s[] = 
{ 
    {"George", func1}, 
    {"Paul", func2}, 
    {"Ringo", func3}, 
    {"John", func4}, 
    {"",  NULL} /* End of list */ 
} 

Hay un número fijo de cadenas en la matriz. Están codificados como en el ejemplo. Si la tabla cambia, sería necesario volver a evaluar la calidad de la función hash.

Quiero aplicar una función hash a una cadena, y si la cadena coincide con una en la matriz, , llame a la función. Se necesita una función hash perfecta para esto. No se permiten colisiones. El propósito de requerir hashing es obtener un rendimiento de O (1) en la búsqueda.

¿Qué ideas tiene sobre el diseño de una función para hacer esto?

+0

No creo que el spam significa lo que creo que significa –

+0

@Mitch: ¿Quieres decir que esto es una pregunta que podría ser fácilmente buscado en Google para? –

+0

@ j_random_hacker: lo hice. Pero es tarde y no es spam ... –

Respuesta

16

Ver la página gperf casa.

+0

La parte de gaviota es que hay un enlace a esto en la parte inferior de la página de wikipedia. – EvilTeach

0

Puede utilizar un mapa

std::string foo() { return "Foo"; } 
std::string bar() { return "Bar"; } 

int main() 
{ 
    std::map<std::string, std::string (*)()> m; 
    m["foo"] = &foo; 
    m["bar"] = &bar; 
} 
+0

std :: el mapa no usa un hash - está basado en el árbol –

+0

por qué inventar la rueda, puede usar bibliotecas existentes como el mapa. – Vinay

+1

quizás el que pregunta quería las características de rendimiento de hash en lugar de las de búsqueda de árbol? –

1
+0

No aborda la pregunta directamente, pero buenos enlaces de todos modos. – EvilTeach

+0

¿Sería el downvoter (a esta pregunta muy antigua) por favor deje un comentario. Gracias. –

0

Si las colisiones son absolutamente no pueden, su única opción es hacer un seguimiento de cada cadena en la base de datos, lo que probablemente no es una mejor manera de ir.

Lo que yo haría es aplicar uno de los algoritmos hash fuertes comunes existentes, tales como: MD5 o SHA. Hay miríadas de muestras por todas partes, aquí hay una por ejemplo: http://www.codeproject.com/KB/security/cryptest.aspx

-1

Bueno, no hay una función hash perfecta.

Tiene varias que minimizan las colisiones, pero ninguna las elimina.

no puede aconsejar uno sin embargo: P

EDIT: La solución no puede ser encontrar una función hash perfecta. La solución es estar al tanto de las colisiones. Genéricamente una función hash tiene colisiones. Eso obviamente depende del conjunto de datos y del tamaño del código hash resultante.

+0

http://en.wikipedia.org/wiki/Perfect_hashing –

+0

@ Adam: Hay una advertencia bastante grande dado que solo se aplica cuando hay un conjunto de datos distinto. Como el OP no mencionó la limitación de las cadenas que se utilizan, estoy de acuerdo con Megacan en que no hay hash perfecto en este caso. +1. – sipwiz

+0

El autor de la pregunta menciona, al menos implícitamente -hay solo cuatro Beatles) o siz si incluye el baterista que saquearon y Stu whatsisname) - aún así, un conjunto de datos fijo. –

0

Utilice un árbol binario equilibrado. Entonces SABER el comportamiento es SIEMPRE O (logn).

No me gustan los hashes. La gente no se da cuenta de cuánto riesgo toman con su algoritmo. Ejecutan algunos datos de prueba y luego se implementan en el campo. NUNCA he visto un algoritmo hash implementado que se verifique el comportamiento en el campo.

O (log n) es casi siempre aceptable en lugar de O (1).

+0

"O (log n) es casi siempre aceptable en lugar de O (1)". En muchas aplicaciones, esta afirmación es completamente errónea. Simplemente aumente la cantidad de puntos de datos por encima de algunos millones para ver esto. –

+0

Una vez que hayas hecho eso, prueba. Los valores hash no dan resultados garantizados, a menos que sepa de antemano cuáles pueden ser todas las entradas posibles. Una función hash que tiende a agrupar la entrada probablemente no te dará O (1). –

+0

En este caso, se conocen todas las entradas. Están sentados en la matriz. y la cadena de entrada es una coincidencia exacta o no coincidencia. – EvilTeach

2

El resumen muestra tanto C como C++. ¿Cuál de ellos estás buscando? C y C++ son dos lenguajes distintos, y difieren mucho en su manejo de cadenas y estructuras de datos (y el hecho de que los C trabajen en C++ no cambia eso).

¿Por qué, específicamente, quieres una función hash perfecta? ¿Es que quieres asociar una cadena con una función y pensaste que sería una buena forma de hacerlo? ¿Es esto una especie de tarea asignada? ¿Tiene alguna razón para no usar el mapa <> en C++? (O unordered_map <> si está disponible?)

Si necesita un hash perfecta, ¿cuáles son las limitaciones de las cuerdas? ¿Habrá un cierto conjunto fijo en el que desea enviar? ¿Qué pasa con las cadenas que no coinciden con uno del conjunto? ¿Estás dispuesto a aceptar hits de cadenas aleatorias o la cantidad de cadenas entrantes es limitada?

Si pudieras editar tu pregunta para incluir información como esa, podríamos ser mucho más útiles.

EDITAR (en respuesta a los dos primeros comentarios):

bien, debemos buscar soluciones C, ya que presumiblemente quiere esto, tanto para su C y C++ trabajo. Es de suponer que quieres el rendimiento, pero has probado? Si se trata de cadenas que entran en el sistema de E/S, es probable que el tiempo disminuya el tiempo de despacho.

Está esperando cadenas arbitrarias. Es mucho esperar una función hash perfecta que evitará todas las colisiones de datos aleatorios, por lo que debe tenerlo en cuenta.

¿Has considerado un trie? Puede ser más eficiente que una función hash perfecta (o no), debería ser bastante fácil de implementar en C y evitará problemas al volver a hacer la lista de cadenas de envío o posibles colisiones.

+0

código en c y C++, y Dios me ayude Pro * C. O (1) hash para el rendimiento. Lol, sin tarea asignada. Estoy buscando construir una herramienta para acelerar algún código de rendimiento crítico. El ejemplo se simplifica para fines de discusión. El uso del mundo real no es. – EvilTeach

+0

Las cuerdas serán muy largas. Ninguno de ellos será de longitud cero. Como límite práctico, ninguna cadena en la matriz tendrá más de 32 caracteres. Lo que pase la persona que llama puede ser de cualquier longitud, pero si es más largo que las cuerdas de la tabla, es el caso de una no coincidencia – EvilTeach

+0

+1 por mencionar trie. –

0

El resultado final de este ejercicio era

  • robar un número de funciones hash orientada cuerda fuera de la red.
  • Cree un tipo de clase de fábrica que pruebe cada una de las funciones contra el conjunto de datos con un rango de valores de operador mod, buscando el hash perfecto más pequeño que funcione con esa función.
  • Ese constructor predeterminado de la clase de fábrica devuelve una cadena, que representa un conjunto de argumentos que cuando el uso selecciona la función hash correcta, y el tamaño del mod para proporcionar el hash perfecto que requiere la menor cantidad de memoria.
  • bajo uso normal, simplemente crea una instancia de la clase con los argumentos devueltos, y la clase se pone en un estado de trabajo con las funciones deseadas.
  • Ese constructor valida que no hay colisiones y cancela si hay.
  • En el caso de que no se encuentre un hash perfecto, se degrada en una búsqueda binaria en una versión ordenada de la tabla de entrada.

Para el conjunto de matrices que tengo en mi dominio, esto parece funcionar muy bien. Una posible optimización futura sería hacer el mismo tipo de prueba, en subcadenas de la entrada. En el caso de muestra, la primera letra del nombre de cada músico es suficiente para distinguirlos. Entonces uno necesitaría equilibrar el costo de la función de hash real contra la memoria utilizada.

Mi agradecimiento a todos los que contribuyeron ideas.

mal

Cuestiones relacionadas