В вашем коде много проблем (о чем свидетельствуют комментарии к вопросу), я перечислю их в конце ответа, поскольку они не связаны с ядром вопроса.
Проблемная строка, какВы подозревали, что это строка:
unordered_map<char*, unordered_map<char*, int> > nodes
Как вы сказали
это потому, что char * на самом деле является строковым значением, но адресом, и они указывают на разные адреса.
Другими словами, ваши строки (кмеры) сравниваются как указатели.Если двум char *
объектам назначаются два разных вызова malloc, то они имеют разные адреса.unordered_map
сравнивает только адрес, а не набор символов, которые находятся по адресу.
Решение состоит в том, чтобы начать использовать строки C ++, а не строки с нулем в конце:
std::unordered_map<std::string, std::unordered_map<std::string, int> > nodes
Это исправит другие проблемы, которые возникают в вашем коде:
- Ваш код имеет утечку памяти.Он выделяет память с помощью malloc и никогда не освобождает ее.Использование
std::string
решает проблему. - kmers имеют тенденцию быть относительно короткими строками (большинство из них ниже 12 букв).
std::string
оптимизирован именно для этого случая и полностью исключает кучу памяти для этих строк.Код будет работать намного быстрее с std::string
, избегая ненужных выделений кучи.
Другой вариант, который менее желателен, заключается в предоставлении собственных функций Hash и KeyEqual:
class cstr_hash
{
public:
std::size_t operator()(const char *cstr) const
{
std::size_t hash = 5381;
for ( ; *cstr != '\0' ; ++cstr)
hash = (hash * 33) + *cstr;
return hash;
}
};
class cstr_eq
{
public:
using value_type = const char*;
bool operator()(const char* a, const char *b) const
{ return strcmp(a, b) == 0; }
};
и затем используйте карту:
std::unordered_map<const char *, int, cstr_hash, cstr_eq> nodes;
Но такой подход не рекомендуется, поскольку он затрудняет предотвращение утечек памяти и не оптимизирует короткие строки, как std::string
.
Некоторые другие проблемы, связанные с вашим кодом:
char* kmers[num_kmers][3];
Это не C ++.Большинство компиляторов поддерживают VLA (массив переменной длины), но это не является частью стандарта.Лучше использовать std::vector<std::string>
.
Утечки памяти.Вы выделяете строки с помощью malloc и никогда не освобождаете их.Лучше использовать std :: string и передать его так, чтобы malloc больше не использовался в коде.
unordered_map
обычно менее эффективен, чем std::map
для контейнеров с менее чем 10 000 элементов.С данными генома есть некоторый шанс, что вы попали в тот случай, когда std::unordered_map
того стоит, но я бы протестировал это (особенно для внутреннего контейнера).
Другая проблема заключается в использовании std::endl
, который может замедлить выполнение кода в 2-10 раз.Вы должны использовать '\n'
вместо endl
.endl
выполняет очистку вывода в конце строки.Дополнительный системный вызов во многих случаях имеет большое значение с точки зрения производительности.Конечно, если это просто отладочный код, это не имеет значения.