Какую структуру данных я должен использовать - PullRequest
0 голосов
/ 10 февраля 2011

Я пытаюсь определить лучшую структуру данных, чтобы использовать для этой проблемы. Я реализую хранилище значений ключей с ключами, которые являются строками. Значения добавляются часто и, как правило, проверяются только 1 или 2 раза. Первоначально я использовал std::map, но я обнаружил, что производительность была неоптимальной, поскольку накладные расходы по добавлению ключей и перебалансировке красно-черного дерева затмили сокращение времени на поиск значения. В настоящее время я использую модифицированный единый связанный список. Он использует структуру, которая содержит строку c (const char *), длину в байтах и ​​сохраненное значение. Когда я хочу найти значение с помощью ключа, я перебираю список и сравниваю размер ключей, если они совпадают, я использую memcmp для проверки идентичности строк. Если они идентичны, я возвращаю значение. Я могу достичь примерно в 10 раз большей производительности, используя этот метод, чем std::map. Однако мне нужно сделать это примерно в 2 раза эффективнее. Кто-нибудь может порекомендовать лучший тип структуры данных, для этой проблемы?

Ответы [ 4 ]

3 голосов
/ 10 февраля 2011

Трудно найти быстрое решение без каких-либо знаний о реальной проблеме.В частности, насколько велик ваш набор данных, где хранятся реальные данные (хранятся ли они в контейнере или где-то еще?).Какие еще операции вам нужно выполнить над контейнером?Вам нужно удалить элементы из контейнера?

В качестве комментария к одному из других вопросов вы заявляете, что ключи должны быть скопированы в std::unordered_map ... если ключи уже хранятся где-то еще,Я бы посоветовал вам использовать карту, но избегайте копирования строк.Используйте указатели в качестве ключей и пользовательский компаратор для разыменования и работы в результате:

// Assuming that the data is stored in std::string somewhere else
struct custom_compare {
   bool operator()( std::string* lhs, std::string* rhs ) const {
      return lhs!=rhs && (lhs->size() < rhs->size() || lhs->compare( *rhs ) < 0);
   }
};
std::map< std::string*, data, custom_compare > mymap;

Хранение указателей вместо фактических строк избавит от копирования.Пользовательский компаратор в основном такой же быстрый, как и тот, который вы внедрили в список, и дерево будет уравновешивать содержимое, что позволяет выполнять O (log n) поисков.В зависимости от размера набора (если имеется много элементов), тогда это будет улучшение по сравнению с линейным поиском, в то время как при небольшом размере будет лучше линейный поиск.

Кроме того, в зависимости от разнообразияданные, вы можете следовать линейному поиску, но разделить пространство поиска в зависимости от некоторых критериев, которые можно быстро рассчитать и в то же время разделить набор как можно более равномерно.Например, вы можете использовать линейный поиск, но вместо одного списка сохраняйте разные списки в зависимости от длины ключа.

Если критерий фактически основан на содержимом строки (буквы, а не размер)тогда вы приближаетесь к определению дерева.Если вы получаете библиотеку, которая уже реализует ее, или вы готовы потратить время, необходимое для этого, trie, вероятно, будет одним из самых быстрых контейнеров для этого типа поиска, поскольку он преобразует переменную «size» из числаэлементы в длину строки.

3 голосов
/ 10 февраля 2011

std::vector должно выполняться быстрее, чем связанный список, и быстрее на push_back(), так как большую часть времени не требуется выделения памяти.

2 голосов
/ 10 февраля 2011

У вас есть один из ваших тегов ... почему бы не использовать Trie ?Вставки должны быть быстрыми, использование памяти может уменьшиться из-за совпадения символов, и поиск выполняется быстро.

0 голосов
/ 10 февраля 2011

Возможно, какая-то хеш-таблица?Использование хорошего алгоритма хеширования для ваших ключей значительно ускорит ваше время поиска.Ваше время вставки будет немного замедлено, но, надеюсь, не очень, если ваша хеш-функция хороша.

...