Как наилучшим образом добиться соответствия строк и чисел в программе c - PullRequest
5 голосов
/ 12 июля 2011

У меня есть определенный набор строк и соответствующие им номера:

kill -> 1
live -> 2
half_kill -> 3
dont_live -> 4

Список содержит 30 таких строк и их сопоставление номеров.

Если пользователь вводит "kill", мне нужно вернуть 1, а если он вводит "dont_live", мне нужно вернуть 4.

Как мне добиться этого в программе c? Я ищу эффективное решение, потому что эту операцию нужно делать сотни раз.

  • я должен поместить их в #define в моем файле .h?

Заранее спасибо.

Ответы [ 8 ]

8 голосов
/ 13 июля 2011

Сортируйте таблицу и используйте стандартную библиотечную функцию bsearch для выполнения двоичного поиска.

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

struct entry {
    char *str;
    int n;
};

/* sorted according to str */
struct entry dict[] = {
    "dont_live", 4,
    "half_kill", 3,
    "kill", 1,
    "live", 2,
};

int compare(const void *s1, const void *s2)
{
     const struct entry *e1 = s1;
     const struct entry *e2 = s2;

     return strcmp(e1->str, e2->str);
}

int
main (int argc, char *argv[])
{
    struct entry *result, key = {argv[1]};

    result = bsearch(&key, dict, sizeof(dict)/sizeof(dict[0]),
                     sizeof dict[0], compare);
    if (result)
        printf("%d\n", result->n);

    return 0;
}

Вот что вы получаете, когда запускаете программу.

$ ./a.out kill
1
$ ./a.out half_kill
3
$ ./a.out foo
<no output>

PS: я повторно использовал части программы Сидилла. Теперь мой ответ должен соответствовать CC BY-SA: p

5 голосов
/ 12 июля 2011

Возможное решение:

#include <stdio.h>
#include <string.h>

struct entry {
    char *str;
    int n;
};

struct entry dict[] = {
    "kill", 1,
    "live", 2,
    "half_kill", 3,
    "dont_live", 4,
    0,0
};

int
number_for_key(char *key)
{
    int i = 0;
    char *name = dict[i].str;
    while (name) {
        if (strcmp(name, key) == 0)
            return dict[i].n;
        name = dict[++i].str;
    }
    return 0;
}

int
main (int argc, char *argv[])
{
    printf("enter your keyword: ");
    char s[100]; scanf("%s", s);
    printf("the number is: %d\n", number_for_key(s));
    return 0;
}
3 голосов
/ 13 июля 2011

Вот один из подходов:

int get_index(char *s)
{
    static const char mapping[] = "\1.kill\2.live\3.half_kill\4.dont_live";
    char buf[sizeof mapping];
    const char *p;
    snprintf(buf, sizeof buf, ".%s", s);
    p = strstr(mapping, buf);
    return p ? p[-1] : 0;
}

Беспорядок . заключается в обходе kill, являющейся подстрокой half_kill.Без этой проблемы вы можете просто искать строку напрямую.

2 голосов
/ 12 июля 2011

Если это очень короткий список строк, то простого блока из if s будет более чем достаточно

if (0 == strcmp(value, "kill")) {
  return 1;
}
if (0 == strcmp(value, "live")) {
  return 2;
}
...

Если число приближается к 10, я бы начал профилировать свое приложение и рассматривать структуру стиля карты.

1 голос
/ 13 июля 2011

если у вас есть фиксированный набор стримов, у вас есть два варианта: сгенерировать идеальное хеширование (проверить gperf или cmph) или создать три, чтобы вам никогда не приходилось проверять символы более одного раза.Компиляторы обычно используют совершенные хэши для распознавания ключевого слова языка, в вашем случае, я бы, наверное, согласился с этим, это должен быть самый быстрый способ (но ничто не сравнится с прямым измерением!)

0 голосов
/ 20 августа 2017

Используйте hashmap / hashtable. Я думаю, что это будет лучшим решением.

0 голосов
/ 13 июля 2011

Создать список значений констант:

const int kill = 1; const int live = 2; const int half_kill = 3;

и т.д.

0 голосов
/ 12 июля 2011

Это действительно узкое место?Вы должны беспокоиться об эффективности, только если простое решение оказывается слишком медленным.

Сказав это, возможные улучшения скорости сначала проверяют длины:

If it's 4 characters then it could be "kill" or "live"
If it's 9 characters then it could be "half_kill" or "dont_live"

или проверяют первый символ воператор переключения:

switch (string[0]) {
case 'k':
    if (strcmp(string, "kill") == 0)
        return 1;
    return 0;
case 'l':
    ...
default:
    return 0;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...