Files
hello-algo/ru/docs/chapter_divide_and_conquer/divide_and_conquer.md
T
2026-01-20 15:08:42 +08:00

15 KiB
Raw Blame History

Разделяй и властвуй

Разделяй и властвуй (divide and conquer) -- это важная и распространенная стратегия в алгоритмах. Обычно она реализуется с помощью рекурсии и включает два этапа: разделение и объединение.

  1. Разделение (этап разбиения): рекурсивное разбиение исходной задачи на две или более подзадачи до тех пор, пока не будет достигнута наименьшая подзадача.
  2. Объединение (этап слияния): начиная с решения наименьших подзадач, снизу вверх объединяются решения всех других подзадач, чтобы построить решение исходной задачи.

Сортировка слиянием является типичным примером применения стратегии «разделяй и властвуй» (см. рис. 12.1).

  1. Разделение: рекурсивное разбиение исходного массива (исходной задачи) на два подмассива (подзадачи) до тех пор, пока в подмассивах не останется по одному элементу (наименьшая подзадача).
  2. Объединение: снизу вверх объединяются упорядоченные подмассивы (решения подзадач), чтобы получить упорядоченный исходный массив (решение исходной задачи).

Стратегия «разделяй и властвуй» в сортировке слиянием

Определение задачи для метода «разделяй и властвуй»

Чтобы определить, подходит ли задача для решения методом «разделяй и властвуй», можно использовать следующие критерии:

  1. Задачу можно разбить: исходную задачу можно разбить на более мелкие, аналогичные подзадачи, которые можно рекурсивно разделить аналогичным образом.
  2. Подзадачи независимы: подзадачи не пересекаются, не зависят друг от друга и могут быть решены независимо.
  3. Решения подзадач можно объединить: решение исходной задачи получается путем объединения решений подзадач.

Очевидно, что сортировка слиянием соответствует этим трем критериям.

  1. Задачу можно разбить: рекурсивное разбиение массива (исходной задачи) на два подмассива (подзадачи).
  2. Подзадачи независимы: каждый подмассив можно отсортировать независимо (подзадачи можно решить независимо).
  3. Решения подзадач можно объединить: два упорядоченных подмассива (решения подзадач) можно объединить в один упорядоченный массив (решение исходной задачи).

Повышение эффективности с помощью стратегии «разделяй и властвуй»

Стратегия «разделяй и властвуй» позволяет не только эффективно решать алгоритмические задачи, но и повышать эффективность алгоритмов. Алгоритмы быстрой сортировки, сортировки слиянием и пирамидальной сортировки быстрее, чем сортировка выбором, пузырьком и вставками, именно благодаря применению стратегии «разделяй и властвуй».

Возникает вопрос: почему метод «разделяй и властвуй» повышает эффективность алгоритма, в чем его основная логика? Иными словами, почему разбиение большой задачи на несколько подзадач, решение этих подзадач и объединение их решений в решение исходной задачи оказывается более эффективным, чем непосредственное решение исходной задачи? Этот вопрос можно обсудить с точки зрения количества операций и параллельных вычислений.

Оптимизация количества операций

Возьмем, к примеру, сортировку пузырьком, которая требует времени O(n^2) для обработки массива длиной n. Предположим, что мы разделили массив на два подмассива, как показано на рис. 12.2. Тогда разбиение потребует времени O(n), сортировка каждого подмассива -- O((n/2)^2), а объединение двух подмассивов -- O(n). Общая временная составит:


O(n + (\frac{n}{2})^2 \times 2 + n) = O(\frac{n^2}{2} + 2n)

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

Далее, решим следующее неравенство, в котором левая и правая части представляют общее количество операций до и после разбиения соответственно:


\begin{aligned}
n^2 & > \frac{n^2}{2} + 2n \\
n^2 - \frac{n^2}{2} - 2n & > 0 \\
n(n - 4) & > 0
\end{aligned}

