2011-03-04 7 views
10

Si tengo un conjunto de valores de cadena pequeños, y quiero buscar un valor numérico para representarlos, ¿cuál es la mejor manera de hacerlo a través de una tabla de búsqueda?Tabla de búsqueda de valor en C por cadenas?

Si sólo estabas necesitando hacer una mirada hacia arriba, sé que la solución óptima sería más que una serie de sentencias if:

if (strcmp(str, "foo") == 0) 
    tmp = FOO; 
else if (strcmp(str, "bar") == 0) 
    tmp = BAR; 

Pero, me pregunto porque estos pequeños valores de cadena representan un atributo en un pequeño proyecto estoy escribiendo en C, y los atributos pueden ser de solo lectura o de lectura y escritura (no solo de escritura por ahora, tal vez nunca).

Entonces, lo que hago actualmente para asegurarme de que todo funcione es tener una función de búsqueda compuesta por una cláusula if-then como la anterior para buscar valores que son de solo lectura y una segunda función que busca valores que se leen -escribir. Pero esto es grande y feo para mí.

Estoy pensando, tengo tres funciones en su lugar. Una función es la función de búsqueda, y devuelve un valor int que es la forma numérica de la cadena. Pero esta función de búsqueda también puede tomar un indicador que determina si recupera un valor de solo lectura o un valor de lectura y escritura. Si se realiza una operación de escritura en un valor que es realmente de solo lectura, la función devolverá -EINVAL (o algo equivalente).

Las otras dos funciones, ahora todavía las de lectura y escritura, simplemente llaman a esta función de búsqueda, pasando una cadena del valor y la bandera que determina si son para lectura o escritura.

La cosa es que no sé cómo esto se modela en C (si se puede modelar), y buscar en Google es tedioso con todas las granjas de contenido arrancando este lugar (y dándome C++/C# en su lugar) .

Así que esto es lo que pienso que se verá:

int lookup_func(const char *name, const char *flag) { 
    int tmpval = 0; 

    /* code to do the lookup. */ 

    if (tmpval == 0) 
     return -EINVAL; 
    else 
     return tmpval; 
} 

int get_readonly_bit(const char *name) { 
    return lookup_func(name, "ro"); 
} 

int get_readwrite_bit(const char *name) { 
    return lookup_func(name, "rw") 
} 

Pensamientos? La idea es reducir el tamaño del código al no repetir las ramas si-entonces para estas dos funciones, que difieren ligeramente en el diseño general, y simplemente dejar que algún tipo de función de búsqueda descubra a qué función sirve este valor.

+0

+1 para la const-corrección ... *, pero la bandera es mejor como un int (o enumeración) * – pmg

+0

deseado [función hash] (http://en.wikipedia.org/wiki/Hash_function) Dependiendo de sus valores de cadena, puede ser tan simple como devolver el valor de la primera letra ... – pmg

+0

@pmg: todavía hay una probabilidad de varias cadenas con el mismo hash. Pequeño, pero lo es :) –

Respuesta

6

¿No consideras poner una mesa? Una tabla hash también está bien si hay muchas propiedades.

int lookup(const char *name) 
{ 
    typedef struct item_t { const char *name; int writable; int value; } item_t; 
    item_t table[] = { 
    { "foo", 0, FOO }, 
    { "bar", 1, BAR }, 
    { NULL, 0, 0 } 
    }; 
    for (item_t *p = table; p->name != NULL; ++p) { 
     if (strcmp(p->name, prop_name) == 0) { 
      return p->value; 
     } 
    } 
    return -EINVAL; 
}
+0

Buena solución. Si solo le preocupa el código "grande y feo", debería hacerlo, ¿no? Si la tabla es larga y su programa realiza muchas búsquedas, trataría de trabajar en ese ciclo for-loop: p. busque una implementación de búsqueda binaria que se aplique a las cadenas y que esté escrita en c, por supuesto. – AudioDroid

+1

@AudioDroid: ¿qué es grande y feo al respecto? Es simple y comprensible y bastante robusto y lo he visto utilizado en muchos lugares. El algoritmo es O (n) que podría ser un problema para las listas largas. Sin embargo, si se trata de un problema debe determinarse con análisis de rendimiento, no conjeturas. – JeremyP

+0

Personalmente desanimo este tipo de solución para cualquier cosa que no sean listas triviales. Al usar cadenas de esta manera, el problema de la configuración regional y la sensibilidad a las mayúsculas y minúsculas puede ser problemático. Además, la eficiencia es sospechosa.Un strcmp implica una secuencia de comparaciones repetidas cuando una comparación de una clave hash sería suficiente. Al comparar el rendimiento de hashing con un strcmp, el método hash demuestra un mejor rendimiento para todas las listas menos triviales (en mi experiencia). – Throwback1986

Cuestiones relacionadas