web-dev-qa-db-fra.com

Méthode rapide pour implémenter le dictionnaire en C

Une des choses qui me manque en écrivant des programmes en C est une structure de données de dictionnaire. Quel est le moyen le plus pratique d’en implémenter un en C? Je ne cherche pas la performance, mais la facilité de le coder à partir de zéro. Je ne veux pas que ce soit générique non plus - quelque chose comme string-> int fera l'affaire. Mais je veux qu'il soit capable de stocker un nombre arbitraire d'articles.

Ceci est destiné plus comme un exercice. Je sais qu'il existe des bibliothèques tierces disponibles que l'on peut utiliser. Mais considérons un instant qu'ils n'existent pas. Dans une telle situation, quel est le moyen le plus rapide de mettre en place un dictionnaire répondant aux exigences ci-dessus.

113
Rohit

La section 6.6 de langage de programmation C présente une structure de données à dictionnaire simple (table de hachage). Je ne pense pas qu'une implémentation de dictionnaire utile puisse être plus simple. Pour votre commodité, je reproduis le code ici.

struct nlist { /* table entry: */
    struct nlist *next; /* next entry in chain */
    char *name; /* defined name */
    char *defn; /* replacement text */
};

#define HASHSIZE 101
static struct nlist *hashtab[HASHSIZE]; /* pointer table */

/* hash: form hash value for string s */
unsigned hash(char *s)
{
    unsigned hashval;
    for (hashval = 0; *s != '\0'; s++)
      hashval = *s + 31 * hashval;
    return hashval % HASHSIZE;
}

/* lookup: look for s in hashtab */
struct nlist *lookup(char *s)
{
    struct nlist *np;
    for (np = hashtab[hash(s)]; np != NULL; np = np->next)
        if (strcmp(s, np->name) == 0)
          return np; /* found */
    return NULL; /* not found */
}

char *strdup(char *);
/* install: put (name, defn) in hashtab */
struct nlist *install(char *name, char *defn)
{
    struct nlist *np;
    unsigned hashval;
    if ((np = lookup(name)) == NULL) { /* not found */
        np = (struct nlist *) malloc(sizeof(*np));
        if (np == NULL || (np->name = strdup(name)) == NULL)
          return NULL;
        hashval = hash(name);
        np->next = hashtab[hashval];
        hashtab[hashval] = np;
    } else /* already there */
        free((void *) np->defn); /*free previous defn */
    if ((np->defn = strdup(defn)) == NULL)
       return NULL;
    return np;
}

char *strdup(char *s) /* make a duplicate of s */
{
    char *p;
    p = (char *) malloc(strlen(s)+1); /* +1 for ’\0’ */
    if (p != NULL)
       strcpy(p, s);
    return p;
}

Notez que si les hachages de deux chaînes entrent en collision, cela peut conduire à un temps de recherche O(n). Vous pouvez réduire le risque de collision en augmentant la valeur de HASHSIZE. Pour une discussion complète de la structure des données, veuillez consulter le livre.

100
Vijay Mathew

Le moyen le plus rapide consisterait à utiliser une implémentation déjà existante, telle que thash .

Et, si vous voulez vraiment vouloir le coder vous-même, les algorithmes de uthash peuvent être examinés et réutilisés. Comme il est sous licence BSD, outre l’exigence de transmettre l’avis de droit d’auteur, son utilisation est pratiquement illimitée.

16
paxdiablo

Pour faciliter la mise en œuvre, il est difficile de battre naïvement la recherche dans un tableau. Mis à part une vérification d'erreur, il s'agit d'une implémentation complète (non testée).

typedef struct dict_entry_s {
    const char *key;
    int value;
} dict_entry_s;

typedef struct dict_s {
    int len;
    int cap;
    dict_entry_s *entry;
} dict_s, *dict_t;

int dict_find_index(dict_t dict, const char *key) {
    for (int i = 0; i < dict->len; i++) {
        if (!strcmp(dict->entry[i], key)) {
            return i;
        }
    }
    return -1;
}

int dict_find(dict_t dict, const char *key, int def) {
    int idx = dict_find_index(dict, key);
    return idx == -1 ? def : dict->entry[idx].value;
}

void dict_add(dict_t dict, const char *key, int value) {
   int idx = dict_find_index(dict, key);
   if (idx != -1) {
       dict->entry[idx].value = value;
       return;
   }
   if (dict->len == dict->cap) {
       dict->cap *= 2;
       dict->entry = realloc(dict->entry, dict->cap * sizeof(dict_entry_s));
   }
   dict->entry[dict->len].key = strdup(key);
   dict->entry[dict->len].value = value;
   dict->len++;
}