Это означает, что при n > 4 количество операций после разбиения меньше, и эффективность сортировки должна быть выше. Обратите внимание, что временная сложность после разбиения остается квадратичной O(n^2), но постоянный коэффициент в сложности уменьшается.

Если продолжить разбиение подмассивов пополам, пока в них не останется по одному элементу, то получится сортировка слиянием, временная сложность которой составляет O(n \log n).

А что, если мы установим несколько дополнительных точек разделения и равномерно разделим исходный массив на k подмассивов? Эта ситуация очень похожа на блочную сортировку, которая хорошо подходит для сортировки очень больших объемов данных, и теоретически ее временная сложность может достигать O(n + k).

Оптимизация параллельных вычислений

Известно, что подзадачи, созданные методом «разделяй и властвуй», независимы друг от друга, поэтому их обычно можно решать параллельно. Таким образом, этот метод не только снижает временную сложность алгоритма, но и способствует параллельной оптимизации операционной системы.

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

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

Параллельные вычисления в блочной сортировке

Типичные сценарии применения стратегии «разделяй и властвуй»

С одной стороны, стратегию «разделяй и властвуй» можно использовать для решения многих классических алгоритмических задач.

  • Поиск ближайшей пары точек: этот алгоритм сначала делит множество точек на две части, затем находит ближайшую пару точек в каждой части, а затем находит ближайшую пару точек, охватывающую обе части.
  • Умножение больших чисел: например, алгоритм Карацубы, который разлагает умножение больших чисел на несколько операций умножения и сложения меньших чисел.
  • Умножение матриц: например, алгоритм Штрассена, который разлагает умножение больших матриц на несколько операций умножения и сложения матриц меньшего размера.
  • Задача о Ханойских башнях: эту задачу можно решить с помощью рекурсии, что является типичным применением стратегии «разделяй и властвуй».
  • Задача о количестве инверсий: если в последовательности предыдущее число больше последующего, то эти два числа образуют инверсию. Задачу о количестве инверсий можно решить с помощью подхода «разделяй и властвуй» и сортировки слиянием.

С другой стороны, стратегия «разделяй и властвуй» широко применяется в разработке алгоритмов и структур данных.

  • Двоичный поиск: такой поиск делит отсортированный массив на две части по индексу среднего элемента. Затем, в зависимости от результата сравнения целевого значения со средним элементом, решает, какую половину исключить, и выполняет ту же операцию на оставшейся части.
  • Сортировка слиянием: уже была рассмотрена в начале этого раздела, не будем еще раз повторяться.
  • Быстрая сортировка: эта сортировка выбирает опорное значение, затем делит массив на два подмассива, элементы одного из которых меньше опорного значения, а элементы другого -- больше. Затем выполняет ту же операцию с обеими частями, пока в подмассиве не останется один элемент.
  • Блочная сортировка: основная идея этой сортировки заключается в распределении данных по нескольким блокам и сортировке элементов в каждом из них. Затем происходит последовательное извлечение элементов из каждого блока для построения отсортированного массива.
  • Деревья: например, двоичные деревья поиска, АВЛ-дерево, красно-черное дерево, B-дерево, дерево B+ и т. д. Операции поиска, вставки и удаления в них можно рассматривать как применение стратегии «разделяй и властвуй».
  • Кучи: куча -- это особый вид полного двоичного дерева, и такие операции, как вставка, удаление и упорядочивание, фактически подразумевают использование метода «разделяй и властвуй».
  • Хеш-таблицы: хотя хеш-таблицы напрямую не применяют подход «разделяй и властвуй», некоторые решения для разрешения коллизий в хешировании косвенно используют эту стратегию. Например, длинные цепочки в методе цепной адресации преобразуются в красно-черные деревья для повышения эффективности поиска.

Можно сказать, что стратегия «разделяй и властвуй» -- это своего рода «скрытая» алгоритмическая идея, присутствующая в различных алгоритмах и структурах данных.