Рассмотрите реализацию быстрой сортировки в худшем случае: какие техники (рандомизация, медиана медиан, интроспекция) можно применить, чтобы уменьшить вероятность квадратичной сложности, и какие доказательства или инварианты вы приведёте для обоснования правильности и эффективности
Кратко — три практических подхода и доказательства/инварианты для каждого. 1) Рандомизация (случайный выбор опорного элемента или предварительное случайное перемешивание) - Идея: выбирать опорный элемент uniformly at random (или заранее перемешать массив). Это убирает зависимость от входа и делает «плохие» разбиения маловероятными. - Формулы/оценки: - Для количества сравнений CnC_nCn справедливо стандартное ожидание E[Cn]=2(n+1)Hn−4n=O(nlogn),
\mathbb{E}[C_n]=2(n+1)H_n-4n=O(n\log n), E[Cn]=2(n+1)Hn−4n=O(nlogn),
где HnH_nHn — гармонический ряд. - Рекуррент для ожидаемого времени: E[T(n)]=n−1+1n∑k=0n−1(E[T(k)]+E[T(n−1−k)])=O(nlogn).
\mathbb{E}[T(n)]=n-1+\frac{1}{n}\sum_{k=0}^{n-1}\big(\mathbb{E}[T(k)]+\mathbb{E}[T(n-1-k)]\big)=O(n\log n). E[T(n)]=n−1+n1k=0∑n−1(E[T(k)]+E[T(n−1−k)])=O(nlogn).
- Высокая вероятность (tail bound): пометив разбиения «хорошими», если разбиение уменьшает размер не менее чем в константный фактор (например, до ≤3/4\le 3/4≤3/4 от размера), вероятность «хорошего» разбиения ≥1/2\ge 1/2≥1/2. По концентрации (Chernoff) число хороших разбиений на пути глубиной clognc\log nclogn концентрируется вокруг своего ожидания, следовательно глубина рекурсии O(logn)O(\log n)O(logn) с вероятностью 1−n−Ω(1)1-n^{-\Omega(1)}1−n−Ω(1). Итого: вероятность квадратичной сложности экспоненциально мала в логарифме размера входа. - Инвариант корректности: шаг partition помещает опорный элемент в его окончательную позицию и сохраняет классификацию элементов pivot; по индукции алгоритм корректен. 2) Медиана медиан (детерминированный выбор хорошего опорного — BFPRT) - Идея: использовать алгоритм выбора порядка статистики за O(n)O(n)O(n) (группировать по 5, взять медианы, рекурсивно вычислить медиану медиан) и использовать её как опорный элемент. Это даёт детерминированную гарантию «неплохого» разбиения. - Ключевое свойство (группа по 5): для массива размера nnn медиана медиан гарантирует, что по меньшей мере 3⌊n/10⌋3\lfloor n/10\rfloor3⌊n/10⌋ элементов ≤\le≤ ей и по меньшей мере 3⌊n/10⌋3\lfloor n/10\rfloor3⌊n/10⌋≥\ge≥ ей. Следовательно размер каждой части после partition не превосходит 7n/107n/107n/10. - Рекуррент для времени (quicksort с таким выбором опорного): T(n)≤2T(7n/10)+O(n).
T(n)\le 2T(7n/10)+O(n). T(n)≤2T(7n/10)+O(n).
По стандартному решению рекуррентов получаем T(n)=O(nlogn)T(n)=O(n\log n)T(n)=O(nlogn) — жёсткая детерминированная гарантия. - Инвариант корректности: тот же partition-инвариант; дополнительная гарантия по балансу разбиения даёт асимптотическую верхнюю границу на глубину рекурсии. - Замечание: константы и накладные расходы у BFPRT больше, поэтому в практике часто используют смешанные схемы (медиана из 3, перемешивание) вместо чистого медиана-медиан. 3) Интроспекция (Introsort) - Идея: исполнять быстрый (рандомизированный или детерминированный) quicksort, но отслеживать максимальную глубину рекурсии; если глубина превышает порог (обычно clognc\log nclogn, часто 2⌊log2n⌋2\lfloor\log_2 n\rfloor2⌊log2n⌋), перейти на алгоритм с гарантированным худшим случаем O(nlogn)O(n\log n)O(nlogn) (обычно heapsort). - Гарантии: - Быстродействие на «хороших» данных равно быстрому варианту (обычно O(nlogn)O(n\log n)O(nlogn) с хорошими константами). - В худшем случае (если много плохих разбиений) переключение гарантирует окончательное время O(nlogn)O(n\log n)O(nlogn) (по свойствам heapsort). - Инвариант корректности: swap/partition-инвариант сохраняется, а переключение не нарушает покрытие всех элементов и корректность результата. - Практическое применение: Introsort (используемый в std::sort) даёт и лучшие практические константы quicksort, и детерминированную гарантию худшего случая через heapsort. Короткие рекомендации и комбинации: - Для практики: перемешивание + медиана из трёх + порог на малые подмассивы (insertion sort) + introsort для безопасности. - Для теоретически жёсткой гарантии по худшему случаю: использовать медиана-медиан (BFPRT) для выбора опорного или introsort (переключение на heapsort). Вывод (формулировка преимуществ): - Рандомизация: устраняет плохие входы, даёт E[T]=O(nlogn)E[T]=O(n\log n)E[T]=O(nlogn) и «высокую вероятность» O(nlogn)O(n\log n)O(nlogn). - Медиана медиан: даёт детерминированную гарантию O(nlogn)O(n\log n)O(nlogn) в худшем случае (за счёт больших констант). - Интроспекция: сочетает практическую эффективность quicksort и жёсткую гарантированную верхнюю оценку через переключение на heapsort.
1) Рандомизация (случайный выбор опорного элемента или предварительное случайное перемешивание)
- Идея: выбирать опорный элемент uniformly at random (или заранее перемешать массив). Это убирает зависимость от входа и делает «плохие» разбиения маловероятными.
- Формулы/оценки:
- Для количества сравнений CnC_nCn справедливо стандартное ожидание
E[Cn]=2(n+1)Hn−4n=O(nlogn), \mathbb{E}[C_n]=2(n+1)H_n-4n=O(n\log n),
E[Cn ]=2(n+1)Hn −4n=O(nlogn), где HnH_nHn — гармонический ряд.
- Рекуррент для ожидаемого времени:
E[T(n)]=n−1+1n∑k=0n−1(E[T(k)]+E[T(n−1−k)])=O(nlogn). \mathbb{E}[T(n)]=n-1+\frac{1}{n}\sum_{k=0}^{n-1}\big(\mathbb{E}[T(k)]+\mathbb{E}[T(n-1-k)]\big)=O(n\log n).
E[T(n)]=n−1+n1 k=0∑n−1 (E[T(k)]+E[T(n−1−k)])=O(nlogn). - Высокая вероятность (tail bound): пометив разбиения «хорошими», если разбиение уменьшает размер не менее чем в константный фактор (например, до ≤3/4\le 3/4≤3/4 от размера), вероятность «хорошего» разбиения ≥1/2\ge 1/2≥1/2. По концентрации (Chernoff) число хороших разбиений на пути глубиной clognc\log nclogn концентрируется вокруг своего ожидания, следовательно глубина рекурсии O(logn)O(\log n)O(logn) с вероятностью 1−n−Ω(1)1-n^{-\Omega(1)}1−n−Ω(1). Итого: вероятность квадратичной сложности экспоненциально мала в логарифме размера входа.
- Инвариант корректности: шаг partition помещает опорный элемент в его окончательную позицию и сохраняет классификацию элементов pivot; по индукции алгоритм корректен.
2) Медиана медиан (детерминированный выбор хорошего опорного — BFPRT)
- Идея: использовать алгоритм выбора порядка статистики за O(n)O(n)O(n) (группировать по 5, взять медианы, рекурсивно вычислить медиану медиан) и использовать её как опорный элемент. Это даёт детерминированную гарантию «неплохого» разбиения.
- Ключевое свойство (группа по 5): для массива размера nnn медиана медиан гарантирует, что по меньшей мере 3⌊n/10⌋3\lfloor n/10\rfloor3⌊n/10⌋ элементов ≤\le≤ ей и по меньшей мере 3⌊n/10⌋3\lfloor n/10\rfloor3⌊n/10⌋ ≥\ge≥ ей. Следовательно размер каждой части после partition не превосходит 7n/107n/107n/10.
- Рекуррент для времени (quicksort с таким выбором опорного):
T(n)≤2T(7n/10)+O(n). T(n)\le 2T(7n/10)+O(n).
T(n)≤2T(7n/10)+O(n). По стандартному решению рекуррентов получаем T(n)=O(nlogn)T(n)=O(n\log n)T(n)=O(nlogn) — жёсткая детерминированная гарантия.
- Инвариант корректности: тот же partition-инвариант; дополнительная гарантия по балансу разбиения даёт асимптотическую верхнюю границу на глубину рекурсии.
- Замечание: константы и накладные расходы у BFPRT больше, поэтому в практике часто используют смешанные схемы (медиана из 3, перемешивание) вместо чистого медиана-медиан.
3) Интроспекция (Introsort)
- Идея: исполнять быстрый (рандомизированный или детерминированный) quicksort, но отслеживать максимальную глубину рекурсии; если глубина превышает порог (обычно clognc\log nclogn, часто 2⌊log2n⌋2\lfloor\log_2 n\rfloor2⌊log2 n⌋), перейти на алгоритм с гарантированным худшим случаем O(nlogn)O(n\log n)O(nlogn) (обычно heapsort).
- Гарантии:
- Быстродействие на «хороших» данных равно быстрому варианту (обычно O(nlogn)O(n\log n)O(nlogn) с хорошими константами).
- В худшем случае (если много плохих разбиений) переключение гарантирует окончательное время O(nlogn)O(n\log n)O(nlogn) (по свойствам heapsort).
- Инвариант корректности: swap/partition-инвариант сохраняется, а переключение не нарушает покрытие всех элементов и корректность результата.
- Практическое применение: Introsort (используемый в std::sort) даёт и лучшие практические константы quicksort, и детерминированную гарантию худшего случая через heapsort.
Короткие рекомендации и комбинации:
- Для практики: перемешивание + медиана из трёх + порог на малые подмассивы (insertion sort) + introsort для безопасности.
- Для теоретически жёсткой гарантии по худшему случаю: использовать медиана-медиан (BFPRT) для выбора опорного или introsort (переключение на heapsort).
Вывод (формулировка преимуществ):
- Рандомизация: устраняет плохие входы, даёт E[T]=O(nlogn)E[T]=O(n\log n)E[T]=O(nlogn) и «высокую вероятность» O(nlogn)O(n\log n)O(nlogn).
- Медиана медиан: даёт детерминированную гарантию O(nlogn)O(n\log n)O(nlogn) в худшем случае (за счёт больших констант).
- Интроспекция: сочетает практическую эффективность quicksort и жёсткую гарантированную верхнюю оценку через переключение на heapsort.