stringtranslate.com

Ассоциативный массив

В информатике ассоциативный массив , карта , таблица символов или словарь — это абстрактный тип данных , который хранит коллекцию пар (ключ, значение) , так что каждый возможный ключ появляется в коллекции не более одного раза. В математических терминах ассоциативный массив — это функция с конечным доменом . [ 1] Он поддерживает операции «поиск», «удаление» и «вставка».

Задача о словаре — это классическая задача проектирования эффективных структур данных , реализующих ассоциативные массивы. [2] Двумя основными решениями задачи о словаре являются хэш-таблицы и деревья поиска . [3] [4] [5] [6] Иногда также возможно решить задачу, используя напрямую адресуемые массивы , двоичные деревья поиска или другие более специализированные структуры.

Многие языки программирования включают ассоциативные массивы как примитивные типы данных , в то время как многие другие языки предоставляют библиотеки программного обеспечения , которые поддерживают ассоциативные массивы. Содержимое адресуемой памяти является формой прямой аппаратной поддержки ассоциативных массивов.

Ассоциативные массивы имеют множество приложений, включая такие фундаментальные шаблоны программирования , как мемоизация и шаблон декоратора . [7]

Название не происходит от ассоциативного свойства, известного в математике. Скорее, оно возникает из ассоциации значений с ключами. Его не следует путать с ассоциативными процессорами .

Операции

В ассоциативном массиве связь между ключом и значением часто называется «сопоставлением»; это же слово может также использоваться для обозначения процесса создания новой ассоциации.

Операции, которые обычно определяются для ассоциативного массива: [3] [4] [8]

Вставить или положить
добавить новую пару в коллекцию, сопоставляя ключ с его новым значением. Любое существующее сопоставление перезаписывается. Аргументами этой операции являются ключ и значение.
Удалить или удалить
удалить пару из коллекции, отменив сопоставление заданного ключа с его значением. Аргументом этой операции является ключ.
Поиск, поиск или получение
найти значение (если есть), привязанное к данному ключу. Аргументом этой операции является ключ, а значение возвращается из операции. Если значение не найдено, некоторые функции поиска вызывают исключение , в то время как другие возвращают значение по умолчанию (например, ноль, null или определенное значение, переданное конструктору).

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

Мультикарта обобщает ассоциативный массив, позволяя связывать несколько значений с одним ключом. [9] Двунаправленная карта — это связанный абстрактный тип данных, в котором сопоставления работают в обоих направлениях: каждое значение должно быть связано с уникальным ключом, а вторая операция поиска принимает значение в качестве аргумента и ищет ключ, связанный с этим значением.

Характеристики

Операции ассоциативного массива должны удовлетворять различным свойствам: [8]

где kи jявляются ключами, v— значением, D— ассоциативный массив, а new()создает новый, пустой ассоциативный массив.

Пример

Предположим, что набор выданных библиотекой книг представлен в структуре данных. Каждая книга в библиотеке может быть выдана одним читателем за раз. Однако один читатель может выдать несколько книг. Таким образом, информация о том, какие книги выданы каким читателям, может быть представлена ​​ассоциативным массивом, в котором книги являются ключами, а читатели — значениями. Используя нотацию Python или JSON , структура данных будет выглядеть следующим образом:

{ "Гордость и предубеждение" : "Алиса" , "Грозовой перевал" : "Алиса" , "Большие надежды" : "Джон" }      

Операция поиска по ключу "Great Expectations" вернет "John". Если Джон вернет свою книгу, это вызовет операцию удаления, а если Пэт извлечет книгу, это вызовет операцию вставки, что приведет к другому состоянию:

{ "Гордость и предубеждение" : "Алиса" , "Братья Карамазовы" : "Пэт" , "Грозовой перевал" : "Алиса" }      

Выполнение

Для словарей с очень небольшим количеством отображений может иметь смысл реализовать словарь с использованием списка ассоциаций , который является связанным списком отображений. При такой реализации время выполнения основных операций словаря линейно зависит от общего числа отображений. Однако его легко реализовать, а постоянные факторы во времени его выполнения малы. [3] [10]

