12 KiB
Переосмысление алгоритмов поиска
Алгоритм поиска (searching algorithm) используется для поиска одного или группы элементов, удовлетворяющих определенным условиям, в структуре данных (например, массиве, связном списке, дереве или графе).
Алгоритмы поиска можно разделить на следующие две категории в зависимости от подхода к реализации:
- Определение целевых элементов путем обхода структуры данных, например, обход массивов, связных списков, деревьев и графов.
- Использование организационной структуры данных или априорной информации, содержащейся в данных, для эффективного поиска элементов, например, двоичный поиск, хеш-поиск и поиск в двоичном дереве поиска.
Нетрудно заметить, что все эти темы уже были рассмотрены в предыдущих главах, поэтому алгоритмы поиска для нас не новы. В этом разделе мы рассмотрим алгоритмы поиска с более систематической точки зрения.
Поиск методом перебора
Поиск методом перебора определяет целевые элементы путем обхода каждого элемента структуры данных.
- "Линейный поиск" применим к линейным структурам данных, таким как массивы и связные списки. Он начинается с одного конца структуры данных, последовательно обращается к элементам, пока не будет найден целевой элемент или не будет достигнут другой конец без нахождения целевого элемента.
- "Поиск в ширину" и "поиск в глубину" -- это две стратегии обхода графов и деревьев. Поиск в ширину начинается с начального узла и выполняет послойный поиск, обращаясь к узлам от ближних к дальним. Поиск в глубину начинается с начального узла, идет по пути до конца, затем возвращается назад и пробует другие пути, пока не будет пройдена вся структура данных.
Преимущество поиска методом перебора заключается в простоте и хорошей универсальности, не требуется предварительная обработка данных и использование дополнительных структур данных.
Однако временная сложность таких алгоритмов составляет $O(n)$, где n -- количество элементов, поэтому производительность низкая при больших объемах данных.
Адаптивный поиск
Адаптивный поиск использует специфические свойства данных (например, упорядоченность) для оптимизации процесса поиска, что позволяет более эффективно определять целевые элементы.
- "Двоичный поиск" использует упорядоченность данных для эффективного поиска и применим только к массивам.
- "Хеш-поиск" использует хеш-таблицу для установления соответствия между поисковыми данными и целевыми данными в виде пар ключ-значение, что позволяет реализовать операции запроса.
- "Поиск в дереве" в специфических древовидных структурах (например, двоичном дереве поиска) основан на сравнении значений узлов для быстрого исключения узлов и определения целевого элемента.
Преимущество таких алгоритмов заключается в высокой эффективности, временная сложность может достигать O(\log n) или даже $O(1)$.
Однако использование этих алгоритмов часто требует предварительной обработки данных. Например, двоичный поиск требует предварительной сортировки массива, хеш-поиск и поиск в дереве требуют дополнительных структур данных, а поддержание этих структур данных также требует дополнительных временных и пространственных затрат.
!!! tip
Адаптивные алгоритмы поиска часто называют алгоритмами поиска, **они в основном используются для быстрого извлечения целевых элементов в определенных структурах данных**.
Выбор метода поиска
Для заданного набора данных размером n мы можем использовать линейный поиск, двоичный поиск, поиск в дереве, хеш-поиск и другие методы для поиска целевого элемента. Принцип работы каждого метода показан на рисунке ниже.
Эффективность операций и характеристики вышеуказанных методов приведены в следующей таблице.
Таблица Сравнение эффективности алгоритмов поиска
| Линейный поиск | Двоичный поиск | Поиск в дереве | Хеш-поиск | |
|---|---|---|---|---|
| Поиск элемента | O(n) |
O(\log n) |
O(\log n) |
O(1) |
| Вставка элемента | O(1) |
O(n) |
O(\log n) |
O(1) |
| Удаление элемента | O(n) |
O(n) |
O(\log n) |
O(1) |
| Дополнительное пространство | O(1) |
O(1) |
O(n) |
O(n) |
| Предварительная обработка данных | / | Сортировка O(n \log n) |
Построение дерева O(n \log n) |
Построение хеш-таблицы O(n) |
| Упорядоченность данных | Неупорядоченные | Упорядоченные | Упорядоченные | Неупорядоченные |
Выбор алгоритма поиска также зависит от масштаба, требований к производительности поиска, частоты запросов и обновлений данных.
Линейный поиск
- Хорошая универсальность, не требуется никаких операций предварительной обработки данных. Если нам нужно выполнить запрос данных только один раз, то время предварительной обработки данных для других трех методов будет больше, чем время линейного поиска.
- Подходит для небольших объемов данных, в этом случае временная сложность оказывает меньшее влияние на эффективность.
- Подходит для сценариев с высокой частотой обновления данных, поскольку этот метод не требует дополнительного обслуживания данных.
Двоичный поиск
- Подходит для больших объемов данных, демонстрирует стабильную эффективность, наихудшая временная сложность составляет
O(\log n). - Объем данных не может быть слишком большим, поскольку для хранения массива требуется непрерывное пространство памяти.
- Не подходит для сценариев с частым добавлением и удалением данных, поскольку затраты на поддержание упорядоченного массива довольно высоки.
Хеш-поиск
- Подходит для сценариев с очень высокими требованиями к производительности запросов, средняя временная сложность составляет
O(1). - Не подходит для сценариев, требующих упорядоченных данных или поиска по диапазону, поскольку хеш-таблица не может поддерживать упорядоченность данных.
- Высокая зависимость от хеш-функции и стратегии обработки хеш-коллизий, существует значительный риск снижения производительности.
- Не подходит для слишком больших объемов данных, поскольку хеш-таблица требует дополнительного пространства для максимального уменьшения коллизий и обеспечения хорошей производительности запросов.
Поиск в дереве
- Подходит для огромных объемов данных, поскольку узлы дерева хранятся в памяти разрозненно.
- Подходит для сценариев, требующих поддержания упорядоченных данных или поиска по диапазону.
- В процессе непрерывного добавления и удаления узлов двоичное дерево поиска может стать несбалансированным, временная сложность ухудшается до
O(n). - При использовании AVL-дерева или красно-черного дерева все операции могут стабильно выполняться с эффективностью
O(\log n), но операции по поддержанию баланса дерева добавляют дополнительные затраты.