dict_t dict_new(void) {
    dict_s proto = {0, 10, malloc(10 * sizeof(dict_entry_s))};
    dict_t d = malloc(sizeof(dict_s));
    *d = proto;
    return d;
}

void dict_free(dict_t dict) {
    for (int i = 0; i < dict->len; i++) {
        free(dict->entry[i].key);
    }
    free(dict->entry);
    free(dict);
}
6
Paul Hankin

Créez une fonction de hachage simple et des listes de structures liées, en fonction du hachage, affectez la liste dans laquelle insérer la valeur. Utilisez le hachage pour le récupérer également.

J'ai fait une implémentation simple il y a quelque temps:

 ... 
 # définir K 16 // coefficient de chaînage 
 
 struct dict 
 {
 char * nom;/* nom de la clé */
 int val;/* valeur */
 struct dict * next;/* champ de lien */
}; 
 
 typedef struct dict dict; 
 dict * tableau [K]; 
 int initialisé = 0; 
 
 
 void putval (char *, int); 
 
 void init_dict () 
 {
 initialisé = 1; 
 Int i; 
 pour (i = 0; iname = (char *) malloc (strlen (nom_clé) +1); 
 ptr-> val = sval; 
 strcpy (ptr-> nom , nom_clé); 
 
 
 ptr-> suivant = (struct dict *) table [hsh]; 
 table [hsh] = ptr; 
 
} 
 
 
 int getval (char * nom_clé) 
 {
 int hsh = hash (nom_clé); 
 dict * ptr; 
 pour (ptr = table [hsh]; ptr! = (dict *) 0; 
 ptr = (dict *) ptr-> suivant) 
 if (strcmp (ptr-> nom, nom_clé) == 0) 
 renvoyer ptr-> val; 
 renvoyer -1; 
} 
3
abc def foo bar

voici un outil rapide, je l’ai utilisé pour obtenir un 'Matrix' (struct) d’une chaîne. vous pouvez avoir un plus grand tableau et changer ses valeurs lors de la course aussi:

typedef struct  { int** lines; int isDefined; }mat;
mat matA, matB, matC, matD, matE, matF;

/* an auxilary struct to be used in a dictionary */
typedef struct  { char* str; mat *matrix; }stringToMat;

/* creating a 'dictionary' for a mat name to its mat. lower case only! */
stringToMat matCases [] =
{
    { "mat_a", &matA },
    { "mat_b", &matB },
    { "mat_c", &matC },
    { "mat_d", &matD },
    { "mat_e", &matE },
    { "mat_f", &matF },
};

mat* getMat(char * str)
{
    stringToMat* pCase;
    mat * selected = NULL;
    if (str != NULL)
    {
        /* runing on the dictionary to get the mat selected */
        for(pCase = matCases; pCase != matCases + sizeof(matCases) / sizeof(matCases[0]); pCase++ )
        {
            if(!strcmp( pCase->str, str))
                selected = (pCase->matrix);
        }
        if (selected == NULL)
            printf("%s is not a valid matrix name\n", str);
    }
    else
        printf("expected matrix name, got NULL\n");
    return selected;
}
2
dagoltz

Je suis surpris que personne ne mentionne hsearch/hcreate ensemble de bibliothèques qui n'est pas disponible sous Windows, mais qui est mandaté par POSIX, et donc disponible sous Linux/GNU systèmes .

Le lien contient un exemple de base simple et complet qui explique très bien son utilisation.

Il a même une variante thread-safe, il est facile à utiliser et très performant.

2
fayyazkl

Une table de hachage est l'implémentation traditionnelle d'un simple "Dictionnaire". Si vous ne vous souciez pas de la vitesse ou de la taille, il suffit de Google . Il existe de nombreuses implémentations disponibles gratuitement.

voici le premier que j'ai v - en un coup d'œil, ça me convient. (C'est assez basique. Si vous voulez vraiment qu'il contienne une quantité illimitée de données, vous devrez alors ajouter une logique à "realloc" la mémoire de la table à mesure qu'elle grandit.)

bonne chance!

1
Lee

GLib et gnulib

Ce sont vos meilleurs choix si vous n'avez pas d'exigences plus spécifiques, car ils sont largement disponibles, portables et probablement efficaces.

Voir aussi: Existe-t-il des bibliothèques C open source avec des structures de données communes?

La méthode la plus rapide consisterait à utiliser un arbre binaire. Le pire des cas n’est que O (logn).

0
cprogrammer

Le hachage est la clé. Je pense utiliser la table de recherche et la clé de hachage pour cela. Vous pouvez trouver de nombreuses fonctions de hachage en ligne.

0
ashmish2