Другой очень простой метод реализации, применимый, когда ключи ограничены узким диапазоном, — это прямая адресация в массив: значение для заданного ключа k сохраняется в ячейке массива A [ k ], или, если для k нет сопоставления , то ячейка сохраняет специальное контрольное значение , которое указывает на отсутствие сопоставления. Этот метод прост и быстр, при этом каждая операция со словарем занимает постоянное время. Однако требование к пространству для этой структуры равно размеру всего пространства ключей, что делает его непрактичным, если только пространство ключей не мало. [5]

Два основных подхода к реализации словарей — это хэш-таблица и дерево поиска . [3] [4] [5] [6]

Реализации хэш-таблиц

Этот график сравнивает среднее количество промахов кэша ЦП , необходимых для поиска элементов в больших хэш-таблицах (намного превышающих размер кэша) с цепочкой и линейным зондированием . Линейное зондирование работает лучше из-за лучшей локальности ссылок , хотя по мере заполнения таблицы его производительность резко падает.

Наиболее часто используемая универсальная реализация ассоциативного массива — это хэш-таблица : массив , объединенный с хэш-функцией , которая разделяет каждый ключ на отдельный «корзину» массива. Основная идея хэш-таблицы заключается в том, что доступ к элементу массива через его индекс — это простая операция с постоянным временем. Поэтому средние накладные расходы на операцию для хэш-таблицы — это только вычисление хеша ключа в сочетании с доступом к соответствующей корзине в массиве. Таким образом, хэш-таблицы обычно выполняются за время O(1) и обычно превосходят альтернативные реализации.

Хэш-таблицы должны уметь обрабатывать коллизии : отображение хэш-функцией двух разных ключей в один и тот же контейнер массива. Два наиболее распространенных подхода к этой проблеме — раздельное связывание и открытая адресация . [3] [4] [5] [11] При раздельном связывании массив не хранит само значение, а хранит указатель на другой контейнер, обычно список ассоциаций , который хранит все значения, соответствующие хешу. Напротив, при открытой адресации, если обнаруживается коллизия хеша, таблица ищет пустое место в массиве для сохранения значения детерминированным образом, обычно путем просмотра следующей непосредственной позиции в массиве.

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

Реализации дерева

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

Другим распространенным подходом является реализация ассоциативного массива с самобалансирующимся бинарным деревом поиска , таким как дерево AVL или красно-черное дерево . [12]

По сравнению с хэш-таблицами эти структуры имеют как сильные, так и слабые стороны. Худшая производительность самобалансирующихся бинарных деревьев поиска значительно лучше, чем у хэш-таблицы, с временной сложностью в нотации big O O(log n ). Это контрастирует с хэш-таблицами, чья худшая производительность включает в себя все элементы, совместно использующие один контейнер, что приводит к временной сложности O( n ). Кроме того, как и все бинарные деревья поиска, самобалансирующиеся бинарные деревья поиска сохраняют свои элементы в порядке. Таким образом, обход ее элементов следует шаблону от наименьшего к наибольшему, тогда как обход хэш-таблицы может привести к элементам, находящимся в, казалось бы, случайном порядке. Поскольку они упорядочены, карты на основе деревьев также могут удовлетворять запросам диапазона (находить все значения между двумя границами), тогда как хэш-карта может находить только точные значения. Однако хэш-таблицы имеют гораздо лучшую среднюю временную сложность, чем самобалансирующиеся бинарные деревья поиска O(1), и их худшая производительность крайне маловероятна при использовании хорошей хэш-функции .

Самобалансирующееся бинарное дерево поиска может быть использовано для реализации сегментов для хэш-таблицы, которая использует раздельное связывание. Это позволяет выполнять поиск констант в среднем случае, но гарантирует производительность в худшем случае O(log n ). Однако это вносит дополнительную сложность в реализацию и может привести к еще более низкой производительности для меньших хэш-таблиц, где время, затрачиваемое на вставку и балансировку дерева, больше времени, необходимого для выполнения линейного поиска по всем элементам связанного списка или аналогичной структуры данных. [13] [14]

Другие деревья

