Каковы преимущества пользовательской структуры данных? - PullRequest
0 голосов
/ 22 сентября 2018

Что нужно для определения и реализации структур данных (например, stack), если они уже доступны в C ++ STL ?

Что такоеразличия между двумя реализациями?

Ответы [ 2 ]

0 голосов
/ 23 сентября 2018

STL реализация структур данных не идеальна для каждый возможный вариант использования .

Мне нравится пример хеш-таблиц.Я уже некоторое время использую реализацию STL, но использую ее в основном для соревнований по конкурентному программированию.

Представьте, что вы Google, и у вас есть миллиарды долларов в ресурсах, предназначенных дляхранение и доступ к хеш-таблицам .Возможно, вы хотели бы иметь наилучшую возможную реализацию для случаев использования в компании, поскольку она экономит ресурсы и делает поиск быстрее в целом.О, и я забыл упомянуть, что у вас также есть несколько лучших инженеров на планете, которые работают на вас (:

(Это видео сделано Kulukundis, рассказывающим о новой хэш-таблице, созданной его командой в Google)https://www.youtube.com/watch?v=ncHmEUmJZf4

Некоторые другие причины, оправдывающие реализацию вашей собственной версии структур данных:

  • Проверьте ваше понимание определенной структуры .

  • Адаптируйте часть конструкции для некоторого специфического варианта использования .

  • Поиск лучшей производительности, чем STL для конкретной структуры данных.

  • Ненависть к ошибкам STL.

  • Сравнительный анализ STL против некоторой простой реализации.

0 голосов
/ 22 сентября 2018

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

Тогда возникает проблема качества реализации.Стандартная реализация может не подойти вам.

Позвольте мне привести пример.Действительно, std::stack реализует стек.Это универсальная реализация.Вы измерили sizeof(std::stack<char>)?Вы сравнивали его с миллионами стеков в среднем по 3,2 элемента с распределением Пуассона ?

Возможно, в вашем случае вы знаете,что у вас есть миллионы стеков char -s (никогда NUL ), и что 99% из них имеют менее 4 элементов.Обладая этими дополнительными знаниями, вы, вероятно, сможете реализовать нечто «лучшее», чем то, что обеспечивает стандартный стек C ++.Так что std::stack<char> будет работать, но с учетом этих дополнительных знаний вы сможете реализовать их по-другому.Вы по-прежнему (для удобства чтения и обслуживания) будете использовать те же методы , что и в std::stack<char> - так что ваш WeirdSmallStackOfChar будет иметь метод push и т. Д. Если (позже в ходе проекта) вы поймете илиэтот большой стек может быть полезен (например, в 1% случаев), вы переопределяете свой стек по-другому (например, если ваша кодовая база вырастет до миллиона строк C ++ и вы понимаете, что у вас довольно часто большие стеки, вы можете «удалить»)ваш WeirdSmallStackOfChar класс и добавьте typedef std::stack<char> WeirdSmallStackOfChar; ....)

Если вам случится узнать, что все ваши стеки имеют менее 4 char -х и что \0в них недопустимо, поэтому представление таких «стеков» в виде поля char w[4], вероятно, является самым разумным подходом.Кодирование выполняется быстро и просто.

Так что, если производительность и объем памяти имеют значение, возможно, вы можете закодировать что-то странное, например

class MyWeirdStackOfChars {
   bool small;
   union {
     std::stack<char>* bigstack;
     char smallstack[4];
   }

Конечно, это очень неполно.Когда small истинно, ваша реализация использует smallstack.В случае 1%, где оно ложно, ваша реализация использует bigstack.Остальное MyWeirdStackOfChars оставлено читателю в качестве упражнения (не так просто).Не забудьте следовать правилу из пяти .

Хорошо, возможно, приведенный выше пример не убедителен.Но как насчет std::map<int,double>?У вас может быть миллионы из них, и вы можете знать, что 99,5% из них меньше 5. Вы, очевидно, могли бы оптимизировать для этого случая.Весьма вероятно, что представление небольших карт массивом пар int & double более эффективно как с точки зрения памяти, так и с точки зрения процессорного времени.

Иногда вы даже знаете, что all на ваших картах менее 16 записей (и std::map<int,double> не знают этого), и ключ равен never 0. Тогда вы можете представить их по-другому.В этом случае, я предполагаю, что я могу реализовать нечто гораздо более эффективное, чем то, что обеспечивает std::map<int,double> (возможно, из-за эффектов cache , массива из 16 записей с int и double является самым быстрым).

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

...