Существует умный способ определить, к какой группе принадлежит слово.
Мы должны создать схему, в которой каждая группа однозначно идентифицируется номером. Как мы определяем и дифференцируем группу: по каким буквам она содержится. Повторяющиеся буквы не учитываются (это набор). Таким образом, нам нужна формула для кодирования набора букв группы. Если мы присваиваем каждой букве число (начиная с 0
), мы получаем идентификатор с помощью суммы степеней двух (на самом деле можно выбрать любое основание, но 2
является естественным выбором для вычислений).
например:.
"abdeae"
Набор букв {'a', 'b', 'd', 'e'}
. Их соответствующие номера: {0, 1, 3, 4}
и идентификатор 2^0 + 2^1 + 2^3 + 2^4
.
Поскольку существует 26
букв, мы можем использовать 32-битное целое число для кодирования идентификатора. 2^i
соответствует биту i
, поэтому алгоритм выглядит так:
uint32_t letter_mask(char ch)
{
assert(ch >= 'a' && ch <= 'z');
return (uint32_t) 1u << (ch - 'a');
}
uint32_t word_group_id(const char * str)
{
size_t len = strlen(str);
uint32_t id = 0;
for (size_t i = 0; i < len; ++i)
{
id |= letter_mask(str[i]);
}
return id;
}
Теперь, когда у нас есть простой способ определить группу слова, вам нужно создать упрощенную версию карты, куда поместить слова.
Это моя простая быстрая реализация. Отказ от ответственности: не проверено. Вы также должны улучшить его, добавив проверки для malloc и realloc.
typedef struct Word_map_bucket
{
uint32_t id;
char** words;
size_t words_size;
} Word_map_bucket;
void init_word_map_bucket(Word_map_bucket* bucket, uint32_t id)
{
bucket->id = id;
bucket->words = NULL;
bucket->words_size = 0;
}
typedef struct Word_map
{
Word_map_bucket* buckets;
size_t buckets_size;
} Word_map;
void init_word_map(Word_map* map)
{
map->buckets = NULL;
map->buckets_size = 0;
}
Word_map_bucket* find_bucket(Word_map map, uint32_t id)
{
for (size_t i = 0; i < map.buckets_size; ++i)
{
if (map.buckets[i].id == id)
return &map.buckets[i];
}
return NULL;
}
Word_map_bucket* add_new_bucket(Word_map* map, uint32_t id)
{
map->buckets = realloc(map->buckets, map->buckets_size + 1);
map->buckets_size += 1;
Word_map_bucket* bucket = &map->buckets[map->buckets_size + 1];
init_word_map_bucket(bucket, id);
return bucket;
}
void add_word(Word_map* map, const char* word)
{
// get to bucket
uint32_t id = word_group_id(word);
Word_map_bucket* bucket = find_bucket(*map, id);
if (bucket == NULL)
bucket = add_new_bucket(map, id);
// increase bucket->words
bucket->words = realloc(bucket->words, bucket->words_size + 1);
bucket->words_size += 1;
// push word into bucket
bucket->words[bucket->words_size - 1] = malloc(strlen(word));
strcpy(bucket->words[bucket->words_size - 1], word);
}