Ассоциативные массивы также могут храниться в несбалансированных бинарных деревьях поиска или в структурах данных, специализированных для определенного типа ключей, таких как radix trees , trys , Judy arrays или van Emde Boas trees , хотя относительная производительность этих реализаций различается. Например, было обнаружено, что деревья Judy работают менее эффективно, чем хэш-таблицы, в то время как тщательно отобранные хэш-таблицы, как правило, работают эффективнее, чем адаптивные radix trees, с потенциально большими ограничениями на типы данных, которые они могут обрабатывать. [15] Преимущества этих альтернативных структур заключаются в их способности обрабатывать дополнительные операции с ассоциативными массивами, такие как поиск сопоставления, ключ которого находится ближе всего к запрашиваемому ключу, когда запрос отсутствует в наборе сопоставлений.

Сравнение

Заказанный словарь

Базовое определение словаря не требует порядка. Чтобы гарантировать фиксированный порядок перечисления, часто используются упорядоченные версии ассоциативного массива. Существует два смысла упорядоченного словаря:

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

Языковая поддержка

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

Встроенная синтаксическая поддержка ассоциативных массивов была представлена ​​в 1969 году SNOBOL4 под названием «table». TMG предлагал таблицы со строковыми ключами и целочисленными значениями. MUMPS сделал многомерные ассоциативные массивы, опционально постоянные, своей ключевой структурой данных. SETL поддерживал их как одну из возможных реализаций множеств и карт. Большинство современных языков сценариев, начиная с AWK и включая Rexx , Perl , PHP , Tcl , JavaScript , Maple , Python , Ruby , Wolfram Language , Go и Lua , поддерживают ассоциативные массивы как основной тип контейнера. Во многих других языках они доступны как библиотечные функции без специального синтаксиса.

В Smalltalk , Objective-C , .NET , [20] Python , REALbasic , Swift , VBA и Delphi [21] они называются словарями ; в Perl , Ruby и Seed7 они называются хэшами ; в C++ , C# , Java , Go , Clojure , Scala , OCaml , Haskell они называются картами (см. map (C++) , unordered_map (C++) и Map); в Common Lisp и Windows PowerShell они называются хэш-таблицами (так как оба обычно используют эту реализацию); в Maple и Lua они называются таблицами . В PHP все массивы могут быть ассоциативными, за исключением того, что ключи ограничены целыми числами и строками. В JavaScript (см. также JSON ) все объекты ведут себя как ассоциативные массивы со строковыми ключами, в то время как типы Map и WeakMap принимают произвольные объекты в качестве ключей. В Lua они используются как примитивный строительный блок для всех структур данных. В Visual FoxPro они называются Collections . Язык D также поддерживает ассоциативные массивы. [22]

Постоянное хранение

Многим программам, использующим ассоциативные массивы, необходимо будет хранить эти данные в более постоянной форме, например, в компьютерном файле . Распространенным решением этой проблемы является обобщенная концепция, известная как архивирование или сериализация , которая создает текстовое или двоичное представление исходных объектов, которое может быть записано непосредственно в файл. Это чаще всего реализуется в базовой объектной модели, такой как .Net или Cocoa, которая включает стандартные функции, преобразующие внутренние данные в текст. Программа может создать полное текстовое представление любой группы объектов, вызывая эти методы, которые почти всегда уже реализованы в базовом классе ассоциативного массива. [23]

Для программ, использующих очень большие наборы данных, такой тип индивидуального хранения файлов не подходит, и требуется система управления базами данных (СУБД). Некоторые системы СУБД изначально хранят ассоциативные массивы, сериализуя данные и затем сохраняя эти сериализованные данные и ключ. Затем отдельные массивы можно загрузить или сохранить из базы данных, используя ключ для ссылки на них. Эти хранилища ключей и значений используются уже много лет и имеют такую ​​же долгую историю, как и более распространенные реляционные базы данных (РБД), но отсутствие стандартизации, среди прочих причин, ограничило их использование определенными нишевыми ролями. РБД использовались для этих ролей в большинстве случаев, хотя сохранение объектов в РБД может быть сложным, проблема, известная как несоответствие объектно-реляционного импеданса .

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

Смотрите также

Ссылки

  1. ^ Коллинз, Грэм; Сайм, Дональд (1995). "Теория конечных отображений". Доказательство теорем высшей логики и его применение . Конспект лекций по информатике. Том 971. С. 122–137. doi :10.1007/3-540-60275-5_61. ISBN 978-3-540-60275-0.
  2. ^ Андерссон, Арне (1989). «Оптимальные границы в задаче словаря». Труды Симпозиума по оптимальным алгоритмам . Конспект лекций по информатике. Том 401. Springer Verlag. С. 106–114. doi :10.1007/3-540-51859-2_10. ISBN 978-3-540-51859-4.
  3. ^ abcde Goodrich, Michael T. ; Tamassia, Roberto (2006), "9.1 Абстрактный тип данных Map", Data Structures & Algorithms in Java (4-е изд.), Wiley, стр. 368–371
  4. ^ abcd Мельхорн, Курт ; Сандерс, Питер (2008), «4 хэш-таблицы и ассоциативные массивы», Алгоритмы и структуры данных: базовый набор инструментов (PDF) , Springer, стр. 81–98, архивировано (PDF) из оригинала 2014-08-02
  5. ^ abcd Кормен, Томас Х .; Лейзерсон, Чарльз Э .; Ривест, Рональд Л .; Стайн, Клиффорд (2001), «11 хэш-таблиц», Введение в алгоритмы (2-е изд.), MIT Press и McGraw-Hill , стр. 221–252, ISBN 0-262-03293-7.
  6. ^ ab Dietzfelbinger, M., Karlin, A., Mehlhorn, K., Meyer auf der Heide, F., Rohnert, H., and Tarjan, RE 1994. "Dynamic Perfect Hashing: Upper and Lower Bounds" Архивировано 04.03.2016 в Wayback Machine . SIAM J. Comput. 23, 4 (август 1994), 738-761. http://portal.acm.org/citation.cfm?id=182370 doi :10.1137/S0097539791194094
  7. ^ Гудрич и Тамассиа (2006), стр. 597–599.
  8. ^ ab Black, Paul E.; Stewart, Rob (2 ноября 2020 г.). "словарь". Словарь алгоритмов и структур данных . Получено 26 января 2022 г. .
  9. ^ Гудрич и Тамассиа (2006), стр. 389–397.
  10. ^ «Когда следует использовать хэш-таблицу вместо списка ассоциаций?». lisp-faq/part2. 1996-02-20.
  11. ^ Кламмер, Ф.; Маццолини, Л. (2006), «Искатели ассоциативных карт», Ext. Abstracts GIS-l 2006 , GIS-I, стр. 71–74.
  12. ^ Джоэл Адамс и Ларри Нихофф. «Деревья в STL». Цитата: «Библиотека стандартных шаблонов... некоторые из ее контейнеров — шаблоны set<T>, map<T1, T2>, multiset<T> и multimap<T1, T2> — обычно строятся с использованием особого вида самобалансирующегося бинарного дерева поиска, называемого красно-черным деревом ».
  13. ^ Кнут, Дональд (1998). Искусство программирования . Том 3: Сортировка и поиск (2-е изд.). Addison-Wesley. С. 513–558. ISBN 0-201-89685-0.
  14. ^ Пробст, Марк (2010-04-30). "Линейный против бинарного поиска" . Получено 2016-11-20 .
  15. ^ Альварес, Виктор; Рихтер, Стефан; Чэнь, Сяо; Диттрих, Йенс (апрель 2015 г.). «Сравнение адаптивных радиксных деревьев и хэш-таблиц». 2015 IEEE 31-я Международная конференция по инжинирингу данных . Сеул, Южная Корея: IEEE. стр. 1227–1238. doi :10.1109/ICDE.2015.7113370. ISBN 978-1-4799-7964-6. S2CID  17170456.
  16. ^ "std::map". ru.cppreference.com .
  17. ^ "Класс OrderedDictionary (System.Collections.Specialized)". Документация MS .
  18. ^ "LinkedHashMap".
  19. ^ "коллекции — Типы данных контейнеров — Документация Python 3.9.0a3". docs.python.org .
  20. ^ "Класс словаря<TKey, TValue>". MSDN.
  21. ^ "System.Generics.Collections.TDictionary - Документация API RAD Studio". docwiki.embarcadero.com . Получено 18.04.2017 .
  22. ^ «Ассоциативные массивы, язык программирования D». Digital Mars.
  23. ^ «Руководство по программированию архивов и сериализаций», Apple Inc., 2012

Внешние ссылки