<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="ru">
		<id>http://neerc.ifmo.ru/wiki/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=%D0%98%D0%BB%D1%8C%D0%BD%D0%B0%D1%80</id>
		<title>Викиконспекты - Вклад участника [ru]</title>
		<link rel="self" type="application/atom+xml" href="http://neerc.ifmo.ru/wiki/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=%D0%98%D0%BB%D1%8C%D0%BD%D0%B0%D1%80"/>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%A1%D0%BB%D1%83%D0%B6%D0%B5%D0%B1%D0%BD%D0%B0%D1%8F:%D0%92%D0%BA%D0%BB%D0%B0%D0%B4/%D0%98%D0%BB%D1%8C%D0%BD%D0%B0%D1%80"/>
		<updated>2026-08-06T09:26:05Z</updated>
		<subtitle>Вклад участника</subtitle>
		<generator>MediaWiki 1.30.0</generator>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%94%D0%B8%D1%81%D0%BA%D1%80%D0%B5%D1%82%D0%BD%D0%B0%D1%8F_%D0%BC%D0%B0%D1%82%D0%B5%D0%BC%D0%B0%D1%82%D0%B8%D0%BA%D0%B0,_%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC%D1%8B_%D0%B8_%D1%81%D1%82%D1%80%D1%83%D0%BA%D1%82%D1%83%D1%80%D1%8B_%D0%B4%D0%B0%D0%BD%D0%BD%D1%8B%D1%85&amp;diff=52700</id>
		<title>Дискретная математика, алгоритмы и структуры данных</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%94%D0%B8%D1%81%D0%BA%D1%80%D0%B5%D1%82%D0%BD%D0%B0%D1%8F_%D0%BC%D0%B0%D1%82%D0%B5%D0%BC%D0%B0%D1%82%D0%B8%D0%BA%D0%B0,_%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC%D1%8B_%D0%B8_%D1%81%D1%82%D1%80%D1%83%D0%BA%D1%82%D1%83%D1%80%D1%8B_%D0%B4%D0%B0%D0%BD%D0%BD%D1%8B%D1%85&amp;diff=52700"/>
				<updated>2016-03-18T15:44:35Z</updated>
		
		<summary type="html">&lt;p&gt;Ильнар: /* Другие задачи */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Категория:Дискретная математика и алгоритмы]]&lt;br /&gt;
[[Категория: Алгоритмы и структуры данных]]&lt;br /&gt;
Убедительная просьба читать [[Обсуждение:Дискретная_математика_и_алгоритмы | правила оформления вики-конспектов]].&lt;br /&gt;
&lt;br /&gt;
Символом &amp;lt;tex&amp;gt; \star &amp;lt;/tex&amp;gt; помечены дополнительные темы (возможно, сложные), которые не были подробно рассмотрены (или вообще рассмотрены) в рамках курса.&lt;br /&gt;
&lt;br /&gt;
= Первый семестр =&lt;br /&gt;
&lt;br /&gt;
== Отношения ==&lt;br /&gt;
*[[Определение отношения]]&lt;br /&gt;
*[[Композиция отношений|Композиция отношений, степень отношения, обратное отношение]]&lt;br /&gt;
*[[Рефлексивное отношение|Рефлексивное отношение. Антирефлексивное отношение.]]&lt;br /&gt;
*[[Симметричное отношение]]&lt;br /&gt;
*[[Антисимметричное отношение]]&lt;br /&gt;
*[[Транзитивное отношение]]&lt;br /&gt;
*[[Отношение порядка]]&lt;br /&gt;
*[[Отношение эквивалентности]]&lt;br /&gt;
*[[Транзитивное замыкание|Транзитивное замыкание отношения]]&lt;br /&gt;
*[[Алгоритм Флойда — Уоршелла|Алгоритм Флойда-Уоршалла построения транзитивного замыкания отношения]]&lt;br /&gt;
*[[Транзитивный остов]]&lt;br /&gt;
&lt;br /&gt;
== Булевы функции ==&lt;br /&gt;
*[[Определение булевой функции]]&lt;br /&gt;
*[[Побитовые операции]]&amp;lt;tex&amp;gt;^\star&amp;lt;/tex&amp;gt;&lt;br /&gt;
*[[Суперпозиции]]&lt;br /&gt;
*[[ДНФ]]&lt;br /&gt;
*[[Сокращенная и минимальная ДНФ | Сокращенная и минимальная ДНФ, минимизация ДНФ методами гиперкубов, карт Карно, Квайна]]&lt;br /&gt;
*[[КНФ]]&lt;br /&gt;
*[[2-SAT]]&lt;br /&gt;
*[[Специальные формы КНФ|Специальные формы КНФ: КНФ в форме Хорна и КНФ в форме Крома]]&lt;br /&gt;
*[[Полином Жегалкина | Полином Жегалкина, преобразование Мёбиуса]]&lt;br /&gt;
*[[Полные системы функций. Теорема Поста о полной системе функций]]&lt;br /&gt;
*[[Представление функции класса DM с помощью медианы]]&lt;br /&gt;
*[[Пороговая функция]]&lt;br /&gt;
*[[Троичная логика]]&amp;lt;tex&amp;gt;^\star&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Схемы из функциональных элементов ==&lt;br /&gt;
*[[Реализация булевой функции схемой из функциональных элементов]]&lt;br /&gt;
*[[Простейшие методы синтеза схем из функциональных элементов]]&lt;br /&gt;
*[[Метод Лупанова синтеза схем]]&lt;br /&gt;
*[[Cумматор]]&lt;br /&gt;
*[[Каскадный сумматор]]&lt;br /&gt;
*[[Двоичный каскадный сумматор]]&lt;br /&gt;
*[[Троичный сумматор]]&amp;lt;tex&amp;gt;^\star&amp;lt;/tex&amp;gt;&lt;br /&gt;
*[[Реализация вычитания сумматором]]&lt;br /&gt;
*[[Матричный умножитель]]&lt;br /&gt;
*[[Дерево Уоллеса]]&lt;br /&gt;
*[[Контактная схема]]&lt;br /&gt;
*[[Триггеры]]&amp;lt;tex&amp;gt;^\star&amp;lt;/tex&amp;gt;&lt;br /&gt;
*[[Квантовые гейты]]&amp;lt;tex&amp;gt;^\star&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Представление информации ==&lt;br /&gt;
*[[Кодирование информации]]&lt;br /&gt;
*[[Представление целых чисел: прямой код, код со сдвигом, дополнительный код]]&lt;br /&gt;
*[[Представление вещественных чисел]]&lt;br /&gt;
*[[Представление символов, таблицы кодировок]]&amp;lt;tex&amp;gt;^\star&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Алгоритмы сжатия ==&lt;br /&gt;
* [[Алгоритм Хаффмана]]&lt;br /&gt;
* [[Оптимальное хранение словаря в алгоритме Хаффмана]]&lt;br /&gt;
* [[Алгоритм Хаффмана за O(n)]]&lt;br /&gt;
* [[Алгоритм Ху-Таккера]]&amp;lt;tex&amp;gt;^\star&amp;lt;/tex&amp;gt;&lt;br /&gt;
* [[Неравенство Крафта]]&lt;br /&gt;
* [[Неравенство Макмиллана]]&lt;br /&gt;
* [[Код Шеннона]]&lt;br /&gt;
* [[Оптимальный префиксный код с длиной кодового слова не более L бит]]&amp;lt;tex&amp;gt;^\star&amp;lt;/tex&amp;gt;&lt;br /&gt;
* [[Алгоритмы LZ77 и LZ78]]&lt;br /&gt;
* [[Алгоритм LZW]]&lt;br /&gt;
* [[Алгоритм LZSS]]&amp;lt;tex&amp;gt;^\star&amp;lt;/tex&amp;gt;&lt;br /&gt;
* [[Преобразование Барроуза-Уиллера | Преобразование Барроуза-Уиллера и обратное ему]]&lt;br /&gt;
* [[Преобразование MTF]]&lt;br /&gt;
* [[Расстояние Хэмминга]]&lt;br /&gt;
* [[Избыточное кодирование, код Хэмминга]]&lt;br /&gt;
* [[Гамма-, дельта- и омега-код Элиаса]]&amp;lt;tex&amp;gt;^\star&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Комбинаторика ==&lt;br /&gt;
=== Комбинаторные объекты ===&lt;br /&gt;
* [[Комбинаторные объекты]]&lt;br /&gt;
* [[Лексикографический порядок]]&lt;br /&gt;
* [[Коды Грея]]&lt;br /&gt;
* [[Коды Грея для перестановок]]&lt;br /&gt;
* [[Коды антигрея]]&lt;br /&gt;
* [[Цепные коды]]&lt;br /&gt;
* [[Правильные скобочные последовательности]]&lt;br /&gt;
&lt;br /&gt;
=== Генерация комбинаторных объектов ===&lt;br /&gt;
* [[Генерация комбинаторных объектов в лексикографическом порядке]]&lt;br /&gt;
* [[Получение номера по объекту]]&lt;br /&gt;
* [[Получение объекта по номеру]]&lt;br /&gt;
* [[Получение следующего объекта]]&lt;br /&gt;
* [[Получение предыдущего объекта]]&amp;lt;tex&amp;gt;^\star&amp;lt;/tex&amp;gt;  &lt;br /&gt;
* [[Метод генерации случайной перестановки, алгоритм Фишера-Йетса]]&lt;br /&gt;
* [[Методы генерации случайного сочетания]]&amp;lt;tex&amp;gt;^\star&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Подсчёт числа объектов ===&lt;br /&gt;
* [[Формула включения-исключения | Формула включения-исключения, подсчет числа беспорядков]]&lt;br /&gt;
* [[Нахождение количества разбиений числа на слагаемые | Нахождение количества разбиений числа на слагаемые. Пентагональная теорема Эйлера]]&lt;br /&gt;
* [[Производящая функция]]&lt;br /&gt;
* [[Лемма Бёрнсайда и Теорема Пойа]]&lt;br /&gt;
* [[Задача об ожерельях]]&lt;br /&gt;
* [[Числа Стирлинга первого рода]]&lt;br /&gt;
* [[Числа Стирлинга второго рода]]&lt;br /&gt;
* [[Числа Эйлера I и II рода | Числа Эйлера первого и второго рода. Подъемы в перестановках]]&amp;lt;tex&amp;gt;^\star&amp;lt;/tex&amp;gt;&lt;br /&gt;
* [[Числа Каталана]]&lt;br /&gt;
&lt;br /&gt;
=== Свойства комбинаторных объектов ===&lt;br /&gt;
* [[Умножение перестановок, обратная перестановка, группа перестановок]]&lt;br /&gt;
* [[Действие перестановки на набор из элементов, представление в виде циклов]]&lt;br /&gt;
* [[Таблица инверсий]]&lt;br /&gt;
* [[Теорема Кэли]]&lt;br /&gt;
* [[Матричное представление перестановок]]&lt;br /&gt;
* [[Задача о минимуме/максимуме скалярного произведения]]&lt;br /&gt;
* [[Задача о монотонных подпоследовательностях, теорема о связи длины НВП и НУП]]&lt;br /&gt;
&lt;br /&gt;
== [[Динамическое программирование]] ==&lt;br /&gt;
=== Классические задачи динамического программирования ===&lt;br /&gt;
*[[Кратчайший путь в ациклическом графе]]&lt;br /&gt;
*[[Задача о числе путей в ациклическом графе]]&lt;br /&gt;
*[[Задача о расстановке знаков в выражении]]&lt;br /&gt;
*[[Задача о порядке перемножения матриц]]&lt;br /&gt;
*[[Задача о наибольшей общей подпоследовательности]]&lt;br /&gt;
*[[Задача о наибольшей возрастающей подпоследовательности]]&lt;br /&gt;
*[[Задача коммивояжера, ДП по подмножествам]]&lt;br /&gt;
*[[Задача о редакционном расстоянии, алгоритм Вагнера-Фишера]]&lt;br /&gt;
*[[Задача о рюкзаке]]&lt;br /&gt;
&lt;br /&gt;
=== Способы оптимизации методов динамического программирования ===&lt;br /&gt;
*[[Метод четырех русских для умножения матриц]]&lt;br /&gt;
*[[Применение метода четырех русских в задачах ДП на примере задачи о НОП]]&amp;lt;tex&amp;gt;^\star&amp;lt;/tex&amp;gt;&lt;br /&gt;
*[[Задача об оптимальном префиксном коде с сохранением порядка. Монотонность точки разреза]]&lt;br /&gt;
*[[Meet-in-the-middle]]&amp;lt;tex&amp;gt;^\star&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Другие задачи ===&lt;br /&gt;
*[[Задача о расстоянии Дамерау-Левенштейна]]&amp;lt;tex&amp;gt;^\star&amp;lt;/tex&amp;gt;&lt;br /&gt;
*[[Задача о выводе в контекстно-свободной грамматике, алгоритм Кока-Янгера-Касами]]&lt;br /&gt;
*[[Задача о наибольшей подпоследовательности-палиндроме]]&lt;br /&gt;
*[[Наибольшая общая возрастающая подпоследовательность]]&amp;lt;tex&amp;gt;^\star&amp;lt;/tex&amp;gt;&lt;br /&gt;
*[[Задача о наибольшей общей палиндромной подпоследовательности]]&amp;lt;tex&amp;gt;^\star&amp;lt;/tex&amp;gt;&lt;br /&gt;
*[[Динамическое программирование по профилю]]&amp;lt;tex&amp;gt;^\star&amp;lt;/tex&amp;gt;&lt;br /&gt;
*[[Динамика по поддеревьям]]&lt;br /&gt;
*[[Количество подпалиндромов в строке]]&amp;lt;tex&amp;gt;^\star&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Теория вероятностей ==&lt;br /&gt;
*[[Вероятностное пространство, элементарный исход, событие]]&lt;br /&gt;
*[[Независимые события]]&lt;br /&gt;
*[[Условная вероятность]]&lt;br /&gt;
*[[Формула полной вероятности]]&lt;br /&gt;
*[[Формула Байеса]]&lt;br /&gt;
*[[Дискретная случайная величина]]&lt;br /&gt;
*[[Независимые случайные величины]]&lt;br /&gt;
*[[Математическое ожидание случайной величины]]&lt;br /&gt;
*[[Дисперсия случайной величины]]&lt;br /&gt;
*[[Ковариация случайных величин]]&lt;br /&gt;
*[[Корреляция случайных величин]]&lt;br /&gt;
*[[Неравенство Маркова]]&lt;br /&gt;
*[[Энтропия случайного источника]]&lt;br /&gt;
*[[Симуляция одним распределением другого]]&lt;br /&gt;
*[[Арифметическое кодирование]]&lt;br /&gt;
*[[Парадоксы теории вероятностей]]&amp;lt;tex&amp;gt;^\star&amp;lt;/tex&amp;gt;&lt;br /&gt;
*[[Схема Бернулли]]&amp;lt;tex&amp;gt;^\star&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Марковские цепи ==&lt;br /&gt;
&lt;br /&gt;
* [[Марковская цепь]]&lt;br /&gt;
* [[Теорема о поглощении]]&lt;br /&gt;
* [[Фундаментальная матрица]]&lt;br /&gt;
* [[Математическое ожидание времени поглощения]]&lt;br /&gt;
* [[Расчет вероятности поглощения в состоянии]]&lt;br /&gt;
* [[Эргодическая марковская цепь]]&lt;br /&gt;
* [[Регулярная марковская цепь]]&lt;br /&gt;
* [[Примеры использования Марковских цепей]]&lt;br /&gt;
* [[Скрытые Марковские модели]]&amp;lt;tex&amp;gt;^\star&amp;lt;/tex&amp;gt;&lt;br /&gt;
* [[Алгоритм Витерби]]&amp;lt;tex&amp;gt;^\star&amp;lt;/tex&amp;gt;&lt;br /&gt;
* [[Алгоритм &amp;quot;Вперед-Назад&amp;quot;]]&amp;lt;tex&amp;gt;^\star&amp;lt;/tex&amp;gt;&lt;br /&gt;
* [[Алгоритм Баума-Велша]]&amp;lt;tex&amp;gt;^\star&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Второй семестр =&lt;br /&gt;
&lt;br /&gt;
== Амортизационный анализ ==&lt;br /&gt;
* [[Амортизационный анализ]]&lt;br /&gt;
* [[Динамический массив]]&lt;br /&gt;
* [[Hashed Array Tree]]&amp;lt;tex&amp;gt;^\star&amp;lt;/tex&amp;gt;&lt;br /&gt;
* [[Список]]&lt;br /&gt;
* [[Стек]]&lt;br /&gt;
* [[Очередь]]&lt;br /&gt;
* [[Дек]]&lt;br /&gt;
* [[Мажорирующий элемент]]&lt;br /&gt;
* [[Счетчик Кнута]]&lt;br /&gt;
* [[Мастер-теорема]]&amp;lt;tex&amp;gt;^\star&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Персистентные структуры данных ==&lt;br /&gt;
* [[Персистентные структуры данных]]&lt;br /&gt;
* [[List order maintenance]]&amp;lt;tex&amp;gt;^\star&amp;lt;/tex&amp;gt;&lt;br /&gt;
* [[Персистентный стек]]&lt;br /&gt;
* [[Персистентная очередь]]&lt;br /&gt;
* [[Персистентный дек]]&lt;br /&gt;
* [[Персистентная приоритетная очередь]]&lt;br /&gt;
&lt;br /&gt;
== [[Приоритетные очереди]] ==&lt;br /&gt;
* [[Двоичная куча]]&lt;br /&gt;
* [[Биномиальная куча]]&lt;br /&gt;
* [[Фибоначчиева куча]]&lt;br /&gt;
* [[Левосторонняя куча]]&lt;br /&gt;
* [[Тонкая куча]]&lt;br /&gt;
* [[Толстая куча на избыточном счетчике]]&lt;br /&gt;
* [[Куча Бродала-Окасаки]]&amp;lt;tex&amp;gt;^\star&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Система непересекающихся множеств ==&lt;br /&gt;
* [[СНМ (наивные реализации) | Наивные реализации]]&lt;br /&gt;
* [[СНМ (списки с весовой эвристикой) | Списки с весовой эвристикой]]&lt;br /&gt;
* [[СНМ(реализация с помощью леса корневых деревьев) | Реализация с помощью леса корневых деревьев]]&lt;br /&gt;
* [[СНМ с операцией удаления за О(1)]]&amp;lt;tex&amp;gt;^\star&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== [[Поисковые структуры данных]] ==&lt;br /&gt;
* [[Упорядоченное множество]]&lt;br /&gt;
* [[Дерево поиска, наивная реализация]]&lt;br /&gt;
* [[АВЛ-дерево]]&lt;br /&gt;
* [[2-3 дерево]]&lt;br /&gt;
* [[B-дерево]]&lt;br /&gt;
* [[Красно-черное дерево]]&lt;br /&gt;
* [[Декартово дерево]]&lt;br /&gt;
* [[Декартово дерево по неявному ключу]]&lt;br /&gt;
* [[Splay-дерево]]&lt;br /&gt;
* [[Tango-дерево]]&amp;lt;tex&amp;gt;^\star&amp;lt;/tex&amp;gt;&lt;br /&gt;
* [[Рандомизированное бинарное дерево поиска]]&lt;br /&gt;
* [[Дерево ван Эмде Боаса]]&lt;br /&gt;
* [[Список с пропусками]]&lt;br /&gt;
* [[Fusion tree]]&amp;lt;tex&amp;gt;^\star&amp;lt;/tex&amp;gt;&lt;br /&gt;
* [[Сверхбыстрый цифровой бор]]&lt;br /&gt;
* [[Rope]]&amp;lt;tex&amp;gt;^\star&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Дерево отрезков ==&lt;br /&gt;
&lt;br /&gt;
* [[Статистики на отрезках. Корневая эвристика]]&lt;br /&gt;
* [[Дерево отрезков. Построение]]&lt;br /&gt;
* [[Реализация запроса в дереве отрезков сверху]]&lt;br /&gt;
* [[Реализация запроса в дереве отрезков снизу]]&lt;br /&gt;
* [[Несогласованные поддеревья. Реализация массового обновления]]&lt;br /&gt;
* [[Многомерное дерево отрезков]]&lt;br /&gt;
* [[Сжатое многомерное дерево отрезков]]&lt;br /&gt;
&lt;br /&gt;
== Дерево Фенвика ==&lt;br /&gt;
* [[Дерево Фенвика]]&lt;br /&gt;
* [[Встречное дерево Фенвика]]&lt;br /&gt;
* [[Дерево Фенвика для некоммутативных операций]]&lt;br /&gt;
* [[Многомерное дерево Фенвика]]&lt;br /&gt;
&lt;br /&gt;
== Хеширование ==&lt;br /&gt;
* [[Хеш-таблица]]&lt;br /&gt;
* [[Разрешение коллизий]]&lt;br /&gt;
* [[Хеширование кукушки]]&lt;br /&gt;
* [[Идеальное хеширование]]&lt;br /&gt;
* [[Перехеширование]]&lt;br /&gt;
* [[Фильтр Блума]]&lt;br /&gt;
* [[Quotient filter]]&amp;lt;tex&amp;gt;^\star&amp;lt;/tex&amp;gt;&lt;br /&gt;
* [[Универсальное семейство хеш-функций]]&lt;br /&gt;
* [[Расширяемое хеширование]]&amp;lt;tex&amp;gt;^\star&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== [[Сортировки]] ==&lt;br /&gt;
=== Квадратичные сортировки ===&lt;br /&gt;
* [[Сортировка выбором]]&lt;br /&gt;
* [[Сортировка пузырьком]]&lt;br /&gt;
* [[Сортировка вставками]]&lt;br /&gt;
=== Сортировки на сравнениях ===&lt;br /&gt;
* [[Сортировка Шелла]]&amp;lt;tex&amp;gt;^\star&amp;lt;/tex&amp;gt;&lt;br /&gt;
* [[Сортировка кучей]]&lt;br /&gt;
* [[Быстрая сортировка]]&lt;br /&gt;
* [[Сортировка слиянием]]&lt;br /&gt;
* [[Cортировка слиянием с использованием O(1) дополнительной памяти]]&lt;br /&gt;
* [[Терпеливая сортировка]]&amp;lt;tex&amp;gt;^\star&amp;lt;/tex&amp;gt;&lt;br /&gt;
* [[Timsort]]&amp;lt;tex&amp;gt;^\star&amp;lt;/tex&amp;gt;&lt;br /&gt;
* [[Smoothsort]]&amp;lt;tex&amp;gt;^\star&amp;lt;/tex&amp;gt;&lt;br /&gt;
* [[Теорема о нижней оценке для сортировки сравнениями]]&lt;br /&gt;
&lt;br /&gt;
=== Многопоточные сортировки ===&lt;br /&gt;
* [[Многопоточная сортировка слиянием]]&amp;lt;tex&amp;gt;^\star&amp;lt;/tex&amp;gt;&lt;br /&gt;
* [[PSRS-сортировка]]&amp;lt;tex&amp;gt;^\star&amp;lt;/tex&amp;gt;&lt;br /&gt;
=== Другие сортировки ===&lt;br /&gt;
* [[Поиск k-ой порядковой статистики]]&lt;br /&gt;
* [[Поиск k-ой порядковой статистики за линейное время]]&lt;br /&gt;
* [[Поиск k-ой порядковой статистики в двух массивах]]&amp;lt;tex&amp;gt;^\star&amp;lt;/tex&amp;gt;&lt;br /&gt;
* [[Сортировка подсчетом]]&lt;br /&gt;
* [[Цифровая сортировка]]&lt;br /&gt;
* [[Карманная сортировка]]&lt;br /&gt;
* [[Сортировка Хана]]&amp;lt;tex&amp;gt;^\star&amp;lt;/tex&amp;gt;&lt;br /&gt;
* [[Задача флага Нидерландов]]&amp;lt;tex&amp;gt;^\star&amp;lt;/tex&amp;gt;&lt;br /&gt;
* [[Блинная сортировка]]&amp;lt;tex&amp;gt;^\star&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Сортирующие сети ==&lt;br /&gt;
* [[Сортирующие сети]]&lt;br /&gt;
* [[0-1 принцип | Проверка сети компараторов на то, что она сортирующая. 0-1 принцип]]&lt;br /&gt;
* [[Сортирующие сети для квадратичных сортировок]]&lt;br /&gt;
* [[Сортировочные сети с особыми свойствами]]&amp;lt;tex&amp;gt;^\star&amp;lt;/tex&amp;gt;&lt;br /&gt;
* [[Сеть Бетчера]]&lt;br /&gt;
&lt;br /&gt;
== Алгоритмы поиска ==&lt;br /&gt;
* [[Целочисленный двоичный поиск]]&lt;br /&gt;
* [[Поиск в матрице]]&amp;lt;tex&amp;gt;^\star&amp;lt;/tex&amp;gt;&lt;br /&gt;
* [[Вещественный двоичный поиск]]&lt;br /&gt;
* [[Троичный поиск]]&lt;br /&gt;
* [[Поиск с помощью золотого сечения]]&lt;br /&gt;
* [[Интерполяционный поиск]]&lt;br /&gt;
* [[Метод Фибоначчи]]&amp;lt;tex&amp;gt;^\star&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Связь между структурами данных ==&lt;br /&gt;
* [[Связь между структурами данных]]&lt;br /&gt;
&lt;br /&gt;
= Третий семестр =&lt;br /&gt;
&lt;br /&gt;
== Основные определения теории графов ==&lt;br /&gt;
* [[Основные определения теории графов|Основные определения: граф, ребро, вершина, степень, петля, путь, цикл]]&lt;br /&gt;
* [[Лемма о рукопожатиях]]&lt;br /&gt;
* [[Теорема о существовании простого пути в случае существования пути]]&lt;br /&gt;
* [[Теорема о существовании простого цикла в случае существования цикла]]&lt;br /&gt;
* [[Матрица смежности графа]]&lt;br /&gt;
* [[Матрица инцидентности графа]]&lt;br /&gt;
* [[Циклическое пространство графа]]&amp;lt;tex&amp;gt;^\star&amp;lt;/tex&amp;gt;&lt;br /&gt;
* [[Фундаментальные циклы графа]]&amp;lt;tex&amp;gt;^\star&amp;lt;/tex&amp;gt;&lt;br /&gt;
* [[Дерево, эквивалентные определения]]&lt;br /&gt;
* [[Алгоритмы на деревьях]]&amp;lt;tex&amp;gt;^\star&amp;lt;/tex&amp;gt;&lt;br /&gt;
* [[Дополнительный, самодополнительный граф]]&lt;br /&gt;
* [[Теоретико-множественные операции над графами]]&amp;lt;tex&amp;gt;^\star&amp;lt;/tex&amp;gt;&lt;br /&gt;
* [[Рёберное ядро]]&lt;br /&gt;
* [[Факторизация графов]]&amp;lt;tex&amp;gt;^\star&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Связность в графах ==&lt;br /&gt;
* [[Отношение связности, компоненты связности]]&lt;br /&gt;
* [[Отношение реберной двусвязности]]&lt;br /&gt;
* [[Отношение вершинной двусвязности]]&lt;br /&gt;
* [[Точка сочленения, эквивалентные определения]]&lt;br /&gt;
* [[Мост, эквивалентные определения]]&lt;br /&gt;
* [[Граф компонент реберной двусвязности]]&lt;br /&gt;
* [[Граф блоков-точек сочленения]]&lt;br /&gt;
* [[k-связность]]&lt;br /&gt;
* [[Теорема Менгера]]&lt;br /&gt;
* [[Теорема Менгера, альтернативное доказательство]]&lt;br /&gt;
* [[Вершинная, реберная связность, связь между ними и минимальной степенью вершины]]&lt;br /&gt;
&lt;br /&gt;
== Остовные деревья ==&lt;br /&gt;
=== Построение остовных деревьев ===&lt;br /&gt;
* [[Остовные деревья: определения, лемма о безопасном ребре]]&lt;br /&gt;
* [[Алгоритм Прима]]&lt;br /&gt;
* [[Алгоритм Краскала]]&lt;br /&gt;
* [[Алгоритм Борувки]]&lt;br /&gt;
* [[Критерий Тарьяна минимальности остовного дерева|Теорема Тарьяна (критерий минимальности остовного дерева)]]&lt;br /&gt;
* [[Алгоритм двух китайцев]]&lt;br /&gt;
&lt;br /&gt;
=== Свойства остовных деревьев ===&lt;br /&gt;
* [[Матрица Кирхгофа]]&lt;br /&gt;
* [[Связь матрицы Кирхгофа и матрицы инцидентности]]&lt;br /&gt;
* [[Подсчет числа остовных деревьев с помощью матрицы Кирхгофа]]&lt;br /&gt;
* [[Количество помеченных деревьев]]&lt;br /&gt;
* [[Коды Прюфера]]&lt;br /&gt;
&lt;br /&gt;
== Обходы графов ==&lt;br /&gt;
=== Эйлеровы графы ===&lt;br /&gt;
* [[Эйлеров цикл, Эйлеров путь, Эйлеровы графы, Эйлеровость орграфов]]&lt;br /&gt;
* [[Покрытие ребер графа путями]]&lt;br /&gt;
* [[Алгоритм построения Эйлерова цикла]]&lt;br /&gt;
* [[Произвольно вычерчиваемые из заданной вершины графы]]&lt;br /&gt;
=== Гамильтоновы графы ===&lt;br /&gt;
* [[Гамильтоновы графы]]&lt;br /&gt;
* [[Теорема Хватала]]&lt;br /&gt;
* [[Теорема Дирака]]&lt;br /&gt;
* [[Теорема Оре]]&lt;br /&gt;
* [[Теорема Поша]]&amp;lt;tex&amp;gt;^\star&amp;lt;/tex&amp;gt;&lt;br /&gt;
* [[Теорема Гуйя-Ури]]&amp;lt;tex&amp;gt;^\star&amp;lt;/tex&amp;gt;&lt;br /&gt;
* [[Алгоритм нахождения Гамильтонова цикла в условиях теорем Дирака и Оре]]&lt;br /&gt;
* [[Теорема Гринберга]]&amp;lt;tex&amp;gt;^\star&amp;lt;/tex&amp;gt;&lt;br /&gt;
* [[Турниры]]&lt;br /&gt;
* [[Теорема Редеи-Камиона]]&lt;br /&gt;
&lt;br /&gt;
== Укладки графов ==&lt;br /&gt;
* [[Укладка графа на плоскости]]&lt;br /&gt;
* [[Формула Эйлера]]&lt;br /&gt;
* [[Непланарность K5 и K3,3|Непланарность &amp;lt;tex&amp;gt;K_5&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;K_{3,3}&amp;lt;/tex&amp;gt;]]&lt;br /&gt;
* [[Укладка дерева]]&lt;br /&gt;
* [[Укладка графа с планарными компонентами реберной двусвязности]]&lt;br /&gt;
* [[Укладка графа с планарными компонентами вершинной двусвязности]]&lt;br /&gt;
* [[Теорема Понтрягина-Куратовского]]&lt;br /&gt;
* [[Род, толщина, крупность, число скрещиваний]]&amp;lt;tex&amp;gt;^\star&amp;lt;/tex&amp;gt;&lt;br /&gt;
* [[Двойственный граф планарного графа]]&lt;br /&gt;
* [[Теорема Фари]]&amp;lt;tex&amp;gt;^\star&amp;lt;/tex&amp;gt;&lt;br /&gt;
* [[Гамма-алгоритм]]&lt;br /&gt;
&lt;br /&gt;
== Раскраски графов ==&lt;br /&gt;
* [[Раскраска графа]]&lt;br /&gt;
* [[Двудольные графы и раскраска в 2 цвета]]&lt;br /&gt;
* [[Хроматический многочлен]]&lt;br /&gt;
* [[Формула Зыкова]]&lt;br /&gt;
* [[Формула Уитни]]&lt;br /&gt;
* [[Теорема Брукса]]&lt;br /&gt;
* [[Верхние и нижние оценки хроматического числа]]&amp;lt;tex&amp;gt;^\star&amp;lt;/tex&amp;gt;&lt;br /&gt;
* [[Хроматическое число планарного графа]]&lt;br /&gt;
* [[Многочлен Татта]]&amp;lt;tex&amp;gt;^\star&amp;lt;/tex&amp;gt;&lt;br /&gt;
* [[Теория Рамсея]]&amp;lt;tex&amp;gt;^\star&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Обход в глубину ==&lt;br /&gt;
* [[Обход в глубину, цвета вершин]]&lt;br /&gt;
* [[Лемма о белых путях]]&lt;br /&gt;
* [[Использование обхода в глубину для проверки связности]]&lt;br /&gt;
* [[Использование обхода в глубину для поиска цикла]]&lt;br /&gt;
* [[Использование обхода в глубину для топологической сортировки]]&lt;br /&gt;
* [[Использование обхода в глубину для поиска компонент сильной связности]]&lt;br /&gt;
* [[Использование обхода в глубину для поиска точек сочленения]]&lt;br /&gt;
* [[Построение компонент вершинной двусвязности]]&lt;br /&gt;
* [[Использование обхода в глубину для поиска мостов]]&lt;br /&gt;
* [[Построение компонент реберной двусвязности]]&lt;br /&gt;
&lt;br /&gt;
== Кратчайшие пути в графах ==&lt;br /&gt;
* [[Обход в ширину]]&lt;br /&gt;
* [[Алгоритм Форда-Беллмана]]&lt;br /&gt;
* [[Алгоритм Дейкстры]]&lt;br /&gt;
* [[Алгоритм Флойда]]&lt;br /&gt;
* [[Алгоритм Джонсона]]&lt;br /&gt;
* [[Алгоритм Левита]]&amp;lt;tex&amp;gt;^\star&amp;lt;/tex&amp;gt;&lt;br /&gt;
* [[Алгоритм A*]] &amp;lt;tex&amp;gt;^\star&amp;lt;/tex&amp;gt;&lt;br /&gt;
* [[Алгоритм D*]] &amp;lt;tex&amp;gt;^\star&amp;lt;/tex&amp;gt;&lt;br /&gt;
* [[Эвристики для поиска кратчайших путей]]&amp;lt;tex&amp;gt;^\star&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Задача о паросочетании ==&lt;br /&gt;
* [[Паросочетания: основные определения, теорема о максимальном паросочетании и дополняющих цепях]]&lt;br /&gt;
* [[Алгоритм Форда-Фалкерсона для поиска максимального паросочетания]]&lt;br /&gt;
* [[Алгоритм Куна для поиска максимального паросочетания]]&lt;br /&gt;
* [[Теорема Холла]]&lt;br /&gt;
* [[Связь максимального паросочетания и минимального вершинного покрытия в двудольных графах]]&lt;br /&gt;
* [[Связь вершинного покрытия и независимого множества]]&lt;br /&gt;
* [[Рёберное ядро]]&amp;lt;tex&amp;gt;^\star&amp;lt;/tex&amp;gt;&lt;br /&gt;
* [[Матрица Татта и связь с размером максимального паросочетания в двудольном графе]]&lt;br /&gt;
* [[Теорема Татта о существовании полного паросочетания]]&lt;br /&gt;
* [[Алгоритм вырезания соцветий|Паросочетания в недвудольных графах. Алгоритм вырезания соцветий]]&lt;br /&gt;
* [[Декомпозиция Эдмондса-Галлаи]]&lt;br /&gt;
* [[Задача об устойчивом паросочетании]]&amp;lt;tex&amp;gt;^\star&amp;lt;/tex&amp;gt;&lt;br /&gt;
* [[Совершенное паросочетание в кубическом графе]]&amp;lt;tex&amp;gt;^\star&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Задача о максимальном потоке ==&lt;br /&gt;
* [[Определение сети, потока]]&lt;br /&gt;
* [[Разрез, лемма о потоке через разрез]]&lt;br /&gt;
* [[Дополняющая сеть, дополняющий путь]]&lt;br /&gt;
* [[Сложение и разность потоков]]&lt;br /&gt;
* [[Теорема Форда-Фалкерсона]]&lt;br /&gt;
* [[Алгоритм Форда-Фалкерсона, реализация с помощью поиска в глубину]]&lt;br /&gt;
* [[Алоритм Эдмондса-Карпа]]&lt;br /&gt;
* [[Алгоритм масштабирования потока]]&lt;br /&gt;
* [[Блокирующий поток]]&lt;br /&gt;
* [[Схема алгоритма Диница]]&lt;br /&gt;
* [[Теоремы Карзанова о числе итераций алгоритма Диница в сети с целочисленными пропускными способностями]]&lt;br /&gt;
* [[Алгоритм Голдберга-Тарьяна]]&amp;lt;tex&amp;gt;^\star&amp;lt;/tex&amp;gt;&lt;br /&gt;
* [[Алгоритм поиска блокирующего потока в ациклической сети]]&lt;br /&gt;
* [[Метод проталкивания предпотока]]&lt;br /&gt;
* [[Алгоритм &amp;quot;поднять-в-начало&amp;quot;]]&lt;br /&gt;
* [[Теорема о декомпозиции]]&lt;br /&gt;
* [[Теорема о декомпозиционном барьере]]&lt;br /&gt;
* [[Циркуляция потока]]&lt;br /&gt;
* [[Алгоритм Каргера для нахождения минимального разреза]]&amp;lt;tex&amp;gt;^\star&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Задача о потоке минимальной стоимости ==&lt;br /&gt;
* [[Поток минимальной стоимости]]&lt;br /&gt;
* [[Теорема Форда-Фалкерсона о потоке минимальной стоимости]]&lt;br /&gt;
* [[Лемма об эквивалентности свойства потока быть минимальной стоимости и отсутствии отрицательных циклов в остаточной сети]]&lt;br /&gt;
* [[Поиск потока минимальной стоимости методом дополнения вдоль путей минимальной стоимости]]&lt;br /&gt;
* [[Использование потенциалов Джонсона при поиске потока минимальной стоимости]]&lt;br /&gt;
* [[Сведение задачи о назначениях к задаче о потоке минимальной стоимости]]&lt;br /&gt;
* [[Венгерский алгоритм решения задачи о назначениях]]&lt;br /&gt;
&lt;br /&gt;
= Четвертый семестр =&lt;br /&gt;
&lt;br /&gt;
== Основные определения. Простые комбинаторные свойства слов ==&lt;br /&gt;
* [[Основные определения, связанные со строками]]&lt;br /&gt;
* [[Период и бордер, их связь]]&lt;br /&gt;
* [[Слово Фибоначчи]]&lt;br /&gt;
* [[Слово Туэ-Морса]]&lt;br /&gt;
* [[Декомпозиция Линдона]]&amp;lt;tex&amp;gt;^\star&amp;lt;/tex&amp;gt;&lt;br /&gt;
* [[Алгоритм Ландау-Шмидта]]&amp;lt;tex&amp;gt;^\star&amp;lt;/tex&amp;gt;&lt;br /&gt;
* [[Алгоритм Крочемора]]&amp;lt;tex&amp;gt;^\star&amp;lt;/tex&amp;gt;&lt;br /&gt;
* [[Алгоритм Мейна-Лоренца]]&amp;lt;tex&amp;gt;^\star&amp;lt;/tex&amp;gt;&lt;br /&gt;
* [[Алгоритм Манакера]]&amp;lt;tex&amp;gt;^\star&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== [[Поиск подстроки в строке]] ==&lt;br /&gt;
=== Точный поиск ===&lt;br /&gt;
* [[Наивный алгоритм поиска подстроки в строке]]&lt;br /&gt;
* [[Поиск подстроки в строке с использованием хеширования. Алгоритм Рабина-Карпа]]&lt;br /&gt;
* [[Поиск наибольшей общей подстроки двух строк с использованием хеширования]]&lt;br /&gt;
* [[Префикс-функция]]&lt;br /&gt;
* [[Алгоритм Кнута-Морриса-Пратта]]&lt;br /&gt;
* [[Автомат Кнута-Морриса-Пратта]]&lt;br /&gt;
* [[Z-функция]]&lt;br /&gt;
* [[Бор]]&lt;br /&gt;
* [[Алгоритм Ахо-Корасик]]&lt;br /&gt;
* [[Алгоритм Бойера-Мура]]&lt;br /&gt;
* [[Алгоритм Апостолико-Крочемора]]&amp;lt;tex&amp;gt;^\star&amp;lt;/tex&amp;gt;&lt;br /&gt;
* [[Алгоритм Колусси]]&amp;lt;tex&amp;gt;^\star&amp;lt;/tex&amp;gt;&lt;br /&gt;
* [[Алгоритм Shift-And]]&amp;lt;tex&amp;gt;^\star&amp;lt;/tex&amp;gt;&lt;br /&gt;
* [[Двусторонний алгоритм]]&amp;lt;tex&amp;gt;^\star&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Нечёткий поиск ===&lt;br /&gt;
* [[Алгоритм Ландау-Вишкина (k несовпадений)]]&amp;lt;tex&amp;gt;^\star&amp;lt;/tex&amp;gt;&lt;br /&gt;
* [[Алгоритм Ландау-Вишкина (k различий)]]&amp;lt;tex&amp;gt;^\star&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Суффиксное дерево ==&lt;br /&gt;
* [[Суффиксный бор]]&lt;br /&gt;
* [[Сжатое суффиксное дерево]]&lt;br /&gt;
* [[Алгоритм Укконена]]&lt;br /&gt;
* [[Алгоритм МакКрейта]]&amp;lt;tex&amp;gt;^\star&amp;lt;/tex&amp;gt;&lt;br /&gt;
* [[Алгоритм Фарача]]&amp;lt;tex&amp;gt;^\star&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Суффиксный массив ==&lt;br /&gt;
* [[Суффиксный массив]]&lt;br /&gt;
* [[Построение суффиксного массива с помощью стандартных методов сортировки]]&lt;br /&gt;
* [[Алгоритм цифровой сортировки суффиксов циклической строки]]&lt;br /&gt;
* [[Алгоритм Касаи и др.]]&lt;br /&gt;
* [[Алгоритм Карккайнена-Сандерса]]&lt;br /&gt;
* [[Алгоритм поиска подстроки в строке с помощью суффиксного массива]]&lt;br /&gt;
&lt;br /&gt;
== Задача о наименьшем общем предке ==&lt;br /&gt;
* [[Сведение задачи LCA к задаче RMQ]]&lt;br /&gt;
* [[Сведение задачи RMQ к задаче LCA]]&lt;br /&gt;
* [[Метод двоичного подъема]]&lt;br /&gt;
* [[Решение RMQ с помощью разреженной таблицы]]&lt;br /&gt;
* [[Алгоритм Фарака-Колтона и Бендера]] (решение +/-1 RMQ с помощью метода четырех русских)&lt;br /&gt;
* [[Алгоритм Хьюи]]&lt;br /&gt;
* [[Heavy-light декомпозиция]]&lt;br /&gt;
* [[Алгоритм Шибера-Вишкина]]&amp;lt;tex&amp;gt;^\star&amp;lt;/tex&amp;gt;&lt;br /&gt;
* [[Алгоритм Тарьяна поиска LCA за O(1) в оффлайн]]&amp;lt;tex&amp;gt;^\star&amp;lt;/tex&amp;gt;&lt;br /&gt;
* [[Link-Cut Tree]]&amp;lt;tex&amp;gt;^\star&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Матроиды ==&lt;br /&gt;
=== Основные факты теории матроидов ===&lt;br /&gt;
* [[Определение матроида]]&lt;br /&gt;
* [[Примеры матроидов]]&lt;br /&gt;
* [[Прямая сумма матроидов]]&lt;br /&gt;
* [[Теорема Радо-Эдмондса (жадный алгоритм)]]&lt;br /&gt;
* [[Теорема о базах]]&lt;br /&gt;
* [[Аксиоматизация матроида базами]]&lt;br /&gt;
* [[Теорема о циклах]]&lt;br /&gt;
* [[Аксиоматизация матроида циклами]]&lt;br /&gt;
* [[Ранговая функция, полумодулярность]]&lt;br /&gt;
* [[Аксиоматизация матроида рангами]]&lt;br /&gt;
* [[Двойственный матроид]]&lt;br /&gt;
* [[Оператор замыкания для матроидов]]&lt;br /&gt;
* [[Покрытия, закрытые множества]]&lt;br /&gt;
* [[Матроид Вамоса]]&amp;lt;tex&amp;gt;^\star&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Пересечение матроидов ===&lt;br /&gt;
* [[Пересечение матроидов, определение, примеры]]&lt;br /&gt;
* [[Лемма о паросочетании в графе замен]]&lt;br /&gt;
* [[Лемма о единственном паросочетании в графе замен]]&lt;br /&gt;
* [[Граф замен для двух матроидов]]&lt;br /&gt;
* [[Лемма о единственном паросочетании в подграфе замен, индуцированном кратчайшим путем]]&lt;br /&gt;
* [[Алгоритм построения базы в пересечении матроидов]]&lt;br /&gt;
&lt;br /&gt;
=== Объединение матроидов ===&lt;br /&gt;
* [[Объединение матроидов, проверка множества на независимость]]&lt;br /&gt;
* [[Объединение матроидов, доказательство того, что объединение является матроидом]]&lt;br /&gt;
* [[Алгоритм построения базы в объединении матроидов]]&lt;br /&gt;
&lt;br /&gt;
== Теория расписаний ==&lt;br /&gt;
* [[Классификация задач]]&lt;br /&gt;
* [[Методы решения задач теории расписаний]]&lt;br /&gt;
* [[Правило Лаулера]]&lt;br /&gt;
* [[Flow shop]]&lt;br /&gt;
* [[P1sumu|&amp;lt;tex&amp;gt;1 \mid \mid \sum U_{i}&amp;lt;/tex&amp;gt;]]&lt;br /&gt;
* [[1ripi1sumwc|&amp;lt;tex&amp;gt;1 \mid r_{i}, p_i=1\mid \sum w_{i}C_{i}&amp;lt;/tex&amp;gt;]]&lt;br /&gt;
* [[1ridipi1|&amp;lt;tex&amp;gt;1 \mid r_{i}, d_{i}, p_{i} = 1 \mid -&amp;lt;/tex&amp;gt;]]&lt;br /&gt;
* [[1ripipsumwu|&amp;lt;tex&amp;gt; 1 \mid r_i,p_i=p \mid \sum w_i U_i&amp;lt;/tex&amp;gt;]]&lt;br /&gt;
* [[1outtreesumwc | &amp;lt;tex&amp;gt;1 \mid outtree \mid \sum w_i C_i&amp;lt;/tex&amp;gt;]]&lt;br /&gt;
* [[1pi1sumwu|&amp;lt;tex&amp;gt;1 \mid p_{i} = 1 \mid \sum w_{i}U_{i}&amp;lt;/tex&amp;gt;]]&lt;br /&gt;
* [[1precpmtnrifmax|&amp;lt;tex&amp;gt;1 \mid prec, pmtn, r_i \mid f_{\max}&amp;lt;/tex&amp;gt;]]&lt;br /&gt;
* [[1precripi1Lmax|&amp;lt;tex&amp;gt;1 \mid prec; r_i; p_i = 1 \mid L_{max}&amp;lt;/tex&amp;gt;]]&lt;br /&gt;
* [[P2precpi1Lmax|&amp;lt;tex&amp;gt;P2 \mid prec, p_i = 1 \mid L_{\max}&amp;lt;/tex&amp;gt;]]&lt;br /&gt;
* [[PpmtnriLmax|&amp;lt;tex&amp;gt;P \mid pmtn, r_i \mid L_{max}&amp;lt;/tex&amp;gt;]]&lt;br /&gt;
* [[QpmtnCmax|&amp;lt;tex&amp;gt;Q \mid pmtn \mid C_{max}&amp;lt;/tex&amp;gt;]]&lt;br /&gt;
* [[QpmtnriLmax|&amp;lt;tex&amp;gt;Q \mid pmtn, r_{i} \mid L_{max}&amp;lt;/tex&amp;gt;]]&lt;br /&gt;
* [[QSumCi|&amp;lt;tex&amp;gt;Q\mid\mid\sum{C_i}&amp;lt;/tex&amp;gt;]]&lt;br /&gt;
* [[R2Cmax|&amp;lt;tex&amp;gt;R2 \mid \mid C_{max}&amp;lt;/tex&amp;gt;]]&lt;br /&gt;
* [[F2Cmax|&amp;lt;tex&amp;gt;F2 \mid \mid C_{max}&amp;lt;/tex&amp;gt;]]&lt;br /&gt;
* [[Fpij1sumwu|&amp;lt;tex&amp;gt;F \mid p_{ij} = 1 \mid \sum w_i U_i&amp;lt;/tex&amp;gt;]]&lt;br /&gt;
* [[O2Cmax|&amp;lt;tex&amp;gt;O2 \mid \mid C_{max}&amp;lt;/tex&amp;gt;]]&lt;br /&gt;
* [[Opi1sumu|&amp;lt;tex&amp;gt;O \mid p_{ij} = 1 \mid \sum U_i&amp;lt;/tex&amp;gt;]]&lt;br /&gt;
* [[J2ni2Cmax|&amp;lt;tex&amp;gt;J2 \mid n_{i} \le 2 \mid C_{max}&amp;lt;/tex&amp;gt;]]&lt;br /&gt;
* [[J2pij1Lmax| &amp;lt;tex&amp;gt;J2\mid p_{ij} = 1\mid L_{max}&amp;lt;/tex&amp;gt;]]&lt;/div&gt;</summary>
		<author><name>Ильнар</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%94%D0%B8%D1%81%D0%BA%D1%80%D0%B5%D1%82%D0%BD%D0%B0%D1%8F_%D0%BC%D0%B0%D1%82%D0%B5%D0%BC%D0%B0%D1%82%D0%B8%D0%BA%D0%B0,_%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC%D1%8B_%D0%B8_%D1%81%D1%82%D1%80%D1%83%D0%BA%D1%82%D1%83%D1%80%D1%8B_%D0%B4%D0%B0%D0%BD%D0%BD%D1%8B%D1%85&amp;diff=52699</id>
		<title>Дискретная математика, алгоритмы и структуры данных</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%94%D0%B8%D1%81%D0%BA%D1%80%D0%B5%D1%82%D0%BD%D0%B0%D1%8F_%D0%BC%D0%B0%D1%82%D0%B5%D0%BC%D0%B0%D1%82%D0%B8%D0%BA%D0%B0,_%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC%D1%8B_%D0%B8_%D1%81%D1%82%D1%80%D1%83%D0%BA%D1%82%D1%83%D1%80%D1%8B_%D0%B4%D0%B0%D0%BD%D0%BD%D1%8B%D1%85&amp;diff=52699"/>
				<updated>2016-03-18T15:44:01Z</updated>
		
		<summary type="html">&lt;p&gt;Ильнар: /* Другие задачи */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Категория:Дискретная математика и алгоритмы]]&lt;br /&gt;
[[Категория: Алгоритмы и структуры данных]]&lt;br /&gt;
Убедительная просьба читать [[Обсуждение:Дискретная_математика_и_алгоритмы | правила оформления вики-конспектов]].&lt;br /&gt;
&lt;br /&gt;
Символом &amp;lt;tex&amp;gt; \star &amp;lt;/tex&amp;gt; помечены дополнительные темы (возможно, сложные), которые не были подробно рассмотрены (или вообще рассмотрены) в рамках курса.&lt;br /&gt;
&lt;br /&gt;
= Первый семестр =&lt;br /&gt;
&lt;br /&gt;
== Отношения ==&lt;br /&gt;
*[[Определение отношения]]&lt;br /&gt;
*[[Композиция отношений|Композиция отношений, степень отношения, обратное отношение]]&lt;br /&gt;
*[[Рефлексивное отношение|Рефлексивное отношение. Антирефлексивное отношение.]]&lt;br /&gt;
*[[Симметричное отношение]]&lt;br /&gt;
*[[Антисимметричное отношение]]&lt;br /&gt;
*[[Транзитивное отношение]]&lt;br /&gt;
*[[Отношение порядка]]&lt;br /&gt;
*[[Отношение эквивалентности]]&lt;br /&gt;
*[[Транзитивное замыкание|Транзитивное замыкание отношения]]&lt;br /&gt;
*[[Алгоритм Флойда — Уоршелла|Алгоритм Флойда-Уоршалла построения транзитивного замыкания отношения]]&lt;br /&gt;
*[[Транзитивный остов]]&lt;br /&gt;
&lt;br /&gt;
== Булевы функции ==&lt;br /&gt;
*[[Определение булевой функции]]&lt;br /&gt;
*[[Побитовые операции]]&amp;lt;tex&amp;gt;^\star&amp;lt;/tex&amp;gt;&lt;br /&gt;
*[[Суперпозиции]]&lt;br /&gt;
*[[ДНФ]]&lt;br /&gt;
*[[Сокращенная и минимальная ДНФ | Сокращенная и минимальная ДНФ, минимизация ДНФ методами гиперкубов, карт Карно, Квайна]]&lt;br /&gt;
*[[КНФ]]&lt;br /&gt;
*[[2-SAT]]&lt;br /&gt;
*[[Специальные формы КНФ|Специальные формы КНФ: КНФ в форме Хорна и КНФ в форме Крома]]&lt;br /&gt;
*[[Полином Жегалкина | Полином Жегалкина, преобразование Мёбиуса]]&lt;br /&gt;
*[[Полные системы функций. Теорема Поста о полной системе функций]]&lt;br /&gt;
*[[Представление функции класса DM с помощью медианы]]&lt;br /&gt;
*[[Пороговая функция]]&lt;br /&gt;
*[[Троичная логика]]&amp;lt;tex&amp;gt;^\star&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Схемы из функциональных элементов ==&lt;br /&gt;
*[[Реализация булевой функции схемой из функциональных элементов]]&lt;br /&gt;
*[[Простейшие методы синтеза схем из функциональных элементов]]&lt;br /&gt;
*[[Метод Лупанова синтеза схем]]&lt;br /&gt;
*[[Cумматор]]&lt;br /&gt;
*[[Каскадный сумматор]]&lt;br /&gt;
*[[Двоичный каскадный сумматор]]&lt;br /&gt;
*[[Троичный сумматор]]&amp;lt;tex&amp;gt;^\star&amp;lt;/tex&amp;gt;&lt;br /&gt;
*[[Реализация вычитания сумматором]]&lt;br /&gt;
*[[Матричный умножитель]]&lt;br /&gt;
*[[Дерево Уоллеса]]&lt;br /&gt;
*[[Контактная схема]]&lt;br /&gt;
*[[Триггеры]]&amp;lt;tex&amp;gt;^\star&amp;lt;/tex&amp;gt;&lt;br /&gt;
*[[Квантовые гейты]]&amp;lt;tex&amp;gt;^\star&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Представление информации ==&lt;br /&gt;
*[[Кодирование информации]]&lt;br /&gt;
*[[Представление целых чисел: прямой код, код со сдвигом, дополнительный код]]&lt;br /&gt;
*[[Представление вещественных чисел]]&lt;br /&gt;
*[[Представление символов, таблицы кодировок]]&amp;lt;tex&amp;gt;^\star&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Алгоритмы сжатия ==&lt;br /&gt;
* [[Алгоритм Хаффмана]]&lt;br /&gt;
* [[Оптимальное хранение словаря в алгоритме Хаффмана]]&lt;br /&gt;
* [[Алгоритм Хаффмана за O(n)]]&lt;br /&gt;
* [[Алгоритм Ху-Таккера]]&amp;lt;tex&amp;gt;^\star&amp;lt;/tex&amp;gt;&lt;br /&gt;
* [[Неравенство Крафта]]&lt;br /&gt;
* [[Неравенство Макмиллана]]&lt;br /&gt;
* [[Код Шеннона]]&lt;br /&gt;
* [[Оптимальный префиксный код с длиной кодового слова не более L бит]]&amp;lt;tex&amp;gt;^\star&amp;lt;/tex&amp;gt;&lt;br /&gt;
* [[Алгоритмы LZ77 и LZ78]]&lt;br /&gt;
* [[Алгоритм LZW]]&lt;br /&gt;
* [[Алгоритм LZSS]]&amp;lt;tex&amp;gt;^\star&amp;lt;/tex&amp;gt;&lt;br /&gt;
* [[Преобразование Барроуза-Уиллера | Преобразование Барроуза-Уиллера и обратное ему]]&lt;br /&gt;
* [[Преобразование MTF]]&lt;br /&gt;
* [[Расстояние Хэмминга]]&lt;br /&gt;
* [[Избыточное кодирование, код Хэмминга]]&lt;br /&gt;
* [[Гамма-, дельта- и омега-код Элиаса]]&amp;lt;tex&amp;gt;^\star&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Комбинаторика ==&lt;br /&gt;
=== Комбинаторные объекты ===&lt;br /&gt;
* [[Комбинаторные объекты]]&lt;br /&gt;
* [[Лексикографический порядок]]&lt;br /&gt;
* [[Коды Грея]]&lt;br /&gt;
* [[Коды Грея для перестановок]]&lt;br /&gt;
* [[Коды антигрея]]&lt;br /&gt;
* [[Цепные коды]]&lt;br /&gt;
* [[Правильные скобочные последовательности]]&lt;br /&gt;
&lt;br /&gt;
=== Генерация комбинаторных объектов ===&lt;br /&gt;
* [[Генерация комбинаторных объектов в лексикографическом порядке]]&lt;br /&gt;
* [[Получение номера по объекту]]&lt;br /&gt;
* [[Получение объекта по номеру]]&lt;br /&gt;
* [[Получение следующего объекта]]&lt;br /&gt;
* [[Получение предыдущего объекта]]&amp;lt;tex&amp;gt;^\star&amp;lt;/tex&amp;gt;  &lt;br /&gt;
* [[Метод генерации случайной перестановки, алгоритм Фишера-Йетса]]&lt;br /&gt;
* [[Методы генерации случайного сочетания]]&amp;lt;tex&amp;gt;^\star&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Подсчёт числа объектов ===&lt;br /&gt;
* [[Формула включения-исключения | Формула включения-исключения, подсчет числа беспорядков]]&lt;br /&gt;
* [[Нахождение количества разбиений числа на слагаемые | Нахождение количества разбиений числа на слагаемые. Пентагональная теорема Эйлера]]&lt;br /&gt;
* [[Производящая функция]]&lt;br /&gt;
* [[Лемма Бёрнсайда и Теорема Пойа]]&lt;br /&gt;
* [[Задача об ожерельях]]&lt;br /&gt;
* [[Числа Стирлинга первого рода]]&lt;br /&gt;
* [[Числа Стирлинга второго рода]]&lt;br /&gt;
* [[Числа Эйлера I и II рода | Числа Эйлера первого и второго рода. Подъемы в перестановках]]&amp;lt;tex&amp;gt;^\star&amp;lt;/tex&amp;gt;&lt;br /&gt;
* [[Числа Каталана]]&lt;br /&gt;
&lt;br /&gt;
=== Свойства комбинаторных объектов ===&lt;br /&gt;
* [[Умножение перестановок, обратная перестановка, группа перестановок]]&lt;br /&gt;
* [[Действие перестановки на набор из элементов, представление в виде циклов]]&lt;br /&gt;
* [[Таблица инверсий]]&lt;br /&gt;
* [[Теорема Кэли]]&lt;br /&gt;
* [[Матричное представление перестановок]]&lt;br /&gt;
* [[Задача о минимуме/максимуме скалярного произведения]]&lt;br /&gt;
* [[Задача о монотонных подпоследовательностях, теорема о связи длины НВП и НУП]]&lt;br /&gt;
&lt;br /&gt;
== [[Динамическое программирование]] ==&lt;br /&gt;
=== Классические задачи динамического программирования ===&lt;br /&gt;
*[[Кратчайший путь в ациклическом графе]]&lt;br /&gt;
*[[Задача о числе путей в ациклическом графе]]&lt;br /&gt;
*[[Задача о расстановке знаков в выражении]]&lt;br /&gt;
*[[Задача о порядке перемножения матриц]]&lt;br /&gt;
*[[Задача о наибольшей общей подпоследовательности]]&lt;br /&gt;
*[[Задача о наибольшей возрастающей подпоследовательности]]&lt;br /&gt;
*[[Задача коммивояжера, ДП по подмножествам]]&lt;br /&gt;
*[[Задача о редакционном расстоянии, алгоритм Вагнера-Фишера]]&lt;br /&gt;
*[[Задача о рюкзаке]]&lt;br /&gt;
&lt;br /&gt;
=== Способы оптимизации методов динамического программирования ===&lt;br /&gt;
*[[Метод четырех русских для умножения матриц]]&lt;br /&gt;
*[[Применение метода четырех русских в задачах ДП на примере задачи о НОП]]&amp;lt;tex&amp;gt;^\star&amp;lt;/tex&amp;gt;&lt;br /&gt;
*[[Задача об оптимальном префиксном коде с сохранением порядка. Монотонность точки разреза]]&lt;br /&gt;
*[[Meet-in-the-middle]]&amp;lt;tex&amp;gt;^\star&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Другие задачи ===&lt;br /&gt;
*[[Задача о расстоянии Дамерау-Левенштейна]]&amp;lt;tex&amp;gt;^\star&amp;lt;/tex&amp;gt;&lt;br /&gt;
*[[Задача о выводе в контекстно-свободной грамматике, алгоритм Кока-Янгера-Касами]]&lt;br /&gt;
*[[Задача о наибольшей подпоследовательности-палиндроме]]&lt;br /&gt;
*[[Наибольшая общая возрастающая подпоследовательность]]&amp;lt;tex&amp;gt;^\star&amp;lt;/tex&amp;gt;&lt;br /&gt;
*[[Задача о наибольшей общей палиндромной подпоследовательности]]&amp;lt;tex&amp;gt;^\star&amp;lt;/tex&amp;gt;&lt;br /&gt;
*[[Динамическое программирование по профилю]]&amp;lt;tex&amp;gt;^\star&amp;lt;/tex&amp;gt;&lt;br /&gt;
*[[Динамика по поддеревьям]]&lt;br /&gt;
*[[Количество подпалиндромов в строке]]&lt;br /&gt;
&lt;br /&gt;
== Теория вероятностей ==&lt;br /&gt;
*[[Вероятностное пространство, элементарный исход, событие]]&lt;br /&gt;
*[[Независимые события]]&lt;br /&gt;
*[[Условная вероятность]]&lt;br /&gt;
*[[Формула полной вероятности]]&lt;br /&gt;
*[[Формула Байеса]]&lt;br /&gt;
*[[Дискретная случайная величина]]&lt;br /&gt;
*[[Независимые случайные величины]]&lt;br /&gt;
*[[Математическое ожидание случайной величины]]&lt;br /&gt;
*[[Дисперсия случайной величины]]&lt;br /&gt;
*[[Ковариация случайных величин]]&lt;br /&gt;
*[[Корреляция случайных величин]]&lt;br /&gt;
*[[Неравенство Маркова]]&lt;br /&gt;
*[[Энтропия случайного источника]]&lt;br /&gt;
*[[Симуляция одним распределением другого]]&lt;br /&gt;
*[[Арифметическое кодирование]]&lt;br /&gt;
*[[Парадоксы теории вероятностей]]&amp;lt;tex&amp;gt;^\star&amp;lt;/tex&amp;gt;&lt;br /&gt;
*[[Схема Бернулли]]&amp;lt;tex&amp;gt;^\star&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Марковские цепи ==&lt;br /&gt;
&lt;br /&gt;
* [[Марковская цепь]]&lt;br /&gt;
* [[Теорема о поглощении]]&lt;br /&gt;
* [[Фундаментальная матрица]]&lt;br /&gt;
* [[Математическое ожидание времени поглощения]]&lt;br /&gt;
* [[Расчет вероятности поглощения в состоянии]]&lt;br /&gt;
* [[Эргодическая марковская цепь]]&lt;br /&gt;
* [[Регулярная марковская цепь]]&lt;br /&gt;
* [[Примеры использования Марковских цепей]]&lt;br /&gt;
* [[Скрытые Марковские модели]]&amp;lt;tex&amp;gt;^\star&amp;lt;/tex&amp;gt;&lt;br /&gt;
* [[Алгоритм Витерби]]&amp;lt;tex&amp;gt;^\star&amp;lt;/tex&amp;gt;&lt;br /&gt;
* [[Алгоритм &amp;quot;Вперед-Назад&amp;quot;]]&amp;lt;tex&amp;gt;^\star&amp;lt;/tex&amp;gt;&lt;br /&gt;
* [[Алгоритм Баума-Велша]]&amp;lt;tex&amp;gt;^\star&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Второй семестр =&lt;br /&gt;
&lt;br /&gt;
== Амортизационный анализ ==&lt;br /&gt;
* [[Амортизационный анализ]]&lt;br /&gt;
* [[Динамический массив]]&lt;br /&gt;
* [[Hashed Array Tree]]&amp;lt;tex&amp;gt;^\star&amp;lt;/tex&amp;gt;&lt;br /&gt;
* [[Список]]&lt;br /&gt;
* [[Стек]]&lt;br /&gt;
* [[Очередь]]&lt;br /&gt;
* [[Дек]]&lt;br /&gt;
* [[Мажорирующий элемент]]&lt;br /&gt;
* [[Счетчик Кнута]]&lt;br /&gt;
* [[Мастер-теорема]]&amp;lt;tex&amp;gt;^\star&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Персистентные структуры данных ==&lt;br /&gt;
* [[Персистентные структуры данных]]&lt;br /&gt;
* [[List order maintenance]]&amp;lt;tex&amp;gt;^\star&amp;lt;/tex&amp;gt;&lt;br /&gt;
* [[Персистентный стек]]&lt;br /&gt;
* [[Персистентная очередь]]&lt;br /&gt;
* [[Персистентный дек]]&lt;br /&gt;
* [[Персистентная приоритетная очередь]]&lt;br /&gt;
&lt;br /&gt;
== [[Приоритетные очереди]] ==&lt;br /&gt;
* [[Двоичная куча]]&lt;br /&gt;
* [[Биномиальная куча]]&lt;br /&gt;
* [[Фибоначчиева куча]]&lt;br /&gt;
* [[Левосторонняя куча]]&lt;br /&gt;
* [[Тонкая куча]]&lt;br /&gt;
* [[Толстая куча на избыточном счетчике]]&lt;br /&gt;
* [[Куча Бродала-Окасаки]]&amp;lt;tex&amp;gt;^\star&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Система непересекающихся множеств ==&lt;br /&gt;
* [[СНМ (наивные реализации) | Наивные реализации]]&lt;br /&gt;
* [[СНМ (списки с весовой эвристикой) | Списки с весовой эвристикой]]&lt;br /&gt;
* [[СНМ(реализация с помощью леса корневых деревьев) | Реализация с помощью леса корневых деревьев]]&lt;br /&gt;
* [[СНМ с операцией удаления за О(1)]]&amp;lt;tex&amp;gt;^\star&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== [[Поисковые структуры данных]] ==&lt;br /&gt;
* [[Упорядоченное множество]]&lt;br /&gt;
* [[Дерево поиска, наивная реализация]]&lt;br /&gt;
* [[АВЛ-дерево]]&lt;br /&gt;
* [[2-3 дерево]]&lt;br /&gt;
* [[B-дерево]]&lt;br /&gt;
* [[Красно-черное дерево]]&lt;br /&gt;
* [[Декартово дерево]]&lt;br /&gt;
* [[Декартово дерево по неявному ключу]]&lt;br /&gt;
* [[Splay-дерево]]&lt;br /&gt;
* [[Tango-дерево]]&amp;lt;tex&amp;gt;^\star&amp;lt;/tex&amp;gt;&lt;br /&gt;
* [[Рандомизированное бинарное дерево поиска]]&lt;br /&gt;
* [[Дерево ван Эмде Боаса]]&lt;br /&gt;
* [[Список с пропусками]]&lt;br /&gt;
* [[Fusion tree]]&amp;lt;tex&amp;gt;^\star&amp;lt;/tex&amp;gt;&lt;br /&gt;
* [[Сверхбыстрый цифровой бор]]&lt;br /&gt;
* [[Rope]]&amp;lt;tex&amp;gt;^\star&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Дерево отрезков ==&lt;br /&gt;
&lt;br /&gt;
* [[Статистики на отрезках. Корневая эвристика]]&lt;br /&gt;
* [[Дерево отрезков. Построение]]&lt;br /&gt;
* [[Реализация запроса в дереве отрезков сверху]]&lt;br /&gt;
* [[Реализация запроса в дереве отрезков снизу]]&lt;br /&gt;
* [[Несогласованные поддеревья. Реализация массового обновления]]&lt;br /&gt;
* [[Многомерное дерево отрезков]]&lt;br /&gt;
* [[Сжатое многомерное дерево отрезков]]&lt;br /&gt;
&lt;br /&gt;
== Дерево Фенвика ==&lt;br /&gt;
* [[Дерево Фенвика]]&lt;br /&gt;
* [[Встречное дерево Фенвика]]&lt;br /&gt;
* [[Дерево Фенвика для некоммутативных операций]]&lt;br /&gt;
* [[Многомерное дерево Фенвика]]&lt;br /&gt;
&lt;br /&gt;
== Хеширование ==&lt;br /&gt;
* [[Хеш-таблица]]&lt;br /&gt;
* [[Разрешение коллизий]]&lt;br /&gt;
* [[Хеширование кукушки]]&lt;br /&gt;
* [[Идеальное хеширование]]&lt;br /&gt;
* [[Перехеширование]]&lt;br /&gt;
* [[Фильтр Блума]]&lt;br /&gt;
* [[Quotient filter]]&amp;lt;tex&amp;gt;^\star&amp;lt;/tex&amp;gt;&lt;br /&gt;
* [[Универсальное семейство хеш-функций]]&lt;br /&gt;
* [[Расширяемое хеширование]]&amp;lt;tex&amp;gt;^\star&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== [[Сортировки]] ==&lt;br /&gt;
=== Квадратичные сортировки ===&lt;br /&gt;
* [[Сортировка выбором]]&lt;br /&gt;
* [[Сортировка пузырьком]]&lt;br /&gt;
* [[Сортировка вставками]]&lt;br /&gt;
=== Сортировки на сравнениях ===&lt;br /&gt;
* [[Сортировка Шелла]]&amp;lt;tex&amp;gt;^\star&amp;lt;/tex&amp;gt;&lt;br /&gt;
* [[Сортировка кучей]]&lt;br /&gt;
* [[Быстрая сортировка]]&lt;br /&gt;
* [[Сортировка слиянием]]&lt;br /&gt;
* [[Cортировка слиянием с использованием O(1) дополнительной памяти]]&lt;br /&gt;
* [[Терпеливая сортировка]]&amp;lt;tex&amp;gt;^\star&amp;lt;/tex&amp;gt;&lt;br /&gt;
* [[Timsort]]&amp;lt;tex&amp;gt;^\star&amp;lt;/tex&amp;gt;&lt;br /&gt;
* [[Smoothsort]]&amp;lt;tex&amp;gt;^\star&amp;lt;/tex&amp;gt;&lt;br /&gt;
* [[Теорема о нижней оценке для сортировки сравнениями]]&lt;br /&gt;
&lt;br /&gt;
=== Многопоточные сортировки ===&lt;br /&gt;
* [[Многопоточная сортировка слиянием]]&amp;lt;tex&amp;gt;^\star&amp;lt;/tex&amp;gt;&lt;br /&gt;
* [[PSRS-сортировка]]&amp;lt;tex&amp;gt;^\star&amp;lt;/tex&amp;gt;&lt;br /&gt;
=== Другие сортировки ===&lt;br /&gt;
* [[Поиск k-ой порядковой статистики]]&lt;br /&gt;
* [[Поиск k-ой порядковой статистики за линейное время]]&lt;br /&gt;
* [[Поиск k-ой порядковой статистики в двух массивах]]&amp;lt;tex&amp;gt;^\star&amp;lt;/tex&amp;gt;&lt;br /&gt;
* [[Сортировка подсчетом]]&lt;br /&gt;
* [[Цифровая сортировка]]&lt;br /&gt;
* [[Карманная сортировка]]&lt;br /&gt;
* [[Сортировка Хана]]&amp;lt;tex&amp;gt;^\star&amp;lt;/tex&amp;gt;&lt;br /&gt;
* [[Задача флага Нидерландов]]&amp;lt;tex&amp;gt;^\star&amp;lt;/tex&amp;gt;&lt;br /&gt;
* [[Блинная сортировка]]&amp;lt;tex&amp;gt;^\star&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Сортирующие сети ==&lt;br /&gt;
* [[Сортирующие сети]]&lt;br /&gt;
* [[0-1 принцип | Проверка сети компараторов на то, что она сортирующая. 0-1 принцип]]&lt;br /&gt;
* [[Сортирующие сети для квадратичных сортировок]]&lt;br /&gt;
* [[Сортировочные сети с особыми свойствами]]&amp;lt;tex&amp;gt;^\star&amp;lt;/tex&amp;gt;&lt;br /&gt;
* [[Сеть Бетчера]]&lt;br /&gt;
&lt;br /&gt;
== Алгоритмы поиска ==&lt;br /&gt;
* [[Целочисленный двоичный поиск]]&lt;br /&gt;
* [[Поиск в матрице]]&amp;lt;tex&amp;gt;^\star&amp;lt;/tex&amp;gt;&lt;br /&gt;
* [[Вещественный двоичный поиск]]&lt;br /&gt;
* [[Троичный поиск]]&lt;br /&gt;
* [[Поиск с помощью золотого сечения]]&lt;br /&gt;
* [[Интерполяционный поиск]]&lt;br /&gt;
* [[Метод Фибоначчи]]&amp;lt;tex&amp;gt;^\star&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Связь между структурами данных ==&lt;br /&gt;
* [[Связь между структурами данных]]&lt;br /&gt;
&lt;br /&gt;
= Третий семестр =&lt;br /&gt;
&lt;br /&gt;
== Основные определения теории графов ==&lt;br /&gt;
* [[Основные определения теории графов|Основные определения: граф, ребро, вершина, степень, петля, путь, цикл]]&lt;br /&gt;
* [[Лемма о рукопожатиях]]&lt;br /&gt;
* [[Теорема о существовании простого пути в случае существования пути]]&lt;br /&gt;
* [[Теорема о существовании простого цикла в случае существования цикла]]&lt;br /&gt;
* [[Матрица смежности графа]]&lt;br /&gt;
* [[Матрица инцидентности графа]]&lt;br /&gt;
* [[Циклическое пространство графа]]&amp;lt;tex&amp;gt;^\star&amp;lt;/tex&amp;gt;&lt;br /&gt;
* [[Фундаментальные циклы графа]]&amp;lt;tex&amp;gt;^\star&amp;lt;/tex&amp;gt;&lt;br /&gt;
* [[Дерево, эквивалентные определения]]&lt;br /&gt;
* [[Алгоритмы на деревьях]]&amp;lt;tex&amp;gt;^\star&amp;lt;/tex&amp;gt;&lt;br /&gt;
* [[Дополнительный, самодополнительный граф]]&lt;br /&gt;
* [[Теоретико-множественные операции над графами]]&amp;lt;tex&amp;gt;^\star&amp;lt;/tex&amp;gt;&lt;br /&gt;
* [[Рёберное ядро]]&lt;br /&gt;
* [[Факторизация графов]]&amp;lt;tex&amp;gt;^\star&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Связность в графах ==&lt;br /&gt;
* [[Отношение связности, компоненты связности]]&lt;br /&gt;
* [[Отношение реберной двусвязности]]&lt;br /&gt;
* [[Отношение вершинной двусвязности]]&lt;br /&gt;
* [[Точка сочленения, эквивалентные определения]]&lt;br /&gt;
* [[Мост, эквивалентные определения]]&lt;br /&gt;
* [[Граф компонент реберной двусвязности]]&lt;br /&gt;
* [[Граф блоков-точек сочленения]]&lt;br /&gt;
* [[k-связность]]&lt;br /&gt;
* [[Теорема Менгера]]&lt;br /&gt;
* [[Теорема Менгера, альтернативное доказательство]]&lt;br /&gt;
* [[Вершинная, реберная связность, связь между ними и минимальной степенью вершины]]&lt;br /&gt;
&lt;br /&gt;
== Остовные деревья ==&lt;br /&gt;
=== Построение остовных деревьев ===&lt;br /&gt;
* [[Остовные деревья: определения, лемма о безопасном ребре]]&lt;br /&gt;
* [[Алгоритм Прима]]&lt;br /&gt;
* [[Алгоритм Краскала]]&lt;br /&gt;
* [[Алгоритм Борувки]]&lt;br /&gt;
* [[Критерий Тарьяна минимальности остовного дерева|Теорема Тарьяна (критерий минимальности остовного дерева)]]&lt;br /&gt;
* [[Алгоритм двух китайцев]]&lt;br /&gt;
&lt;br /&gt;
=== Свойства остовных деревьев ===&lt;br /&gt;
* [[Матрица Кирхгофа]]&lt;br /&gt;
* [[Связь матрицы Кирхгофа и матрицы инцидентности]]&lt;br /&gt;
* [[Подсчет числа остовных деревьев с помощью матрицы Кирхгофа]]&lt;br /&gt;
* [[Количество помеченных деревьев]]&lt;br /&gt;
* [[Коды Прюфера]]&lt;br /&gt;
&lt;br /&gt;
== Обходы графов ==&lt;br /&gt;
=== Эйлеровы графы ===&lt;br /&gt;
* [[Эйлеров цикл, Эйлеров путь, Эйлеровы графы, Эйлеровость орграфов]]&lt;br /&gt;
* [[Покрытие ребер графа путями]]&lt;br /&gt;
* [[Алгоритм построения Эйлерова цикла]]&lt;br /&gt;
* [[Произвольно вычерчиваемые из заданной вершины графы]]&lt;br /&gt;
=== Гамильтоновы графы ===&lt;br /&gt;
* [[Гамильтоновы графы]]&lt;br /&gt;
* [[Теорема Хватала]]&lt;br /&gt;
* [[Теорема Дирака]]&lt;br /&gt;
* [[Теорема Оре]]&lt;br /&gt;
* [[Теорема Поша]]&amp;lt;tex&amp;gt;^\star&amp;lt;/tex&amp;gt;&lt;br /&gt;
* [[Теорема Гуйя-Ури]]&amp;lt;tex&amp;gt;^\star&amp;lt;/tex&amp;gt;&lt;br /&gt;
* [[Алгоритм нахождения Гамильтонова цикла в условиях теорем Дирака и Оре]]&lt;br /&gt;
* [[Теорема Гринберга]]&amp;lt;tex&amp;gt;^\star&amp;lt;/tex&amp;gt;&lt;br /&gt;
* [[Турниры]]&lt;br /&gt;
* [[Теорема Редеи-Камиона]]&lt;br /&gt;
&lt;br /&gt;
== Укладки графов ==&lt;br /&gt;
* [[Укладка графа на плоскости]]&lt;br /&gt;
* [[Формула Эйлера]]&lt;br /&gt;
* [[Непланарность K5 и K3,3|Непланарность &amp;lt;tex&amp;gt;K_5&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;K_{3,3}&amp;lt;/tex&amp;gt;]]&lt;br /&gt;
* [[Укладка дерева]]&lt;br /&gt;
* [[Укладка графа с планарными компонентами реберной двусвязности]]&lt;br /&gt;
* [[Укладка графа с планарными компонентами вершинной двусвязности]]&lt;br /&gt;
* [[Теорема Понтрягина-Куратовского]]&lt;br /&gt;
* [[Род, толщина, крупность, число скрещиваний]]&amp;lt;tex&amp;gt;^\star&amp;lt;/tex&amp;gt;&lt;br /&gt;
* [[Двойственный граф планарного графа]]&lt;br /&gt;
* [[Теорема Фари]]&amp;lt;tex&amp;gt;^\star&amp;lt;/tex&amp;gt;&lt;br /&gt;
* [[Гамма-алгоритм]]&lt;br /&gt;
&lt;br /&gt;
== Раскраски графов ==&lt;br /&gt;
* [[Раскраска графа]]&lt;br /&gt;
* [[Двудольные графы и раскраска в 2 цвета]]&lt;br /&gt;
* [[Хроматический многочлен]]&lt;br /&gt;
* [[Формула Зыкова]]&lt;br /&gt;
* [[Формула Уитни]]&lt;br /&gt;
* [[Теорема Брукса]]&lt;br /&gt;
* [[Верхние и нижние оценки хроматического числа]]&amp;lt;tex&amp;gt;^\star&amp;lt;/tex&amp;gt;&lt;br /&gt;
* [[Хроматическое число планарного графа]]&lt;br /&gt;
* [[Многочлен Татта]]&amp;lt;tex&amp;gt;^\star&amp;lt;/tex&amp;gt;&lt;br /&gt;
* [[Теория Рамсея]]&amp;lt;tex&amp;gt;^\star&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Обход в глубину ==&lt;br /&gt;
* [[Обход в глубину, цвета вершин]]&lt;br /&gt;
* [[Лемма о белых путях]]&lt;br /&gt;
* [[Использование обхода в глубину для проверки связности]]&lt;br /&gt;
* [[Использование обхода в глубину для поиска цикла]]&lt;br /&gt;
* [[Использование обхода в глубину для топологической сортировки]]&lt;br /&gt;
* [[Использование обхода в глубину для поиска компонент сильной связности]]&lt;br /&gt;
* [[Использование обхода в глубину для поиска точек сочленения]]&lt;br /&gt;
* [[Построение компонент вершинной двусвязности]]&lt;br /&gt;
* [[Использование обхода в глубину для поиска мостов]]&lt;br /&gt;
* [[Построение компонент реберной двусвязности]]&lt;br /&gt;
&lt;br /&gt;
== Кратчайшие пути в графах ==&lt;br /&gt;
* [[Обход в ширину]]&lt;br /&gt;
* [[Алгоритм Форда-Беллмана]]&lt;br /&gt;
* [[Алгоритм Дейкстры]]&lt;br /&gt;
* [[Алгоритм Флойда]]&lt;br /&gt;
* [[Алгоритм Джонсона]]&lt;br /&gt;
* [[Алгоритм Левита]]&amp;lt;tex&amp;gt;^\star&amp;lt;/tex&amp;gt;&lt;br /&gt;
* [[Алгоритм A*]] &amp;lt;tex&amp;gt;^\star&amp;lt;/tex&amp;gt;&lt;br /&gt;
* [[Алгоритм D*]] &amp;lt;tex&amp;gt;^\star&amp;lt;/tex&amp;gt;&lt;br /&gt;
* [[Эвристики для поиска кратчайших путей]]&amp;lt;tex&amp;gt;^\star&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Задача о паросочетании ==&lt;br /&gt;
* [[Паросочетания: основные определения, теорема о максимальном паросочетании и дополняющих цепях]]&lt;br /&gt;
* [[Алгоритм Форда-Фалкерсона для поиска максимального паросочетания]]&lt;br /&gt;
* [[Алгоритм Куна для поиска максимального паросочетания]]&lt;br /&gt;
* [[Теорема Холла]]&lt;br /&gt;
* [[Связь максимального паросочетания и минимального вершинного покрытия в двудольных графах]]&lt;br /&gt;
* [[Связь вершинного покрытия и независимого множества]]&lt;br /&gt;
* [[Рёберное ядро]]&amp;lt;tex&amp;gt;^\star&amp;lt;/tex&amp;gt;&lt;br /&gt;
* [[Матрица Татта и связь с размером максимального паросочетания в двудольном графе]]&lt;br /&gt;
* [[Теорема Татта о существовании полного паросочетания]]&lt;br /&gt;
* [[Алгоритм вырезания соцветий|Паросочетания в недвудольных графах. Алгоритм вырезания соцветий]]&lt;br /&gt;
* [[Декомпозиция Эдмондса-Галлаи]]&lt;br /&gt;
* [[Задача об устойчивом паросочетании]]&amp;lt;tex&amp;gt;^\star&amp;lt;/tex&amp;gt;&lt;br /&gt;
* [[Совершенное паросочетание в кубическом графе]]&amp;lt;tex&amp;gt;^\star&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Задача о максимальном потоке ==&lt;br /&gt;
* [[Определение сети, потока]]&lt;br /&gt;
* [[Разрез, лемма о потоке через разрез]]&lt;br /&gt;
* [[Дополняющая сеть, дополняющий путь]]&lt;br /&gt;
* [[Сложение и разность потоков]]&lt;br /&gt;
* [[Теорема Форда-Фалкерсона]]&lt;br /&gt;
* [[Алгоритм Форда-Фалкерсона, реализация с помощью поиска в глубину]]&lt;br /&gt;
* [[Алоритм Эдмондса-Карпа]]&lt;br /&gt;
* [[Алгоритм масштабирования потока]]&lt;br /&gt;
* [[Блокирующий поток]]&lt;br /&gt;
* [[Схема алгоритма Диница]]&lt;br /&gt;
* [[Теоремы Карзанова о числе итераций алгоритма Диница в сети с целочисленными пропускными способностями]]&lt;br /&gt;
* [[Алгоритм Голдберга-Тарьяна]]&amp;lt;tex&amp;gt;^\star&amp;lt;/tex&amp;gt;&lt;br /&gt;
* [[Алгоритм поиска блокирующего потока в ациклической сети]]&lt;br /&gt;
* [[Метод проталкивания предпотока]]&lt;br /&gt;
* [[Алгоритм &amp;quot;поднять-в-начало&amp;quot;]]&lt;br /&gt;
* [[Теорема о декомпозиции]]&lt;br /&gt;
* [[Теорема о декомпозиционном барьере]]&lt;br /&gt;
* [[Циркуляция потока]]&lt;br /&gt;
* [[Алгоритм Каргера для нахождения минимального разреза]]&amp;lt;tex&amp;gt;^\star&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Задача о потоке минимальной стоимости ==&lt;br /&gt;
* [[Поток минимальной стоимости]]&lt;br /&gt;
* [[Теорема Форда-Фалкерсона о потоке минимальной стоимости]]&lt;br /&gt;
* [[Лемма об эквивалентности свойства потока быть минимальной стоимости и отсутствии отрицательных циклов в остаточной сети]]&lt;br /&gt;
* [[Поиск потока минимальной стоимости методом дополнения вдоль путей минимальной стоимости]]&lt;br /&gt;
* [[Использование потенциалов Джонсона при поиске потока минимальной стоимости]]&lt;br /&gt;
* [[Сведение задачи о назначениях к задаче о потоке минимальной стоимости]]&lt;br /&gt;
* [[Венгерский алгоритм решения задачи о назначениях]]&lt;br /&gt;
&lt;br /&gt;
= Четвертый семестр =&lt;br /&gt;
&lt;br /&gt;
== Основные определения. Простые комбинаторные свойства слов ==&lt;br /&gt;
* [[Основные определения, связанные со строками]]&lt;br /&gt;
* [[Период и бордер, их связь]]&lt;br /&gt;
* [[Слово Фибоначчи]]&lt;br /&gt;
* [[Слово Туэ-Морса]]&lt;br /&gt;
* [[Декомпозиция Линдона]]&amp;lt;tex&amp;gt;^\star&amp;lt;/tex&amp;gt;&lt;br /&gt;
* [[Алгоритм Ландау-Шмидта]]&amp;lt;tex&amp;gt;^\star&amp;lt;/tex&amp;gt;&lt;br /&gt;
* [[Алгоритм Крочемора]]&amp;lt;tex&amp;gt;^\star&amp;lt;/tex&amp;gt;&lt;br /&gt;
* [[Алгоритм Мейна-Лоренца]]&amp;lt;tex&amp;gt;^\star&amp;lt;/tex&amp;gt;&lt;br /&gt;
* [[Алгоритм Манакера]]&amp;lt;tex&amp;gt;^\star&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== [[Поиск подстроки в строке]] ==&lt;br /&gt;
=== Точный поиск ===&lt;br /&gt;
* [[Наивный алгоритм поиска подстроки в строке]]&lt;br /&gt;
* [[Поиск подстроки в строке с использованием хеширования. Алгоритм Рабина-Карпа]]&lt;br /&gt;
* [[Поиск наибольшей общей подстроки двух строк с использованием хеширования]]&lt;br /&gt;
* [[Префикс-функция]]&lt;br /&gt;
* [[Алгоритм Кнута-Морриса-Пратта]]&lt;br /&gt;
* [[Автомат Кнута-Морриса-Пратта]]&lt;br /&gt;
* [[Z-функция]]&lt;br /&gt;
* [[Бор]]&lt;br /&gt;
* [[Алгоритм Ахо-Корасик]]&lt;br /&gt;
* [[Алгоритм Бойера-Мура]]&lt;br /&gt;
* [[Алгоритм Апостолико-Крочемора]]&amp;lt;tex&amp;gt;^\star&amp;lt;/tex&amp;gt;&lt;br /&gt;
* [[Алгоритм Колусси]]&amp;lt;tex&amp;gt;^\star&amp;lt;/tex&amp;gt;&lt;br /&gt;
* [[Алгоритм Shift-And]]&amp;lt;tex&amp;gt;^\star&amp;lt;/tex&amp;gt;&lt;br /&gt;
* [[Двусторонний алгоритм]]&amp;lt;tex&amp;gt;^\star&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Нечёткий поиск ===&lt;br /&gt;
* [[Алгоритм Ландау-Вишкина (k несовпадений)]]&amp;lt;tex&amp;gt;^\star&amp;lt;/tex&amp;gt;&lt;br /&gt;
* [[Алгоритм Ландау-Вишкина (k различий)]]&amp;lt;tex&amp;gt;^\star&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Суффиксное дерево ==&lt;br /&gt;
* [[Суффиксный бор]]&lt;br /&gt;
* [[Сжатое суффиксное дерево]]&lt;br /&gt;
* [[Алгоритм Укконена]]&lt;br /&gt;
* [[Алгоритм МакКрейта]]&amp;lt;tex&amp;gt;^\star&amp;lt;/tex&amp;gt;&lt;br /&gt;
* [[Алгоритм Фарача]]&amp;lt;tex&amp;gt;^\star&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Суффиксный массив ==&lt;br /&gt;
* [[Суффиксный массив]]&lt;br /&gt;
* [[Построение суффиксного массива с помощью стандартных методов сортировки]]&lt;br /&gt;
* [[Алгоритм цифровой сортировки суффиксов циклической строки]]&lt;br /&gt;
* [[Алгоритм Касаи и др.]]&lt;br /&gt;
* [[Алгоритм Карккайнена-Сандерса]]&lt;br /&gt;
* [[Алгоритм поиска подстроки в строке с помощью суффиксного массива]]&lt;br /&gt;
&lt;br /&gt;
== Задача о наименьшем общем предке ==&lt;br /&gt;
* [[Сведение задачи LCA к задаче RMQ]]&lt;br /&gt;
* [[Сведение задачи RMQ к задаче LCA]]&lt;br /&gt;
* [[Метод двоичного подъема]]&lt;br /&gt;
* [[Решение RMQ с помощью разреженной таблицы]]&lt;br /&gt;
* [[Алгоритм Фарака-Колтона и Бендера]] (решение +/-1 RMQ с помощью метода четырех русских)&lt;br /&gt;
* [[Алгоритм Хьюи]]&lt;br /&gt;
* [[Heavy-light декомпозиция]]&lt;br /&gt;
* [[Алгоритм Шибера-Вишкина]]&amp;lt;tex&amp;gt;^\star&amp;lt;/tex&amp;gt;&lt;br /&gt;
* [[Алгоритм Тарьяна поиска LCA за O(1) в оффлайн]]&amp;lt;tex&amp;gt;^\star&amp;lt;/tex&amp;gt;&lt;br /&gt;
* [[Link-Cut Tree]]&amp;lt;tex&amp;gt;^\star&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Матроиды ==&lt;br /&gt;
=== Основные факты теории матроидов ===&lt;br /&gt;
* [[Определение матроида]]&lt;br /&gt;
* [[Примеры матроидов]]&lt;br /&gt;
* [[Прямая сумма матроидов]]&lt;br /&gt;
* [[Теорема Радо-Эдмондса (жадный алгоритм)]]&lt;br /&gt;
* [[Теорема о базах]]&lt;br /&gt;
* [[Аксиоматизация матроида базами]]&lt;br /&gt;
* [[Теорема о циклах]]&lt;br /&gt;
* [[Аксиоматизация матроида циклами]]&lt;br /&gt;
* [[Ранговая функция, полумодулярность]]&lt;br /&gt;
* [[Аксиоматизация матроида рангами]]&lt;br /&gt;
* [[Двойственный матроид]]&lt;br /&gt;
* [[Оператор замыкания для матроидов]]&lt;br /&gt;
* [[Покрытия, закрытые множества]]&lt;br /&gt;
* [[Матроид Вамоса]]&amp;lt;tex&amp;gt;^\star&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Пересечение матроидов ===&lt;br /&gt;
* [[Пересечение матроидов, определение, примеры]]&lt;br /&gt;
* [[Лемма о паросочетании в графе замен]]&lt;br /&gt;
* [[Лемма о единственном паросочетании в графе замен]]&lt;br /&gt;
* [[Граф замен для двух матроидов]]&lt;br /&gt;
* [[Лемма о единственном паросочетании в подграфе замен, индуцированном кратчайшим путем]]&lt;br /&gt;
* [[Алгоритм построения базы в пересечении матроидов]]&lt;br /&gt;
&lt;br /&gt;
=== Объединение матроидов ===&lt;br /&gt;
* [[Объединение матроидов, проверка множества на независимость]]&lt;br /&gt;
* [[Объединение матроидов, доказательство того, что объединение является матроидом]]&lt;br /&gt;
* [[Алгоритм построения базы в объединении матроидов]]&lt;br /&gt;
&lt;br /&gt;
== Теория расписаний ==&lt;br /&gt;
* [[Классификация задач]]&lt;br /&gt;
* [[Методы решения задач теории расписаний]]&lt;br /&gt;
* [[Правило Лаулера]]&lt;br /&gt;
* [[Flow shop]]&lt;br /&gt;
* [[P1sumu|&amp;lt;tex&amp;gt;1 \mid \mid \sum U_{i}&amp;lt;/tex&amp;gt;]]&lt;br /&gt;
* [[1ripi1sumwc|&amp;lt;tex&amp;gt;1 \mid r_{i}, p_i=1\mid \sum w_{i}C_{i}&amp;lt;/tex&amp;gt;]]&lt;br /&gt;
* [[1ridipi1|&amp;lt;tex&amp;gt;1 \mid r_{i}, d_{i}, p_{i} = 1 \mid -&amp;lt;/tex&amp;gt;]]&lt;br /&gt;
* [[1ripipsumwu|&amp;lt;tex&amp;gt; 1 \mid r_i,p_i=p \mid \sum w_i U_i&amp;lt;/tex&amp;gt;]]&lt;br /&gt;
* [[1outtreesumwc | &amp;lt;tex&amp;gt;1 \mid outtree \mid \sum w_i C_i&amp;lt;/tex&amp;gt;]]&lt;br /&gt;
* [[1pi1sumwu|&amp;lt;tex&amp;gt;1 \mid p_{i} = 1 \mid \sum w_{i}U_{i}&amp;lt;/tex&amp;gt;]]&lt;br /&gt;
* [[1precpmtnrifmax|&amp;lt;tex&amp;gt;1 \mid prec, pmtn, r_i \mid f_{\max}&amp;lt;/tex&amp;gt;]]&lt;br /&gt;
* [[1precripi1Lmax|&amp;lt;tex&amp;gt;1 \mid prec; r_i; p_i = 1 \mid L_{max}&amp;lt;/tex&amp;gt;]]&lt;br /&gt;
* [[P2precpi1Lmax|&amp;lt;tex&amp;gt;P2 \mid prec, p_i = 1 \mid L_{\max}&amp;lt;/tex&amp;gt;]]&lt;br /&gt;
* [[PpmtnriLmax|&amp;lt;tex&amp;gt;P \mid pmtn, r_i \mid L_{max}&amp;lt;/tex&amp;gt;]]&lt;br /&gt;
* [[QpmtnCmax|&amp;lt;tex&amp;gt;Q \mid pmtn \mid C_{max}&amp;lt;/tex&amp;gt;]]&lt;br /&gt;
* [[QpmtnriLmax|&amp;lt;tex&amp;gt;Q \mid pmtn, r_{i} \mid L_{max}&amp;lt;/tex&amp;gt;]]&lt;br /&gt;
* [[QSumCi|&amp;lt;tex&amp;gt;Q\mid\mid\sum{C_i}&amp;lt;/tex&amp;gt;]]&lt;br /&gt;
* [[R2Cmax|&amp;lt;tex&amp;gt;R2 \mid \mid C_{max}&amp;lt;/tex&amp;gt;]]&lt;br /&gt;
* [[F2Cmax|&amp;lt;tex&amp;gt;F2 \mid \mid C_{max}&amp;lt;/tex&amp;gt;]]&lt;br /&gt;
* [[Fpij1sumwu|&amp;lt;tex&amp;gt;F \mid p_{ij} = 1 \mid \sum w_i U_i&amp;lt;/tex&amp;gt;]]&lt;br /&gt;
* [[O2Cmax|&amp;lt;tex&amp;gt;O2 \mid \mid C_{max}&amp;lt;/tex&amp;gt;]]&lt;br /&gt;
* [[Opi1sumu|&amp;lt;tex&amp;gt;O \mid p_{ij} = 1 \mid \sum U_i&amp;lt;/tex&amp;gt;]]&lt;br /&gt;
* [[J2ni2Cmax|&amp;lt;tex&amp;gt;J2 \mid n_{i} \le 2 \mid C_{max}&amp;lt;/tex&amp;gt;]]&lt;br /&gt;
* [[J2pij1Lmax| &amp;lt;tex&amp;gt;J2\mid p_{ij} = 1\mid L_{max}&amp;lt;/tex&amp;gt;]]&lt;/div&gt;</summary>
		<author><name>Ильнар</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%94%D0%B2%D0%BE%D0%B8%D1%87%D0%BD%D0%B0%D1%8F_%D0%BA%D1%83%D1%87%D0%B0&amp;diff=47702</id>
		<title>Двоичная куча</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%94%D0%B2%D0%BE%D0%B8%D1%87%D0%BD%D0%B0%D1%8F_%D0%BA%D1%83%D1%87%D0%B0&amp;diff=47702"/>
				<updated>2015-06-05T20:36:40Z</updated>
		
		<summary type="html">&lt;p&gt;Ильнар: /* Поиск k-ого элемента */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Определение==&lt;br /&gt;
{{Определение&lt;br /&gt;
|definition=&lt;br /&gt;
'''Двоичная куча''' или '''пирамида''' (англ. ''Binary heap'') — такое двоичное [[Дерево, эквивалентные определения|подвешенное дерево]], для которого выполнены следующие три условия:&lt;br /&gt;
&lt;br /&gt;
* Значение в любой вершине не меньше, (если куча для максимума), чем значения её потомков.&lt;br /&gt;
* На &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt;-ом слое &amp;lt;tex&amp;gt;2^i&amp;lt;/tex&amp;gt; вершин, кроме последнего. Слои нумеруются с нуля.&lt;br /&gt;
* Последний слой заполнен слева направо (как показано на рисунке)&lt;br /&gt;
}}&lt;br /&gt;
[[Файл:Min_heap.png‎|thumb|325px|Пример кучи для минимума]]&lt;br /&gt;
[[Файл:Min_heap_array.png‎|thumb|325px|Хранение кучи в массиве, красная стрелка {{---}} левый сын, зеленая {{---}} правый]]&lt;br /&gt;
Удобнее всего двоичную кучу хранить в виде массива &amp;lt;tex&amp;gt;a[0..n-1]&amp;lt;/tex&amp;gt;, у которого нулевой элемент, &amp;lt;tex&amp;gt;a[0]&amp;lt;/tex&amp;gt; — элемент в корне, а потомками элемента &amp;lt;tex&amp;gt;a[i]&amp;lt;/tex&amp;gt; являются &amp;lt;tex&amp;gt;a[2i+1]&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;a[2i+2]&amp;lt;/tex&amp;gt;. Высота кучи определяется как высота двоичного дерева. То есть она равна количеству рёбер в самом длинном простом пути, соединяющем корень кучи с одним из её листьев. Высота кучи есть &amp;lt;tex&amp;gt;O(\log{n})&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt; — количество узлов дерева.&lt;br /&gt;
&lt;br /&gt;
Чаще всего используют кучи для минимума (когда предок не больше детей) и для максимума (когда предок не меньше детей).&lt;br /&gt;
&lt;br /&gt;
Двоичные кучи используют, например, для того, чтобы извлекать минимум из набора чисел за &amp;lt;tex&amp;gt;O(\log{n})&amp;lt;/tex&amp;gt;. Они являются частным случаем приоритетных очередей.&lt;br /&gt;
&lt;br /&gt;
==Базовые процедуры==&lt;br /&gt;
&lt;br /&gt;
===Восстановление свойств кучи===&lt;br /&gt;
&lt;br /&gt;
Если в куче изменяется один из элементов, то она может перестать удовлетворять свойству упорядоченности. Для восстановления этого свойства служат процедуры &amp;lt;tex&amp;gt; \mathrm {siftDown} &amp;lt;/tex&amp;gt; (просеивание вниз)&lt;br /&gt;
и &amp;lt;tex&amp;gt; \mathrm {siftUp} &amp;lt;/tex&amp;gt; (просеивание вверх). &lt;br /&gt;
Если значение измененного элемента увеличивается, то свойства кучи восстанавливаются функцией &amp;lt;tex&amp;gt; \mathrm {siftDown} &amp;lt;/tex&amp;gt;.&lt;br /&gt;
Работа процедуры: если &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt;-й элемент меньше, чем его сыновья, всё поддерево уже является кучей, и делать ничего не надо. В противном случае меняем местами &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt;-й элемент с наименьшим из его сыновей, после чего выполняем &amp;lt;tex&amp;gt; \mathrm {siftDown} &amp;lt;/tex&amp;gt; для этого сына.&lt;br /&gt;
Процедура выполняется за время &amp;lt;tex&amp;gt;O(\log{n})&amp;lt;/tex&amp;gt;.&lt;br /&gt;
====siftDown====&lt;br /&gt;
&amp;lt;code style=&amp;quot;display:inline-block&amp;quot;&amp;gt;&lt;br /&gt;
 '''function''' siftDown(i : '''int'''):&lt;br /&gt;
     '''while''' 2 * i + 1 &amp;lt;tex&amp;gt;&amp;lt;&amp;lt;/tex&amp;gt; a.heapSize     &amp;lt;font color = &amp;quot;green&amp;quot;&amp;gt;// heapSize {{---}} количество элементов в куче&amp;lt;/font&amp;gt;&lt;br /&gt;
         left = 2 * i + 1             &amp;lt;font color = &amp;quot;green&amp;quot;&amp;gt;// left {{---}} левый сын&amp;lt;/font&amp;gt;&lt;br /&gt;
         right = 2 * i + 2            &amp;lt;font color = &amp;quot;green&amp;quot;&amp;gt;// right {{---}} правый сын&amp;lt;/font&amp;gt;&lt;br /&gt;
         j = left&lt;br /&gt;
         '''if''' right &amp;lt;tex&amp;gt;&amp;lt;&amp;lt;/tex&amp;gt; a.heapSize '''and''' a[right] &amp;lt;tex&amp;gt;&amp;lt;&amp;lt;/tex&amp;gt; A[left]&lt;br /&gt;
             j = right&lt;br /&gt;
         '''if''' a[i] &amp;lt;tex&amp;gt;\leqslant&amp;lt;/tex&amp;gt; a[j]&lt;br /&gt;
             '''break'''&lt;br /&gt;
         swap(a[i], a[j])&lt;br /&gt;
         i = j&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====siftUp====&lt;br /&gt;
Если значение измененного элемента уменьшается, то свойства кучи восстанавливаются функцией &amp;lt;tex&amp;gt; \mathrm {siftUp} &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Работа процедуры: если элемент больше своего отца, условие 1 соблюдено для всего дерева, и больше ничего делать не нужно. Иначе, мы меняем местами его с отцом. После чего выполняем &amp;lt;tex&amp;gt; \mathrm {siftUp} &amp;lt;/tex&amp;gt;&lt;br /&gt;
для этого отца. Иными словами, слишком маленький элемент всплывает наверх.&lt;br /&gt;
Процедура выполняется за время &amp;lt;tex&amp;gt;O(\log{n})&amp;lt;/tex&amp;gt;. &lt;br /&gt;
&amp;lt;code style=&amp;quot;display:inline-block&amp;quot;&amp;gt;&lt;br /&gt;
 '''function''' siftUp(i : '''int'''):&lt;br /&gt;
     '''while''' a[i] &amp;lt;tex&amp;gt;&amp;lt;&amp;lt;/tex&amp;gt; a[(i - 1) / 2]     &amp;lt;font color = &amp;quot;green&amp;quot;&amp;gt;// i &amp;lt;tex&amp;gt;==&amp;lt;/tex&amp;gt; 0 {{---}} мы в корне&amp;lt;/font&amp;gt;&lt;br /&gt;
         swap(a[i], a[(i - 1) / 2])&lt;br /&gt;
         i = (i - 1) / 2&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Извлечение минимального элемента===&lt;br /&gt;
&lt;br /&gt;
Выполняет извлечение минимального элемента из кучи за время &amp;lt;tex&amp;gt;O(\log{n})&amp;lt;/tex&amp;gt;.&lt;br /&gt;
Извлечение выполняется в четыре этапа:&lt;br /&gt;
# Значение корневого элемента (он и является минимальным) сохраняется для последующего возврата.&lt;br /&gt;
# Последний элемент копируется в корень, после чего удаляется из кучи.&lt;br /&gt;
# Вызывается &amp;lt;math&amp;gt; \mathrm {siftDown} &amp;lt;/math&amp;gt; для корня.&lt;br /&gt;
# Сохранённый элемент возвращается.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code style=&amp;quot;display:inline-block&amp;quot;&amp;gt;&lt;br /&gt;
 '''int''' extractMin():&lt;br /&gt;
     '''int''' min = a[0]&lt;br /&gt;
     a[0] = a[a.heapSize - 1]&lt;br /&gt;
     a.heapSize = a.heapSize - 1&lt;br /&gt;
     siftDown(0)&lt;br /&gt;
     '''return''' min&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Добавление нового элемента===&lt;br /&gt;
&lt;br /&gt;
Выполняет добавление элемента в кучу за время &amp;lt;tex&amp;gt;O(\log{n})&amp;lt;/tex&amp;gt;.&lt;br /&gt;
Добавление произвольного элемента в конец кучи, и восстановление свойства упорядоченности с помощью процедуры &amp;lt;math&amp;gt; \mathrm {siftUp} &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code style=&amp;quot;display:inline-block&amp;quot;&amp;gt;&lt;br /&gt;
 '''function''' insert(key : '''int'''):&lt;br /&gt;
     a.heapSize = a.heapSize + 1&lt;br /&gt;
     a[a.heapSize - 1] = key&lt;br /&gt;
     siftUp(a.heapSize - 1)&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Построение кучи за O(n) ===&lt;br /&gt;
{{Определение | definition =&lt;br /&gt;
'''&amp;lt;tex&amp;gt;D&amp;lt;/tex&amp;gt;-куча''' {{---}} это куча, в которой у каждого элемента, кроме, возможно, элементов на последнем уровне, ровно &amp;lt;tex&amp;gt;d&amp;lt;/tex&amp;gt; потомков. &lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Дан массив &amp;lt;tex&amp;gt;a[0.. n - 1].&amp;lt;/tex&amp;gt; Требуется построить &amp;lt;tex&amp;gt;d&amp;lt;/tex&amp;gt;-кучу с минимумом в корне. Наиболее очевидный способ построить такую кучу из неупорядоченного массива {{---}} сделать нулевой элемент массива корнем, а дальше по очереди добавить все его элементы в конец кучи и запускать от каждого добавленного элемента &amp;lt;math&amp;gt;\mathrm {siftUp}&amp;lt;/math&amp;gt;. Временная оценка такого алгоритма &amp;lt;tex&amp;gt; O(n\log{n})&amp;lt;/tex&amp;gt;. Однако можно построить кучу еще быстрее — за &amp;lt;tex&amp;gt; O(n) &amp;lt;/tex&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Представим, что в массиве хранится дерево (&amp;lt;tex&amp;gt;a[0] - &amp;lt;/tex&amp;gt;  корень, а потомками элемента &amp;lt;tex&amp;gt;a[i]&amp;lt;/tex&amp;gt; являются &amp;lt;tex&amp;gt;a[2i+1]...a[2i+d]&amp;lt;/tex&amp;gt;). Сделаем &amp;lt;tex&amp;gt; \mathrm {siftDown} &amp;lt;/tex&amp;gt; для вершин, имеющих хотя бы одного потомка: от &amp;lt;tex dpi=140&amp;gt;\dfrac{n}{d}&amp;lt;/tex&amp;gt; до &amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;,{{---}} так как поддеревья, состоящие из одной вершины без потомков, уже упорядочены.&lt;br /&gt;
{{Лемма&lt;br /&gt;
|statement= На выходе получим искомую кучу. &lt;br /&gt;
|proof= При вызове &amp;lt;tex&amp;gt; \mathrm {siftDown} &amp;lt;/tex&amp;gt; для вершины, ее поддеревья являются кучами. После выполнения &amp;lt;tex&amp;gt; \mathrm {siftDown} &amp;lt;/tex&amp;gt; эта вершина с ее поддеревьями будут также являться кучей.  Значит, после выполнения всех &amp;lt;tex&amp;gt; \mathrm {siftDown} &amp;lt;/tex&amp;gt; получится куча.&lt;br /&gt;
}}&lt;br /&gt;
{{Лемма&lt;br /&gt;
|statement= Время работы этого алгоритма &amp;lt;tex&amp;gt; O(n) &amp;lt;/tex&amp;gt;.&lt;br /&gt;
|proof= Число вершин на высоте &amp;lt;tex&amp;gt;h&amp;lt;/tex&amp;gt; в куче из &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt; элементов не превосходит &amp;lt;tex dpi = &amp;quot;160&amp;quot;&amp;gt;  \left \lceil \frac{n}{d^h} \right \rceil &amp;lt;/tex&amp;gt;.  Высота кучи не превосходит &amp;lt;tex&amp;gt; \log_{d}n &amp;lt;/tex&amp;gt;. Обозначим за &amp;lt;tex&amp;gt; H &amp;lt;/tex&amp;gt; высоту дерева, тогда время построения не превосходит&lt;br /&gt;
 &lt;br /&gt;
&amp;lt;tex dpi = &amp;quot;160&amp;quot;&amp;gt; \sum_{h = 1}^H  \limits\frac{n}{d^h} \cdot d &amp;lt;/tex&amp;gt; &amp;lt;tex dpi = &amp;quot;150&amp;quot;&amp;gt;  \cdot  h &amp;lt;/tex&amp;gt; &amp;lt;tex  dpi = &amp;quot;160&amp;quot;&amp;gt; = n \cdot d \cdot {\sum_{h = 1}^H  \limits}\frac{h}{d^h}. &amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Докажем вспомогательную лемму о сумме ряда.&lt;br /&gt;
&lt;br /&gt;
{{Лемма&lt;br /&gt;
|statement= &amp;lt;tex dpi = &amp;quot;160&amp;quot;&amp;gt; {\sum_{h = 1}^\infty  \limits}\frac{h}{d^h} = \frac{d}{(d - 1)^2} . &amp;lt;/tex&amp;gt; &lt;br /&gt;
|proof=&lt;br /&gt;
 Обозначим за &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; сумму ряда. Заметим, что&lt;br /&gt;
&amp;lt;tex dpi = &amp;quot;160&amp;quot;&amp;gt; \frac{n}{d^n} = \frac{1}{d} \cdot \frac{n - 1}{d ^{n - 1}} + \frac{1}{d^n}. &amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex dpi = &amp;quot;160&amp;quot;&amp;gt;{\sum_{n = 1}^\infty  \limits}\frac{1}{d^n}&amp;lt;/tex&amp;gt; {{---}} это сумма бесконечной убывающей геометрической прогрессии, и она равна &amp;lt;tex dpi = &amp;quot;160&amp;quot;&amp;gt; &lt;br /&gt;
\frac{\frac{1}{d}}{1 - \frac{1}{d}} = \frac{1}{d - 1}. &amp;lt;/tex&amp;gt; &lt;br /&gt;
&lt;br /&gt;
Получаем  &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; &amp;lt;tex dpi = &amp;quot;160&amp;quot; &amp;gt;=\frac{1}{d}&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;\cdot s +&amp;lt;/tex&amp;gt;  &amp;lt;tex dpi = &amp;quot;160&amp;quot; &amp;gt; \frac{1}{d - 1}. &amp;lt;/tex&amp;gt; Откуда &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; &amp;lt;tex dpi = &amp;quot;160&amp;quot;&amp;gt;  = \frac{d}{(d - 1)^2}. &amp;lt;/tex&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Подставляя в нашу формулу результат леммы, получаем &amp;lt;tex &amp;gt;n&amp;lt;/tex&amp;gt; &amp;lt;tex dpi = &amp;quot;160&amp;quot;&amp;gt;\cdot (\frac {d}{d - 1})^2 &amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;  \leqslant  4 \cdot n &amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;=O(n).&amp;lt;/tex&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Псевдокод алгоритма:&lt;br /&gt;
&amp;lt;code style=&amp;quot;display:inline-block&amp;quot;&amp;gt;&lt;br /&gt;
 '''function''' heapify():&lt;br /&gt;
     '''for''' i = a.heapSize / 2 '''downto''' 0&lt;br /&gt;
         siftDown(i)&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Слияние двух куч===&lt;br /&gt;
Даны две кучи &amp;lt;tex&amp;gt;a&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt;, размерами &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt;, требуется объединить эти две кучи. &lt;br /&gt;
====Наивная реализация====&lt;br /&gt;
Поочередно добавим все элементы из &amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt; в &amp;lt;tex&amp;gt;a&amp;lt;/tex&amp;gt;. Время работы {{---}} &amp;lt;tex&amp;gt;O(m \log(n+m))&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&amp;lt;code style=&amp;quot;display:inline-block&amp;quot;&amp;gt;&lt;br /&gt;
 '''function''' merge(a, b : '''Heap'''):&lt;br /&gt;
     '''while''' b.heapSize &amp;lt;tex&amp;gt;\neq&amp;lt;/tex&amp;gt; 0  &lt;br /&gt;
         a.insert(b.extractMin())&lt;br /&gt;
&amp;lt;/code&amp;gt; &lt;br /&gt;
====Реализация с помощью построения кучи====&lt;br /&gt;
Добавим все элементы кучи &amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt; в конец массива &amp;lt;tex&amp;gt;a&amp;lt;/tex&amp;gt;, после чего вызовем функцию построения кучи. Процедура выполняется за время &amp;lt;tex&amp;gt;O(n + m)&amp;lt;/tex&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code style=&amp;quot;display:inline-block&amp;quot;&amp;gt;&lt;br /&gt;
 '''function''' merge(a, b : '''Heap'''):&lt;br /&gt;
     '''for''' i = 0 '''to''' b.heapSize - 1  &lt;br /&gt;
         a.heapSize = a.heapSize + 1&lt;br /&gt;
         a[a.heapSize - 1] = b[i]&lt;br /&gt;
     a.heapify()&lt;br /&gt;
&amp;lt;/code&amp;gt; &lt;br /&gt;
&lt;br /&gt;
===Поиск k-ого элемента===&lt;br /&gt;
Требуется найти &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt;-ый по величине элемент в куче.&lt;br /&gt;
&lt;br /&gt;
# Создаем новую кучу, в которой будем хранить пару &amp;lt;tex&amp;gt;\langle \mathtt{value}, \mathtt{index} \rangle&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;\mathtt{value}&amp;lt;/tex&amp;gt; {{---}} значение элемента, а &amp;lt;tex&amp;gt;\mathtt{index}&amp;lt;/tex&amp;gt; {{---}} индекс элемента в основном массиве, и добавляем в нее корень кучи. &lt;br /&gt;
# Возьмем корень новой кучи и добавим её детей из основной кучи, после чего удалим корень. Проделаем этот шаг &amp;lt;tex&amp;gt;k - 1&amp;lt;/tex&amp;gt; раз.&lt;br /&gt;
# В корне новой кучи будет находиться ответ.&lt;br /&gt;
&lt;br /&gt;
Время работы алгоритма {{---}} &amp;lt;tex&amp;gt;O(k \log k)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
При &amp;lt;tex&amp;gt;n \lnapprox k \ log k&amp;lt;/tex&amp;gt; выгоднее запускать [[поиск k-ой порядковой статистики]].&lt;br /&gt;
[[Файл:Min_heap_kth.png‎|thumb|center|650px|Пример при &amp;lt;tex&amp;gt;k = 5&amp;lt;/tex&amp;gt;, красные {{---}} уже удаленные из кучи элементы, зеленые находятся в куче, а голубые {{---}} еще не рассмотрены.]]&lt;br /&gt;
&lt;br /&gt;
== См. также ==&lt;br /&gt;
* [[Биномиальная куча]]&lt;br /&gt;
* [[Фибоначчиева куча]]&lt;br /&gt;
* [[Левосторонняя куча]]&lt;br /&gt;
&lt;br /&gt;
== Источники информации ==&lt;br /&gt;
* [[wikipedia:ru:Двоичная куча|Википедия {{---}} Двоичная куча]]&lt;br /&gt;
* [[wikipedia:ru:Очередь с приоритетом|Википедия {{---}} Очередь с приоритетом]]&lt;br /&gt;
* [[wikipedia:en:Binary heap|Wikipedia {{---}} Binary heap]]&lt;br /&gt;
* [[wikipedia:en:Priority queue|Wikipedia {{---}} Priority queue]]&lt;br /&gt;
&lt;br /&gt;
[[Категория: Дискретная математика и алгоритмы]]&lt;br /&gt;
[[Категория: Приоритетные очереди]]&lt;br /&gt;
[[Категория: Структуры данных]]&lt;/div&gt;</summary>
		<author><name>Ильнар</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%94%D0%B2%D0%BE%D0%B8%D1%87%D0%BD%D0%B0%D1%8F_%D0%BA%D1%83%D1%87%D0%B0&amp;diff=47701</id>
		<title>Двоичная куча</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%94%D0%B2%D0%BE%D0%B8%D1%87%D0%BD%D0%B0%D1%8F_%D0%BA%D1%83%D1%87%D0%B0&amp;diff=47701"/>
				<updated>2015-06-05T20:34:32Z</updated>
		
		<summary type="html">&lt;p&gt;Ильнар: /* Поиск k-ого элемента */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Определение==&lt;br /&gt;
{{Определение&lt;br /&gt;
|definition=&lt;br /&gt;
'''Двоичная куча''' или '''пирамида''' (англ. ''Binary heap'') — такое двоичное [[Дерево, эквивалентные определения|подвешенное дерево]], для которого выполнены следующие три условия:&lt;br /&gt;
&lt;br /&gt;
* Значение в любой вершине не меньше, (если куча для максимума), чем значения её потомков.&lt;br /&gt;
* На &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt;-ом слое &amp;lt;tex&amp;gt;2^i&amp;lt;/tex&amp;gt; вершин, кроме последнего. Слои нумеруются с нуля.&lt;br /&gt;
* Последний слой заполнен слева направо (как показано на рисунке)&lt;br /&gt;
}}&lt;br /&gt;
[[Файл:Min_heap.png‎|thumb|325px|Пример кучи для минимума]]&lt;br /&gt;
[[Файл:Min_heap_array.png‎|thumb|325px|Хранение кучи в массиве, красная стрелка {{---}} левый сын, зеленая {{---}} правый]]&lt;br /&gt;
Удобнее всего двоичную кучу хранить в виде массива &amp;lt;tex&amp;gt;a[0..n-1]&amp;lt;/tex&amp;gt;, у которого нулевой элемент, &amp;lt;tex&amp;gt;a[0]&amp;lt;/tex&amp;gt; — элемент в корне, а потомками элемента &amp;lt;tex&amp;gt;a[i]&amp;lt;/tex&amp;gt; являются &amp;lt;tex&amp;gt;a[2i+1]&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;a[2i+2]&amp;lt;/tex&amp;gt;. Высота кучи определяется как высота двоичного дерева. То есть она равна количеству рёбер в самом длинном простом пути, соединяющем корень кучи с одним из её листьев. Высота кучи есть &amp;lt;tex&amp;gt;O(\log{n})&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt; — количество узлов дерева.&lt;br /&gt;
&lt;br /&gt;
Чаще всего используют кучи для минимума (когда предок не больше детей) и для максимума (когда предок не меньше детей).&lt;br /&gt;
&lt;br /&gt;
Двоичные кучи используют, например, для того, чтобы извлекать минимум из набора чисел за &amp;lt;tex&amp;gt;O(\log{n})&amp;lt;/tex&amp;gt;. Они являются частным случаем приоритетных очередей.&lt;br /&gt;
&lt;br /&gt;
==Базовые процедуры==&lt;br /&gt;
&lt;br /&gt;
===Восстановление свойств кучи===&lt;br /&gt;
&lt;br /&gt;
Если в куче изменяется один из элементов, то она может перестать удовлетворять свойству упорядоченности. Для восстановления этого свойства служат процедуры &amp;lt;tex&amp;gt; \mathrm {siftDown} &amp;lt;/tex&amp;gt; (просеивание вниз)&lt;br /&gt;
и &amp;lt;tex&amp;gt; \mathrm {siftUp} &amp;lt;/tex&amp;gt; (просеивание вверх). &lt;br /&gt;
Если значение измененного элемента увеличивается, то свойства кучи восстанавливаются функцией &amp;lt;tex&amp;gt; \mathrm {siftDown} &amp;lt;/tex&amp;gt;.&lt;br /&gt;
Работа процедуры: если &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt;-й элемент меньше, чем его сыновья, всё поддерево уже является кучей, и делать ничего не надо. В противном случае меняем местами &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt;-й элемент с наименьшим из его сыновей, после чего выполняем &amp;lt;tex&amp;gt; \mathrm {siftDown} &amp;lt;/tex&amp;gt; для этого сына.&lt;br /&gt;
Процедура выполняется за время &amp;lt;tex&amp;gt;O(\log{n})&amp;lt;/tex&amp;gt;.&lt;br /&gt;
====siftDown====&lt;br /&gt;
&amp;lt;code style=&amp;quot;display:inline-block&amp;quot;&amp;gt;&lt;br /&gt;
 '''function''' siftDown(i : '''int'''):&lt;br /&gt;
     '''while''' 2 * i + 1 &amp;lt;tex&amp;gt;&amp;lt;&amp;lt;/tex&amp;gt; a.heapSize     &amp;lt;font color = &amp;quot;green&amp;quot;&amp;gt;// heapSize {{---}} количество элементов в куче&amp;lt;/font&amp;gt;&lt;br /&gt;
         left = 2 * i + 1             &amp;lt;font color = &amp;quot;green&amp;quot;&amp;gt;// left {{---}} левый сын&amp;lt;/font&amp;gt;&lt;br /&gt;
         right = 2 * i + 2            &amp;lt;font color = &amp;quot;green&amp;quot;&amp;gt;// right {{---}} правый сын&amp;lt;/font&amp;gt;&lt;br /&gt;
         j = left&lt;br /&gt;
         '''if''' right &amp;lt;tex&amp;gt;&amp;lt;&amp;lt;/tex&amp;gt; a.heapSize '''and''' a[right] &amp;lt;tex&amp;gt;&amp;lt;&amp;lt;/tex&amp;gt; A[left]&lt;br /&gt;
             j = right&lt;br /&gt;
         '''if''' a[i] &amp;lt;tex&amp;gt;\leqslant&amp;lt;/tex&amp;gt; a[j]&lt;br /&gt;
             '''break'''&lt;br /&gt;
         swap(a[i], a[j])&lt;br /&gt;
         i = j&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====siftUp====&lt;br /&gt;
Если значение измененного элемента уменьшается, то свойства кучи восстанавливаются функцией &amp;lt;tex&amp;gt; \mathrm {siftUp} &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Работа процедуры: если элемент больше своего отца, условие 1 соблюдено для всего дерева, и больше ничего делать не нужно. Иначе, мы меняем местами его с отцом. После чего выполняем &amp;lt;tex&amp;gt; \mathrm {siftUp} &amp;lt;/tex&amp;gt;&lt;br /&gt;
для этого отца. Иными словами, слишком маленький элемент всплывает наверх.&lt;br /&gt;
Процедура выполняется за время &amp;lt;tex&amp;gt;O(\log{n})&amp;lt;/tex&amp;gt;. &lt;br /&gt;
&amp;lt;code style=&amp;quot;display:inline-block&amp;quot;&amp;gt;&lt;br /&gt;
 '''function''' siftUp(i : '''int'''):&lt;br /&gt;
     '''while''' a[i] &amp;lt;tex&amp;gt;&amp;lt;&amp;lt;/tex&amp;gt; a[(i - 1) / 2]     &amp;lt;font color = &amp;quot;green&amp;quot;&amp;gt;// i &amp;lt;tex&amp;gt;==&amp;lt;/tex&amp;gt; 0 {{---}} мы в корне&amp;lt;/font&amp;gt;&lt;br /&gt;
         swap(a[i], a[(i - 1) / 2])&lt;br /&gt;
         i = (i - 1) / 2&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Извлечение минимального элемента===&lt;br /&gt;
&lt;br /&gt;
Выполняет извлечение минимального элемента из кучи за время &amp;lt;tex&amp;gt;O(\log{n})&amp;lt;/tex&amp;gt;.&lt;br /&gt;
Извлечение выполняется в четыре этапа:&lt;br /&gt;
# Значение корневого элемента (он и является минимальным) сохраняется для последующего возврата.&lt;br /&gt;
# Последний элемент копируется в корень, после чего удаляется из кучи.&lt;br /&gt;
# Вызывается &amp;lt;math&amp;gt; \mathrm {siftDown} &amp;lt;/math&amp;gt; для корня.&lt;br /&gt;
# Сохранённый элемент возвращается.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code style=&amp;quot;display:inline-block&amp;quot;&amp;gt;&lt;br /&gt;
 '''int''' extractMin():&lt;br /&gt;
     '''int''' min = a[0]&lt;br /&gt;
     a[0] = a[a.heapSize - 1]&lt;br /&gt;
     a.heapSize = a.heapSize - 1&lt;br /&gt;
     siftDown(0)&lt;br /&gt;
     '''return''' min&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Добавление нового элемента===&lt;br /&gt;
&lt;br /&gt;
Выполняет добавление элемента в кучу за время &amp;lt;tex&amp;gt;O(\log{n})&amp;lt;/tex&amp;gt;.&lt;br /&gt;
Добавление произвольного элемента в конец кучи, и восстановление свойства упорядоченности с помощью процедуры &amp;lt;math&amp;gt; \mathrm {siftUp} &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code style=&amp;quot;display:inline-block&amp;quot;&amp;gt;&lt;br /&gt;
 '''function''' insert(key : '''int'''):&lt;br /&gt;
     a.heapSize = a.heapSize + 1&lt;br /&gt;
     a[a.heapSize - 1] = key&lt;br /&gt;
     siftUp(a.heapSize - 1)&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Построение кучи за O(n) ===&lt;br /&gt;
{{Определение | definition =&lt;br /&gt;
'''&amp;lt;tex&amp;gt;D&amp;lt;/tex&amp;gt;-куча''' {{---}} это куча, в которой у каждого элемента, кроме, возможно, элементов на последнем уровне, ровно &amp;lt;tex&amp;gt;d&amp;lt;/tex&amp;gt; потомков. &lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Дан массив &amp;lt;tex&amp;gt;a[0.. n - 1].&amp;lt;/tex&amp;gt; Требуется построить &amp;lt;tex&amp;gt;d&amp;lt;/tex&amp;gt;-кучу с минимумом в корне. Наиболее очевидный способ построить такую кучу из неупорядоченного массива {{---}} сделать нулевой элемент массива корнем, а дальше по очереди добавить все его элементы в конец кучи и запускать от каждого добавленного элемента &amp;lt;math&amp;gt;\mathrm {siftUp}&amp;lt;/math&amp;gt;. Временная оценка такого алгоритма &amp;lt;tex&amp;gt; O(n\log{n})&amp;lt;/tex&amp;gt;. Однако можно построить кучу еще быстрее — за &amp;lt;tex&amp;gt; O(n) &amp;lt;/tex&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Представим, что в массиве хранится дерево (&amp;lt;tex&amp;gt;a[0] - &amp;lt;/tex&amp;gt;  корень, а потомками элемента &amp;lt;tex&amp;gt;a[i]&amp;lt;/tex&amp;gt; являются &amp;lt;tex&amp;gt;a[2i+1]...a[2i+d]&amp;lt;/tex&amp;gt;). Сделаем &amp;lt;tex&amp;gt; \mathrm {siftDown} &amp;lt;/tex&amp;gt; для вершин, имеющих хотя бы одного потомка: от &amp;lt;tex dpi=140&amp;gt;\dfrac{n}{d}&amp;lt;/tex&amp;gt; до &amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;,{{---}} так как поддеревья, состоящие из одной вершины без потомков, уже упорядочены.&lt;br /&gt;
{{Лемма&lt;br /&gt;
|statement= На выходе получим искомую кучу. &lt;br /&gt;
|proof= При вызове &amp;lt;tex&amp;gt; \mathrm {siftDown} &amp;lt;/tex&amp;gt; для вершины, ее поддеревья являются кучами. После выполнения &amp;lt;tex&amp;gt; \mathrm {siftDown} &amp;lt;/tex&amp;gt; эта вершина с ее поддеревьями будут также являться кучей.  Значит, после выполнения всех &amp;lt;tex&amp;gt; \mathrm {siftDown} &amp;lt;/tex&amp;gt; получится куча.&lt;br /&gt;
}}&lt;br /&gt;
{{Лемма&lt;br /&gt;
|statement= Время работы этого алгоритма &amp;lt;tex&amp;gt; O(n) &amp;lt;/tex&amp;gt;.&lt;br /&gt;
|proof= Число вершин на высоте &amp;lt;tex&amp;gt;h&amp;lt;/tex&amp;gt; в куче из &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt; элементов не превосходит &amp;lt;tex dpi = &amp;quot;160&amp;quot;&amp;gt;  \left \lceil \frac{n}{d^h} \right \rceil &amp;lt;/tex&amp;gt;.  Высота кучи не превосходит &amp;lt;tex&amp;gt; \log_{d}n &amp;lt;/tex&amp;gt;. Обозначим за &amp;lt;tex&amp;gt; H &amp;lt;/tex&amp;gt; высоту дерева, тогда время построения не превосходит&lt;br /&gt;
 &lt;br /&gt;
&amp;lt;tex dpi = &amp;quot;160&amp;quot;&amp;gt; \sum_{h = 1}^H  \limits\frac{n}{d^h} \cdot d &amp;lt;/tex&amp;gt; &amp;lt;tex dpi = &amp;quot;150&amp;quot;&amp;gt;  \cdot  h &amp;lt;/tex&amp;gt; &amp;lt;tex  dpi = &amp;quot;160&amp;quot;&amp;gt; = n \cdot d \cdot {\sum_{h = 1}^H  \limits}\frac{h}{d^h}. &amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Докажем вспомогательную лемму о сумме ряда.&lt;br /&gt;
&lt;br /&gt;
{{Лемма&lt;br /&gt;
|statement= &amp;lt;tex dpi = &amp;quot;160&amp;quot;&amp;gt; {\sum_{h = 1}^\infty  \limits}\frac{h}{d^h} = \frac{d}{(d - 1)^2} . &amp;lt;/tex&amp;gt; &lt;br /&gt;
|proof=&lt;br /&gt;
 Обозначим за &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; сумму ряда. Заметим, что&lt;br /&gt;
&amp;lt;tex dpi = &amp;quot;160&amp;quot;&amp;gt; \frac{n}{d^n} = \frac{1}{d} \cdot \frac{n - 1}{d ^{n - 1}} + \frac{1}{d^n}. &amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex dpi = &amp;quot;160&amp;quot;&amp;gt;{\sum_{n = 1}^\infty  \limits}\frac{1}{d^n}&amp;lt;/tex&amp;gt; {{---}} это сумма бесконечной убывающей геометрической прогрессии, и она равна &amp;lt;tex dpi = &amp;quot;160&amp;quot;&amp;gt; &lt;br /&gt;
\frac{\frac{1}{d}}{1 - \frac{1}{d}} = \frac{1}{d - 1}. &amp;lt;/tex&amp;gt; &lt;br /&gt;
&lt;br /&gt;
Получаем  &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; &amp;lt;tex dpi = &amp;quot;160&amp;quot; &amp;gt;=\frac{1}{d}&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;\cdot s +&amp;lt;/tex&amp;gt;  &amp;lt;tex dpi = &amp;quot;160&amp;quot; &amp;gt; \frac{1}{d - 1}. &amp;lt;/tex&amp;gt; Откуда &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; &amp;lt;tex dpi = &amp;quot;160&amp;quot;&amp;gt;  = \frac{d}{(d - 1)^2}. &amp;lt;/tex&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Подставляя в нашу формулу результат леммы, получаем &amp;lt;tex &amp;gt;n&amp;lt;/tex&amp;gt; &amp;lt;tex dpi = &amp;quot;160&amp;quot;&amp;gt;\cdot (\frac {d}{d - 1})^2 &amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;  \leqslant  4 \cdot n &amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;=O(n).&amp;lt;/tex&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Псевдокод алгоритма:&lt;br /&gt;
&amp;lt;code style=&amp;quot;display:inline-block&amp;quot;&amp;gt;&lt;br /&gt;
 '''function''' heapify():&lt;br /&gt;
     '''for''' i = a.heapSize / 2 '''downto''' 0&lt;br /&gt;
         siftDown(i)&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Слияние двух куч===&lt;br /&gt;
Даны две кучи &amp;lt;tex&amp;gt;a&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt;, размерами &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt;, требуется объединить эти две кучи. &lt;br /&gt;
====Наивная реализация====&lt;br /&gt;
Поочередно добавим все элементы из &amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt; в &amp;lt;tex&amp;gt;a&amp;lt;/tex&amp;gt;. Время работы {{---}} &amp;lt;tex&amp;gt;O(m \log(n+m))&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&amp;lt;code style=&amp;quot;display:inline-block&amp;quot;&amp;gt;&lt;br /&gt;
 '''function''' merge(a, b : '''Heap'''):&lt;br /&gt;
     '''while''' b.heapSize &amp;lt;tex&amp;gt;\neq&amp;lt;/tex&amp;gt; 0  &lt;br /&gt;
         a.insert(b.extractMin())&lt;br /&gt;
&amp;lt;/code&amp;gt; &lt;br /&gt;
====Реализация с помощью построения кучи====&lt;br /&gt;
Добавим все элементы кучи &amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt; в конец массива &amp;lt;tex&amp;gt;a&amp;lt;/tex&amp;gt;, после чего вызовем функцию построения кучи. Процедура выполняется за время &amp;lt;tex&amp;gt;O(n + m)&amp;lt;/tex&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code style=&amp;quot;display:inline-block&amp;quot;&amp;gt;&lt;br /&gt;
 '''function''' merge(a, b : '''Heap'''):&lt;br /&gt;
     '''for''' i = 0 '''to''' b.heapSize - 1  &lt;br /&gt;
         a.heapSize = a.heapSize + 1&lt;br /&gt;
         a[a.heapSize - 1] = b[i]&lt;br /&gt;
     a.heapify()&lt;br /&gt;
&amp;lt;/code&amp;gt; &lt;br /&gt;
&lt;br /&gt;
===Поиск k-ого элемента===&lt;br /&gt;
Требуется найти &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt;-ый по величине элемент в куче.&lt;br /&gt;
&lt;br /&gt;
# Создаем новую кучу, в которой будем хранить пару &amp;lt;tex&amp;gt;\langle \mathtt{value}, \mathtt{index} \rangle&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;\mathtt{value}&amp;lt;/tex&amp;gt; {{---}} значение элемента, а &amp;lt;tex&amp;gt;\mathtt{index}&amp;lt;/tex&amp;gt; {{---}} индекс элемента в основном массиве, и добавляем в нее корень кучи. &lt;br /&gt;
# Возьмем корень новой кучи и добавим её детей из основной кучи, после чего удалим корень. Проделаем этот шаг &amp;lt;tex&amp;gt;k - 1&amp;lt;/tex&amp;gt; раз.&lt;br /&gt;
# В корне новой кучи будет находиться ответ.&lt;br /&gt;
&lt;br /&gt;
Время работы алгоритма {{---}} &amp;lt;tex&amp;gt;O(k \log k)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
При &amp;lt;tex&amp;gt;n \lnapprox k \ log k&amp;lt;/tex&amp;gt; выгоднее запускать [[поиск k-ой порядковой статистики за линейное время]].&lt;br /&gt;
[[Файл:Min_heap_kth.png‎|thumb|center|650px|Пример при &amp;lt;tex&amp;gt;k = 5&amp;lt;/tex&amp;gt;, красные {{---}} уже удаленные из кучи элементы, зеленые находятся в куче, а голубые {{---}} еще не рассмотрены.]]&lt;br /&gt;
&lt;br /&gt;
== См. также ==&lt;br /&gt;
* [[Биномиальная куча]]&lt;br /&gt;
* [[Фибоначчиева куча]]&lt;br /&gt;
* [[Левосторонняя куча]]&lt;br /&gt;
&lt;br /&gt;
== Источники информации ==&lt;br /&gt;
* [[wikipedia:ru:Двоичная куча|Википедия {{---}} Двоичная куча]]&lt;br /&gt;
* [[wikipedia:ru:Очередь с приоритетом|Википедия {{---}} Очередь с приоритетом]]&lt;br /&gt;
* [[wikipedia:en:Binary heap|Wikipedia {{---}} Binary heap]]&lt;br /&gt;
* [[wikipedia:en:Priority queue|Wikipedia {{---}} Priority queue]]&lt;br /&gt;
&lt;br /&gt;
[[Категория: Дискретная математика и алгоритмы]]&lt;br /&gt;
[[Категория: Приоритетные очереди]]&lt;br /&gt;
[[Категория: Структуры данных]]&lt;/div&gt;</summary>
		<author><name>Ильнар</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%94%D0%B2%D0%BE%D0%B8%D1%87%D0%BD%D0%B0%D1%8F_%D0%BA%D1%83%D1%87%D0%B0&amp;diff=47699</id>
		<title>Двоичная куча</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%94%D0%B2%D0%BE%D0%B8%D1%87%D0%BD%D0%B0%D1%8F_%D0%BA%D1%83%D1%87%D0%B0&amp;diff=47699"/>
				<updated>2015-06-05T20:19:07Z</updated>
		
		<summary type="html">&lt;p&gt;Ильнар: /* Построение кучи за O(n) */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Определение==&lt;br /&gt;
{{Определение&lt;br /&gt;
|definition=&lt;br /&gt;
'''Двоичная куча''' или '''пирамида''' (англ. ''Binary heap'') — такое двоичное [[Дерево, эквивалентные определения|подвешенное дерево]], для которого выполнены следующие три условия:&lt;br /&gt;
&lt;br /&gt;
* Значение в любой вершине не меньше, (если куча для максимума), чем значения её потомков.&lt;br /&gt;
* На &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt;-ом слое &amp;lt;tex&amp;gt;2^i&amp;lt;/tex&amp;gt; вершин, кроме последнего. Слои нумеруются с нуля.&lt;br /&gt;
* Последний слой заполнен слева направо (как показано на рисунке)&lt;br /&gt;
}}&lt;br /&gt;
[[Файл:Min_heap.png‎|thumb|325px|Пример кучи для минимума]]&lt;br /&gt;
[[Файл:Min_heap_array.png‎|thumb|325px|Хранение кучи в массиве, красная стрелка {{---}} левый сын, зеленая {{---}} правый]]&lt;br /&gt;
Удобнее всего двоичную кучу хранить в виде массива &amp;lt;tex&amp;gt;a[0..n-1]&amp;lt;/tex&amp;gt;, у которого нулевой элемент, &amp;lt;tex&amp;gt;a[0]&amp;lt;/tex&amp;gt; — элемент в корне, а потомками элемента &amp;lt;tex&amp;gt;a[i]&amp;lt;/tex&amp;gt; являются &amp;lt;tex&amp;gt;a[2i+1]&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;a[2i+2]&amp;lt;/tex&amp;gt;. Высота кучи определяется как высота двоичного дерева. То есть она равна количеству рёбер в самом длинном простом пути, соединяющем корень кучи с одним из её листьев. Высота кучи есть &amp;lt;tex&amp;gt;O(\log{n})&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt; — количество узлов дерева.&lt;br /&gt;
&lt;br /&gt;
Чаще всего используют кучи для минимума (когда предок не больше детей) и для максимума (когда предок не меньше детей).&lt;br /&gt;
&lt;br /&gt;
Двоичные кучи используют, например, для того, чтобы извлекать минимум из набора чисел за &amp;lt;tex&amp;gt;O(\log{n})&amp;lt;/tex&amp;gt;. Они являются частным случаем приоритетных очередей.&lt;br /&gt;
&lt;br /&gt;
==Базовые процедуры==&lt;br /&gt;
&lt;br /&gt;
===Восстановление свойств кучи===&lt;br /&gt;
&lt;br /&gt;
Если в куче изменяется один из элементов, то она может перестать удовлетворять свойству упорядоченности. Для восстановления этого свойства служат процедуры &amp;lt;tex&amp;gt; \mathrm {siftDown} &amp;lt;/tex&amp;gt; (просеивание вниз)&lt;br /&gt;
и &amp;lt;tex&amp;gt; \mathrm {siftUp} &amp;lt;/tex&amp;gt; (просеивание вверх). &lt;br /&gt;
Если значение измененного элемента увеличивается, то свойства кучи восстанавливаются функцией &amp;lt;tex&amp;gt; \mathrm {siftDown} &amp;lt;/tex&amp;gt;.&lt;br /&gt;
Работа процедуры: если &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt;-й элемент меньше, чем его сыновья, всё поддерево уже является кучей, и делать ничего не надо. В противном случае меняем местами &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt;-й элемент с наименьшим из его сыновей, после чего выполняем &amp;lt;tex&amp;gt; \mathrm {siftDown} &amp;lt;/tex&amp;gt; для этого сына.&lt;br /&gt;
Процедура выполняется за время &amp;lt;tex&amp;gt;O(\log{n})&amp;lt;/tex&amp;gt;.&lt;br /&gt;
====siftDown====&lt;br /&gt;
&amp;lt;code style=&amp;quot;display:inline-block&amp;quot;&amp;gt;&lt;br /&gt;
 '''function''' siftDown(i : '''int'''):&lt;br /&gt;
     '''while''' 2 * i + 1 &amp;lt;tex&amp;gt;&amp;lt;&amp;lt;/tex&amp;gt; a.heapSize     &amp;lt;font color = &amp;quot;green&amp;quot;&amp;gt;// heapSize {{---}} количество элементов в куче&amp;lt;/font&amp;gt;&lt;br /&gt;
         left = 2 * i + 1             &amp;lt;font color = &amp;quot;green&amp;quot;&amp;gt;// left {{---}} левый сын&amp;lt;/font&amp;gt;&lt;br /&gt;
         right = 2 * i + 2            &amp;lt;font color = &amp;quot;green&amp;quot;&amp;gt;// right {{---}} правый сын&amp;lt;/font&amp;gt;&lt;br /&gt;
         j = left&lt;br /&gt;
         '''if''' right &amp;lt;tex&amp;gt;&amp;lt;&amp;lt;/tex&amp;gt; a.heapSize '''and''' a[right] &amp;lt;tex&amp;gt;&amp;lt;&amp;lt;/tex&amp;gt; A[left]&lt;br /&gt;
             j = right&lt;br /&gt;
         '''if''' a[i] &amp;lt;tex&amp;gt;\leqslant&amp;lt;/tex&amp;gt; a[j]&lt;br /&gt;
             '''break'''&lt;br /&gt;
         swap(a[i], a[j])&lt;br /&gt;
         i = j&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====siftUp====&lt;br /&gt;
Если значение измененного элемента уменьшается, то свойства кучи восстанавливаются функцией &amp;lt;tex&amp;gt; \mathrm {siftUp} &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Работа процедуры: если элемент больше своего отца, условие 1 соблюдено для всего дерева, и больше ничего делать не нужно. Иначе, мы меняем местами его с отцом. После чего выполняем &amp;lt;tex&amp;gt; \mathrm {siftUp} &amp;lt;/tex&amp;gt;&lt;br /&gt;
для этого отца. Иными словами, слишком маленький элемент всплывает наверх.&lt;br /&gt;
Процедура выполняется за время &amp;lt;tex&amp;gt;O(\log{n})&amp;lt;/tex&amp;gt;. &lt;br /&gt;
&amp;lt;code style=&amp;quot;display:inline-block&amp;quot;&amp;gt;&lt;br /&gt;
 '''function''' siftUp(i : '''int'''):&lt;br /&gt;
     '''while''' a[i] &amp;lt;tex&amp;gt;&amp;lt;&amp;lt;/tex&amp;gt; a[(i - 1) / 2]     &amp;lt;font color = &amp;quot;green&amp;quot;&amp;gt;// i &amp;lt;tex&amp;gt;==&amp;lt;/tex&amp;gt; 0 {{---}} мы в корне&amp;lt;/font&amp;gt;&lt;br /&gt;
         swap(a[i], a[(i - 1) / 2])&lt;br /&gt;
         i = (i - 1) / 2&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Извлечение минимального элемента===&lt;br /&gt;
&lt;br /&gt;
Выполняет извлечение минимального элемента из кучи за время &amp;lt;tex&amp;gt;O(\log{n})&amp;lt;/tex&amp;gt;.&lt;br /&gt;
Извлечение выполняется в четыре этапа:&lt;br /&gt;
# Значение корневого элемента (он и является минимальным) сохраняется для последующего возврата.&lt;br /&gt;
# Последний элемент копируется в корень, после чего удаляется из кучи.&lt;br /&gt;
# Вызывается &amp;lt;math&amp;gt; \mathrm {siftDown} &amp;lt;/math&amp;gt; для корня.&lt;br /&gt;
# Сохранённый элемент возвращается.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code style=&amp;quot;display:inline-block&amp;quot;&amp;gt;&lt;br /&gt;
 '''int''' extractMin():&lt;br /&gt;
     '''int''' min = a[0]&lt;br /&gt;
     a[0] = a[a.heapSize - 1]&lt;br /&gt;
     a.heapSize = a.heapSize - 1&lt;br /&gt;
     siftDown(0)&lt;br /&gt;
     '''return''' min&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Добавление нового элемента===&lt;br /&gt;
&lt;br /&gt;
Выполняет добавление элемента в кучу за время &amp;lt;tex&amp;gt;O(\log{n})&amp;lt;/tex&amp;gt;.&lt;br /&gt;
Добавление произвольного элемента в конец кучи, и восстановление свойства упорядоченности с помощью процедуры &amp;lt;math&amp;gt; \mathrm {siftUp} &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code style=&amp;quot;display:inline-block&amp;quot;&amp;gt;&lt;br /&gt;
 '''function''' insert(key : '''int'''):&lt;br /&gt;
     a.heapSize = a.heapSize + 1&lt;br /&gt;
     a[a.heapSize - 1] = key&lt;br /&gt;
     siftUp(a.heapSize - 1)&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Построение кучи за O(n) ===&lt;br /&gt;
{{Определение | definition =&lt;br /&gt;
'''&amp;lt;tex&amp;gt;D&amp;lt;/tex&amp;gt;-куча''' {{---}} это куча, в которой у каждого элемента, кроме, возможно, элементов на последнем уровне, ровно &amp;lt;tex&amp;gt;d&amp;lt;/tex&amp;gt; потомков. &lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Дан массив &amp;lt;tex&amp;gt;a[0.. n - 1].&amp;lt;/tex&amp;gt; Требуется построить &amp;lt;tex&amp;gt;d&amp;lt;/tex&amp;gt;-кучу с минимумом в корне. Наиболее очевидный способ построить такую кучу из неупорядоченного массива {{---}} сделать нулевой элемент массива корнем, а дальше по очереди добавить все его элементы в конец кучи и запускать от каждого добавленного элемента &amp;lt;math&amp;gt;\mathrm {siftUp}&amp;lt;/math&amp;gt;. Временная оценка такого алгоритма &amp;lt;tex&amp;gt; O(n\log{n})&amp;lt;/tex&amp;gt;. Однако можно построить кучу еще быстрее — за &amp;lt;tex&amp;gt; O(n) &amp;lt;/tex&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Представим, что в массиве хранится дерево (&amp;lt;tex&amp;gt;a[0] - &amp;lt;/tex&amp;gt;  корень, а потомками элемента &amp;lt;tex&amp;gt;a[i]&amp;lt;/tex&amp;gt; являются &amp;lt;tex&amp;gt;a[2i+1]...a[2i+d]&amp;lt;/tex&amp;gt;). Сделаем &amp;lt;tex&amp;gt; \mathrm {siftDown} &amp;lt;/tex&amp;gt; для вершин, имеющих хотя бы одного потомка: от &amp;lt;tex dpi=140&amp;gt;\dfrac{n}{d}&amp;lt;/tex&amp;gt; до &amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;,{{---}} так как поддеревья, состоящие из одной вершины без потомков, уже упорядочены.&lt;br /&gt;
{{Лемма&lt;br /&gt;
|statement= На выходе получим искомую кучу. &lt;br /&gt;
|proof= При вызове &amp;lt;tex&amp;gt; \mathrm {siftDown} &amp;lt;/tex&amp;gt; для вершины, ее поддеревья являются кучами. После выполнения &amp;lt;tex&amp;gt; \mathrm {siftDown} &amp;lt;/tex&amp;gt; эта вершина с ее поддеревьями будут также являться кучей.  Значит, после выполнения всех &amp;lt;tex&amp;gt; \mathrm {siftDown} &amp;lt;/tex&amp;gt; получится куча.&lt;br /&gt;
}}&lt;br /&gt;
{{Лемма&lt;br /&gt;
|statement= Время работы этого алгоритма &amp;lt;tex&amp;gt; O(n) &amp;lt;/tex&amp;gt;.&lt;br /&gt;
|proof= Число вершин на высоте &amp;lt;tex&amp;gt;h&amp;lt;/tex&amp;gt; в куче из &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt; элементов не превосходит &amp;lt;tex dpi = &amp;quot;160&amp;quot;&amp;gt;  \left \lceil \frac{n}{d^h} \right \rceil &amp;lt;/tex&amp;gt;.  Высота кучи не превосходит &amp;lt;tex&amp;gt; \log_{d}n &amp;lt;/tex&amp;gt;. Обозначим за &amp;lt;tex&amp;gt; H &amp;lt;/tex&amp;gt; высоту дерева, тогда время построения не превосходит&lt;br /&gt;
 &lt;br /&gt;
&amp;lt;tex dpi = &amp;quot;160&amp;quot;&amp;gt; \sum_{h = 1}^H  \limits\frac{n}{d^h} \cdot d &amp;lt;/tex&amp;gt; &amp;lt;tex dpi = &amp;quot;150&amp;quot;&amp;gt;  \cdot  h &amp;lt;/tex&amp;gt; &amp;lt;tex  dpi = &amp;quot;160&amp;quot;&amp;gt; = n \cdot d \cdot {\sum_{h = 1}^H  \limits}\frac{h}{d^h}. &amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Докажем вспомогательную лемму о сумме ряда.&lt;br /&gt;
&lt;br /&gt;
{{Лемма&lt;br /&gt;
|statement= &amp;lt;tex dpi = &amp;quot;160&amp;quot;&amp;gt; {\sum_{h = 1}^\infty  \limits}\frac{h}{d^h} = \frac{d}{(d - 1)^2} . &amp;lt;/tex&amp;gt; &lt;br /&gt;
|proof=&lt;br /&gt;
 Обозначим за &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; сумму ряда. Заметим, что&lt;br /&gt;
&amp;lt;tex dpi = &amp;quot;160&amp;quot;&amp;gt; \frac{n}{d^n} = \frac{1}{d} \cdot \frac{n - 1}{d ^{n - 1}} + \frac{1}{d^n}. &amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex dpi = &amp;quot;160&amp;quot;&amp;gt;{\sum_{n = 1}^\infty  \limits}\frac{1}{d^n}&amp;lt;/tex&amp;gt; {{---}} это сумма бесконечной убывающей геометрической прогрессии, и она равна &amp;lt;tex dpi = &amp;quot;160&amp;quot;&amp;gt; &lt;br /&gt;
\frac{\frac{1}{d}}{1 - \frac{1}{d}} = \frac{1}{d - 1}. &amp;lt;/tex&amp;gt; &lt;br /&gt;
&lt;br /&gt;
Получаем  &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; &amp;lt;tex dpi = &amp;quot;160&amp;quot; &amp;gt;=\frac{1}{d}&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;\cdot s +&amp;lt;/tex&amp;gt;  &amp;lt;tex dpi = &amp;quot;160&amp;quot; &amp;gt; \frac{1}{d - 1}. &amp;lt;/tex&amp;gt; Откуда &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; &amp;lt;tex dpi = &amp;quot;160&amp;quot;&amp;gt;  = \frac{d}{(d - 1)^2}. &amp;lt;/tex&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Подставляя в нашу формулу результат леммы, получаем &amp;lt;tex &amp;gt;n&amp;lt;/tex&amp;gt; &amp;lt;tex dpi = &amp;quot;160&amp;quot;&amp;gt;\cdot (\frac {d}{d - 1})^2 &amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;  \leqslant  4 \cdot n &amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;=O(n).&amp;lt;/tex&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Псевдокод алгоритма:&lt;br /&gt;
&amp;lt;code style=&amp;quot;display:inline-block&amp;quot;&amp;gt;&lt;br /&gt;
 '''function''' heapify():&lt;br /&gt;
     '''for''' i = a.heapSize / 2 '''downto''' 0&lt;br /&gt;
         siftDown(i)&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Слияние двух куч===&lt;br /&gt;
Даны две кучи &amp;lt;tex&amp;gt;a&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt;, размерами &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt;, требуется объединить эти две кучи. &lt;br /&gt;
====Наивная реализация====&lt;br /&gt;
Поочередно добавим все элементы из &amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt; в &amp;lt;tex&amp;gt;a&amp;lt;/tex&amp;gt;. Время работы {{---}} &amp;lt;tex&amp;gt;O(m \log(n+m))&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&amp;lt;code style=&amp;quot;display:inline-block&amp;quot;&amp;gt;&lt;br /&gt;
 '''function''' merge(a, b : '''Heap'''):&lt;br /&gt;
     '''while''' b.heapSize &amp;lt;tex&amp;gt;\neq&amp;lt;/tex&amp;gt; 0  &lt;br /&gt;
         a.insert(b.extractMin())&lt;br /&gt;
&amp;lt;/code&amp;gt; &lt;br /&gt;
====Реализация с помощью построения кучи====&lt;br /&gt;
Добавим все элементы кучи &amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt; в конец массива &amp;lt;tex&amp;gt;a&amp;lt;/tex&amp;gt;, после чего вызовем функцию построения кучи. Процедура выполняется за время &amp;lt;tex&amp;gt;O(n + m)&amp;lt;/tex&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code style=&amp;quot;display:inline-block&amp;quot;&amp;gt;&lt;br /&gt;
 '''function''' merge(a, b : '''Heap'''):&lt;br /&gt;
     '''for''' i = 0 '''to''' b.heapSize - 1  &lt;br /&gt;
         a.heapSize = a.heapSize + 1&lt;br /&gt;
         a[a.heapSize - 1] = b[i]&lt;br /&gt;
     a.heapify()&lt;br /&gt;
&amp;lt;/code&amp;gt; &lt;br /&gt;
&lt;br /&gt;
===Поиск k-ого элемента===&lt;br /&gt;
Требуется найти &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt;-ый по величине элемент в куче.&lt;br /&gt;
&lt;br /&gt;
# Создаем новую кучу, в которой будем хранить пару &amp;lt;tex&amp;gt;\langle \mathtt{value}, \mathtt{index} \rangle&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;\mathtt{value}&amp;lt;/tex&amp;gt; {{---}} значение элемента, а &amp;lt;tex&amp;gt;\mathtt{index}&amp;lt;/tex&amp;gt; {{---}} индекс элемента в основном массиве, и добавляем в нее корень кучи. &lt;br /&gt;
# Возьмем корень новой кучи и добавим её детей из основной кучи, после чего удалим корень. Проделаем этот шаг &amp;lt;tex&amp;gt;k - 1&amp;lt;/tex&amp;gt; раз.&lt;br /&gt;
# В корне новой кучи будет находиться ответ.&lt;br /&gt;
&lt;br /&gt;
Время работы алгоритма {{---}} &amp;lt;tex&amp;gt;O(k \log k)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
[[Файл:Min_heap_kth.png‎|thumb|center|650px|Пример при &amp;lt;tex&amp;gt;k = 5&amp;lt;/tex&amp;gt;, красные {{---}} уже удаленные из кучи элементы, зеленые находятся в куче, а голубые {{---}} еще не рассмотрены.]]&lt;br /&gt;
&lt;br /&gt;
== См. также ==&lt;br /&gt;
* [[Биномиальная куча]]&lt;br /&gt;
* [[Фибоначчиева куча]]&lt;br /&gt;
* [[Левосторонняя куча]]&lt;br /&gt;
&lt;br /&gt;
== Источники информации ==&lt;br /&gt;
* [[wikipedia:ru:Двоичная куча|Википедия {{---}} Двоичная куча]]&lt;br /&gt;
* [[wikipedia:ru:Очередь с приоритетом|Википедия {{---}} Очередь с приоритетом]]&lt;br /&gt;
* [[wikipedia:en:Binary heap|Wikipedia {{---}} Binary heap]]&lt;br /&gt;
* [[wikipedia:en:Priority queue|Wikipedia {{---}} Priority queue]]&lt;br /&gt;
&lt;br /&gt;
[[Категория: Дискретная математика и алгоритмы]]&lt;br /&gt;
[[Категория: Приоритетные очереди]]&lt;br /&gt;
[[Категория: Структуры данных]]&lt;/div&gt;</summary>
		<author><name>Ильнар</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%94%D0%B2%D0%BE%D0%B8%D1%87%D0%BD%D0%B0%D1%8F_%D0%BA%D1%83%D1%87%D0%B0&amp;diff=47698</id>
		<title>Двоичная куча</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%94%D0%B2%D0%BE%D0%B8%D1%87%D0%BD%D0%B0%D1%8F_%D0%BA%D1%83%D1%87%D0%B0&amp;diff=47698"/>
				<updated>2015-06-05T20:15:10Z</updated>
		
		<summary type="html">&lt;p&gt;Ильнар: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Определение==&lt;br /&gt;
{{Определение&lt;br /&gt;
|definition=&lt;br /&gt;
'''Двоичная куча''' или '''пирамида''' (англ. ''Binary heap'') — такое двоичное [[Дерево, эквивалентные определения|подвешенное дерево]], для которого выполнены следующие три условия:&lt;br /&gt;
&lt;br /&gt;
* Значение в любой вершине не меньше, (если куча для максимума), чем значения её потомков.&lt;br /&gt;
* На &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt;-ом слое &amp;lt;tex&amp;gt;2^i&amp;lt;/tex&amp;gt; вершин, кроме последнего. Слои нумеруются с нуля.&lt;br /&gt;
* Последний слой заполнен слева направо (как показано на рисунке)&lt;br /&gt;
}}&lt;br /&gt;
[[Файл:Min_heap.png‎|thumb|325px|Пример кучи для минимума]]&lt;br /&gt;
[[Файл:Min_heap_array.png‎|thumb|325px|Хранение кучи в массиве, красная стрелка {{---}} левый сын, зеленая {{---}} правый]]&lt;br /&gt;
Удобнее всего двоичную кучу хранить в виде массива &amp;lt;tex&amp;gt;a[0..n-1]&amp;lt;/tex&amp;gt;, у которого нулевой элемент, &amp;lt;tex&amp;gt;a[0]&amp;lt;/tex&amp;gt; — элемент в корне, а потомками элемента &amp;lt;tex&amp;gt;a[i]&amp;lt;/tex&amp;gt; являются &amp;lt;tex&amp;gt;a[2i+1]&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;a[2i+2]&amp;lt;/tex&amp;gt;. Высота кучи определяется как высота двоичного дерева. То есть она равна количеству рёбер в самом длинном простом пути, соединяющем корень кучи с одним из её листьев. Высота кучи есть &amp;lt;tex&amp;gt;O(\log{n})&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt; — количество узлов дерева.&lt;br /&gt;
&lt;br /&gt;
Чаще всего используют кучи для минимума (когда предок не больше детей) и для максимума (когда предок не меньше детей).&lt;br /&gt;
&lt;br /&gt;
Двоичные кучи используют, например, для того, чтобы извлекать минимум из набора чисел за &amp;lt;tex&amp;gt;O(\log{n})&amp;lt;/tex&amp;gt;. Они являются частным случаем приоритетных очередей.&lt;br /&gt;
&lt;br /&gt;
==Базовые процедуры==&lt;br /&gt;
&lt;br /&gt;
===Восстановление свойств кучи===&lt;br /&gt;
&lt;br /&gt;
Если в куче изменяется один из элементов, то она может перестать удовлетворять свойству упорядоченности. Для восстановления этого свойства служат процедуры &amp;lt;tex&amp;gt; \mathrm {siftDown} &amp;lt;/tex&amp;gt; (просеивание вниз)&lt;br /&gt;
и &amp;lt;tex&amp;gt; \mathrm {siftUp} &amp;lt;/tex&amp;gt; (просеивание вверх). &lt;br /&gt;
Если значение измененного элемента увеличивается, то свойства кучи восстанавливаются функцией &amp;lt;tex&amp;gt; \mathrm {siftDown} &amp;lt;/tex&amp;gt;.&lt;br /&gt;
Работа процедуры: если &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt;-й элемент меньше, чем его сыновья, всё поддерево уже является кучей, и делать ничего не надо. В противном случае меняем местами &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt;-й элемент с наименьшим из его сыновей, после чего выполняем &amp;lt;tex&amp;gt; \mathrm {siftDown} &amp;lt;/tex&amp;gt; для этого сына.&lt;br /&gt;
Процедура выполняется за время &amp;lt;tex&amp;gt;O(\log{n})&amp;lt;/tex&amp;gt;.&lt;br /&gt;
====siftDown====&lt;br /&gt;
&amp;lt;code style=&amp;quot;display:inline-block&amp;quot;&amp;gt;&lt;br /&gt;
 '''function''' siftDown(i : '''int'''):&lt;br /&gt;
     '''while''' 2 * i + 1 &amp;lt;tex&amp;gt;&amp;lt;&amp;lt;/tex&amp;gt; a.heapSize     &amp;lt;font color = &amp;quot;green&amp;quot;&amp;gt;// heapSize {{---}} количество элементов в куче&amp;lt;/font&amp;gt;&lt;br /&gt;
         left = 2 * i + 1             &amp;lt;font color = &amp;quot;green&amp;quot;&amp;gt;// left {{---}} левый сын&amp;lt;/font&amp;gt;&lt;br /&gt;
         right = 2 * i + 2            &amp;lt;font color = &amp;quot;green&amp;quot;&amp;gt;// right {{---}} правый сын&amp;lt;/font&amp;gt;&lt;br /&gt;
         j = left&lt;br /&gt;
         '''if''' right &amp;lt;tex&amp;gt;&amp;lt;&amp;lt;/tex&amp;gt; a.heapSize '''and''' a[right] &amp;lt;tex&amp;gt;&amp;lt;&amp;lt;/tex&amp;gt; A[left]&lt;br /&gt;
             j = right&lt;br /&gt;
         '''if''' a[i] &amp;lt;tex&amp;gt;\leqslant&amp;lt;/tex&amp;gt; a[j]&lt;br /&gt;
             '''break'''&lt;br /&gt;
         swap(a[i], a[j])&lt;br /&gt;
         i = j&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====siftUp====&lt;br /&gt;
Если значение измененного элемента уменьшается, то свойства кучи восстанавливаются функцией &amp;lt;tex&amp;gt; \mathrm {siftUp} &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Работа процедуры: если элемент больше своего отца, условие 1 соблюдено для всего дерева, и больше ничего делать не нужно. Иначе, мы меняем местами его с отцом. После чего выполняем &amp;lt;tex&amp;gt; \mathrm {siftUp} &amp;lt;/tex&amp;gt;&lt;br /&gt;
для этого отца. Иными словами, слишком маленький элемент всплывает наверх.&lt;br /&gt;
Процедура выполняется за время &amp;lt;tex&amp;gt;O(\log{n})&amp;lt;/tex&amp;gt;. &lt;br /&gt;
&amp;lt;code style=&amp;quot;display:inline-block&amp;quot;&amp;gt;&lt;br /&gt;
 '''function''' siftUp(i : '''int'''):&lt;br /&gt;
     '''while''' a[i] &amp;lt;tex&amp;gt;&amp;lt;&amp;lt;/tex&amp;gt; a[(i - 1) / 2]     &amp;lt;font color = &amp;quot;green&amp;quot;&amp;gt;// i &amp;lt;tex&amp;gt;==&amp;lt;/tex&amp;gt; 0 {{---}} мы в корне&amp;lt;/font&amp;gt;&lt;br /&gt;
         swap(a[i], a[(i - 1) / 2])&lt;br /&gt;
         i = (i - 1) / 2&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Извлечение минимального элемента===&lt;br /&gt;
&lt;br /&gt;
Выполняет извлечение минимального элемента из кучи за время &amp;lt;tex&amp;gt;O(\log{n})&amp;lt;/tex&amp;gt;.&lt;br /&gt;
Извлечение выполняется в четыре этапа:&lt;br /&gt;
# Значение корневого элемента (он и является минимальным) сохраняется для последующего возврата.&lt;br /&gt;
# Последний элемент копируется в корень, после чего удаляется из кучи.&lt;br /&gt;
# Вызывается &amp;lt;math&amp;gt; \mathrm {siftDown} &amp;lt;/math&amp;gt; для корня.&lt;br /&gt;
# Сохранённый элемент возвращается.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code style=&amp;quot;display:inline-block&amp;quot;&amp;gt;&lt;br /&gt;
 '''int''' extractMin():&lt;br /&gt;
     '''int''' min = a[0]&lt;br /&gt;
     a[0] = a[a.heapSize - 1]&lt;br /&gt;
     a.heapSize = a.heapSize - 1&lt;br /&gt;
     siftDown(0)&lt;br /&gt;
     '''return''' min&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Добавление нового элемента===&lt;br /&gt;
&lt;br /&gt;
Выполняет добавление элемента в кучу за время &amp;lt;tex&amp;gt;O(\log{n})&amp;lt;/tex&amp;gt;.&lt;br /&gt;
Добавление произвольного элемента в конец кучи, и восстановление свойства упорядоченности с помощью процедуры &amp;lt;math&amp;gt; \mathrm {siftUp} &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code style=&amp;quot;display:inline-block&amp;quot;&amp;gt;&lt;br /&gt;
 '''function''' insert(key : '''int'''):&lt;br /&gt;
     a.heapSize = a.heapSize + 1&lt;br /&gt;
     a[a.heapSize - 1] = key&lt;br /&gt;
     siftUp(a.heapSize - 1)&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Построение кучи за O(n) ===&lt;br /&gt;
{{Определение | definition =&lt;br /&gt;
'''&amp;lt;tex&amp;gt;D&amp;lt;/tex&amp;gt;-куча''' {{---}} это куча, в которой у каждого элемента, кроме, возможно, элементов на последнем уровне, ровно &amp;lt;tex&amp;gt;d&amp;lt;/tex&amp;gt; потомков. &lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Дан массив &amp;lt;tex&amp;gt;a[0.. n - 1].&amp;lt;/tex&amp;gt; Требуется построить &amp;lt;tex&amp;gt;d&amp;lt;/tex&amp;gt;-кучу с минимумом в корне. Наиболее очевидный способ построить такую кучу из неупорядоченного массива {{---}} сделать нулевой элемент массива корнем, а дальше по очереди добавить все его элементы в конец кучи и запускать от каждого добавленного элемента &amp;lt;math&amp;gt;\mathrm {siftUp}&amp;lt;/math&amp;gt;. Временная оценка такого алгоритма &amp;lt;tex&amp;gt; O(n\log{n})&amp;lt;/tex&amp;gt;. Однако можно построить кучу еще быстрее — за &amp;lt;tex&amp;gt; O(n) &amp;lt;/tex&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Представим, что в массиве хранится дерево (&amp;lt;tex&amp;gt;a[0] - &amp;lt;/tex&amp;gt;  корень, а потомками элемента &amp;lt;tex&amp;gt;a[i]&amp;lt;/tex&amp;gt; являются &amp;lt;tex&amp;gt;a[2i+1]...a[2i+d]&amp;lt;/tex&amp;gt;). Сделаем &amp;lt;tex&amp;gt; \mathrm {siftDown} &amp;lt;/tex&amp;gt; для вершин, имеющих хотя бы одного потомка: от &amp;lt;tex dpi=140&amp;gt;\genfrac {}{}{}{}{n}{d}&amp;lt;/tex&amp;gt; до &amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;,{{---}} так как поддеревья, состоящие из одной вершины без потомков, уже упорядочены.&lt;br /&gt;
{{Лемма&lt;br /&gt;
|statement= На выходе получим искомую кучу. &lt;br /&gt;
|proof= При вызове &amp;lt;tex&amp;gt; \mathrm {siftDown} &amp;lt;/tex&amp;gt; для вершины, ее поддеревья являются кучами. После выполнения &amp;lt;tex&amp;gt; \mathrm {siftDown} &amp;lt;/tex&amp;gt; эта вершина с ее поддеревьями будут также являться кучей.  Значит, после выполнения всех &amp;lt;tex&amp;gt; \mathrm {siftDown} &amp;lt;/tex&amp;gt; получится куча.&lt;br /&gt;
}}&lt;br /&gt;
{{Лемма&lt;br /&gt;
|statement= Время работы этого алгоритма &amp;lt;tex&amp;gt; O(n) &amp;lt;/tex&amp;gt;.&lt;br /&gt;
|proof= Число вершин на высоте &amp;lt;tex&amp;gt;h&amp;lt;/tex&amp;gt; в куче из &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt; элементов не превосходит &amp;lt;tex dpi = &amp;quot;160&amp;quot;&amp;gt;  \left \lceil \frac{n}{d^h} \right \rceil &amp;lt;/tex&amp;gt;.  Высота кучи не превосходит &amp;lt;tex&amp;gt; \log_{d}n &amp;lt;/tex&amp;gt;. Обозначим за &amp;lt;tex&amp;gt; H &amp;lt;/tex&amp;gt; высоту дерева, тогда время построения не превосходит&lt;br /&gt;
 &lt;br /&gt;
&amp;lt;tex dpi = &amp;quot;160&amp;quot;&amp;gt; \sum_{h = 1}^H  \limits\frac{n}{d^h} \cdot d &amp;lt;/tex&amp;gt; &amp;lt;tex dpi = &amp;quot;150&amp;quot;&amp;gt;  \cdot  h &amp;lt;/tex&amp;gt; &amp;lt;tex  dpi = &amp;quot;160&amp;quot;&amp;gt; = n \cdot d \cdot {\sum_{h = 1}^H  \limits}\frac{h}{d^h}. &amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Докажем вспомогательную лемму о сумме ряда.&lt;br /&gt;
&lt;br /&gt;
{{Лемма&lt;br /&gt;
|statement= &amp;lt;tex dpi = &amp;quot;160&amp;quot;&amp;gt; {\sum_{h = 1}^\infty  \limits}\frac{h}{d^h} = \frac{d}{(d - 1)^2} . &amp;lt;/tex&amp;gt; &lt;br /&gt;
|proof=&lt;br /&gt;
 Обозначим за &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; сумму ряда. Заметим, что&lt;br /&gt;
&amp;lt;tex dpi = &amp;quot;160&amp;quot;&amp;gt; \frac{n}{d^n} = \frac{1}{d} \cdot \frac{n - 1}{d ^{n - 1}} + \frac{1}{d^n}. &amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex dpi = &amp;quot;160&amp;quot;&amp;gt;{\sum_{n = 1}^\infty  \limits}\frac{1}{d^n}&amp;lt;/tex&amp;gt; {{---}} это сумма бесконечной убывающей геометрической прогрессии, и она равна &amp;lt;tex dpi = &amp;quot;160&amp;quot;&amp;gt; &lt;br /&gt;
\frac{\frac{1}{d}}{1 - \frac{1}{d}} = \frac{1}{d - 1}. &amp;lt;/tex&amp;gt; &lt;br /&gt;
&lt;br /&gt;
Получаем  &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; &amp;lt;tex dpi = &amp;quot;160&amp;quot; &amp;gt;=\frac{1}{d}&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;\cdot s +&amp;lt;/tex&amp;gt;  &amp;lt;tex dpi = &amp;quot;160&amp;quot; &amp;gt; \frac{1}{d - 1}. &amp;lt;/tex&amp;gt; Откуда &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; &amp;lt;tex dpi = &amp;quot;160&amp;quot;&amp;gt;  = \frac{d}{(d - 1)^2}. &amp;lt;/tex&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Подставляя в нашу формулу результат леммы, получаем &amp;lt;tex &amp;gt;n&amp;lt;/tex&amp;gt; &amp;lt;tex dpi = &amp;quot;160&amp;quot;&amp;gt;\cdot (\frac {d}{d - 1})^2 &amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;  \leqslant  4 \cdot n &amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;=O(n).&amp;lt;/tex&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Псевдокод алгоритма:&lt;br /&gt;
&amp;lt;code style=&amp;quot;display:inline-block&amp;quot;&amp;gt;&lt;br /&gt;
 '''function''' heapify():&lt;br /&gt;
     '''for''' i = a.heapSize / 2 '''downto''' 0&lt;br /&gt;
         siftDown(i)&lt;br /&gt;
&amp;lt;/code&amp;gt; &lt;br /&gt;
&lt;br /&gt;
===Слияние двух куч===&lt;br /&gt;
Даны две кучи &amp;lt;tex&amp;gt;a&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt;, размерами &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt;, требуется объединить эти две кучи. &lt;br /&gt;
====Наивная реализация====&lt;br /&gt;
Поочередно добавим все элементы из &amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt; в &amp;lt;tex&amp;gt;a&amp;lt;/tex&amp;gt;. Время работы {{---}} &amp;lt;tex&amp;gt;O(m \log(n+m))&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&amp;lt;code style=&amp;quot;display:inline-block&amp;quot;&amp;gt;&lt;br /&gt;
 '''function''' merge(a, b : '''Heap'''):&lt;br /&gt;
     '''while''' b.heapSize &amp;lt;tex&amp;gt;\neq&amp;lt;/tex&amp;gt; 0  &lt;br /&gt;
         a.insert(b.extractMin())&lt;br /&gt;
&amp;lt;/code&amp;gt; &lt;br /&gt;
====Реализация с помощью построения кучи====&lt;br /&gt;
Добавим все элементы кучи &amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt; в конец массива &amp;lt;tex&amp;gt;a&amp;lt;/tex&amp;gt;, после чего вызовем функцию построения кучи. Процедура выполняется за время &amp;lt;tex&amp;gt;O(n + m)&amp;lt;/tex&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code style=&amp;quot;display:inline-block&amp;quot;&amp;gt;&lt;br /&gt;
 '''function''' merge(a, b : '''Heap'''):&lt;br /&gt;
     '''for''' i = 0 '''to''' b.heapSize - 1  &lt;br /&gt;
         a.heapSize = a.heapSize + 1&lt;br /&gt;
         a[a.heapSize - 1] = b[i]&lt;br /&gt;
     a.heapify()&lt;br /&gt;
&amp;lt;/code&amp;gt; &lt;br /&gt;
&lt;br /&gt;
===Поиск k-ого элемента===&lt;br /&gt;
Требуется найти &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt;-ый по величине элемент в куче.&lt;br /&gt;
&lt;br /&gt;
# Создаем новую кучу, в которой будем хранить пару &amp;lt;tex&amp;gt;\langle \mathtt{value}, \mathtt{index} \rangle&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;\mathtt{value}&amp;lt;/tex&amp;gt; {{---}} значение элемента, а &amp;lt;tex&amp;gt;\mathtt{index}&amp;lt;/tex&amp;gt; {{---}} индекс элемента в основном массиве, и добавляем в нее корень кучи. &lt;br /&gt;
# Возьмем корень новой кучи и добавим её детей из основной кучи, после чего удалим корень. Проделаем этот шаг &amp;lt;tex&amp;gt;k - 1&amp;lt;/tex&amp;gt; раз.&lt;br /&gt;
# В корне новой кучи будет находиться ответ.&lt;br /&gt;
&lt;br /&gt;
Время работы алгоритма {{---}} &amp;lt;tex&amp;gt;O(k \log k)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
[[Файл:Min_heap_kth.png‎|thumb|center|650px|Пример при &amp;lt;tex&amp;gt;k = 5&amp;lt;/tex&amp;gt;, красные {{---}} уже удаленные из кучи элементы, зеленые находятся в куче, а голубые {{---}} еще не рассмотрены.]]&lt;br /&gt;
&lt;br /&gt;
== См. также ==&lt;br /&gt;
* [[Биномиальная куча]]&lt;br /&gt;
* [[Фибоначчиева куча]]&lt;br /&gt;
* [[Левосторонняя куча]]&lt;br /&gt;
&lt;br /&gt;
== Источники информации ==&lt;br /&gt;
* [[wikipedia:ru:Двоичная куча|Википедия {{---}} Двоичная куча]]&lt;br /&gt;
* [[wikipedia:ru:Очередь с приоритетом|Википедия {{---}} Очередь с приоритетом]]&lt;br /&gt;
* [[wikipedia:en:Binary heap|Wikipedia {{---}} Binary heap]]&lt;br /&gt;
* [[wikipedia:en:Priority queue|Wikipedia {{---}} Priority queue]]&lt;br /&gt;
&lt;br /&gt;
[[Категория: Дискретная математика и алгоритмы]]&lt;br /&gt;
[[Категория: Приоритетные очереди]]&lt;br /&gt;
[[Категория: Структуры данных]]&lt;/div&gt;</summary>
		<author><name>Ильнар</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%94%D0%B2%D0%BE%D0%B8%D1%87%D0%BD%D0%B0%D1%8F_%D0%BA%D1%83%D1%87%D0%B0&amp;diff=47697</id>
		<title>Двоичная куча</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%94%D0%B2%D0%BE%D0%B8%D1%87%D0%BD%D0%B0%D1%8F_%D0%BA%D1%83%D1%87%D0%B0&amp;diff=47697"/>
				<updated>2015-06-05T20:09:39Z</updated>
		
		<summary type="html">&lt;p&gt;Ильнар: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Определение==&lt;br /&gt;
{{Определение&lt;br /&gt;
|definition=&lt;br /&gt;
'''Двоичная куча''' или '''пирамида''' (англ. ''Binary heap'') — такое двоичное [[Дерево, эквивалентные определения|подвешенное дерево]], для которого выполнены следующие три условия:&lt;br /&gt;
&lt;br /&gt;
* Значение в любой вершине не меньше, (если куча для максимума), чем значения её потомков.&lt;br /&gt;
* На &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt;-ом слое &amp;lt;tex&amp;gt;2^i&amp;lt;/tex&amp;gt; вершин, кроме последнего. Слои нумеруются с нуля.&lt;br /&gt;
* Последний слой заполнен слева направо (как показано на рисунке)&lt;br /&gt;
}}&lt;br /&gt;
[[Файл:Min_heap.png‎|thumb|325px|Пример кучи для минимума]]&lt;br /&gt;
[[Файл:Min_heap_array.png‎|thumb|325px|Хранение кучи в массиве, красная стрелка {{---}} левый сын, зеленая {{---}} правый]]&lt;br /&gt;
Удобнее всего двоичную кучу хранить в виде массива &amp;lt;tex&amp;gt;a[0..n-1]&amp;lt;/tex&amp;gt;, у которого нулевой элемент, &amp;lt;tex&amp;gt;a[0]&amp;lt;/tex&amp;gt; — элемент в корне, а потомками элемента &amp;lt;tex&amp;gt;a[i]&amp;lt;/tex&amp;gt; являются &amp;lt;tex&amp;gt;a[2i+1]&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;a[2i+2]&amp;lt;/tex&amp;gt;. Высота кучи определяется как высота двоичного дерева. То есть она равна количеству рёбер в самом длинном простом пути, соединяющем корень кучи с одним из её листьев. Высота кучи есть &amp;lt;tex&amp;gt;O(\log{n})&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt; — количество узлов дерева.&lt;br /&gt;
&lt;br /&gt;
Чаще всего используют кучи для минимума (когда предок не больше детей) и для максимума (когда предок не меньше детей).&lt;br /&gt;
&lt;br /&gt;
Двоичные кучи используют, например, для того, чтобы извлекать минимум из набора чисел за &amp;lt;tex&amp;gt;O(\log{n})&amp;lt;/tex&amp;gt;. Они являются частным случаем приоритетных очередей.&lt;br /&gt;
&lt;br /&gt;
==Базовые процедуры==&lt;br /&gt;
&lt;br /&gt;
===Восстановление свойств кучи===&lt;br /&gt;
&lt;br /&gt;
Если в куче изменяется один из элементов, то она может перестать удовлетворять свойству упорядоченности. Для восстановления этого свойства служат процедуры &amp;lt;tex&amp;gt; \mathrm {siftDown} &amp;lt;/tex&amp;gt; (просеивание вниз)&lt;br /&gt;
и &amp;lt;tex&amp;gt; \mathrm {siftUp} &amp;lt;/tex&amp;gt; (просеивание вверх). &lt;br /&gt;
Если значение измененного элемента увеличивается, то свойства кучи восстанавливаются функцией &amp;lt;tex&amp;gt; \mathrm {siftDown} &amp;lt;/tex&amp;gt;.&lt;br /&gt;
Работа процедуры: если &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt;-й элемент меньше, чем его сыновья, всё поддерево уже является кучей, и делать ничего не надо. В противном случае меняем местами &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt;-й элемент с наименьшим из его сыновей, после чего выполняем &amp;lt;tex&amp;gt; \mathrm {siftDown} &amp;lt;/tex&amp;gt; для этого сына.&lt;br /&gt;
Процедура выполняется за время &amp;lt;tex&amp;gt;O(\log{n})&amp;lt;/tex&amp;gt;.&lt;br /&gt;
====siftDown====&lt;br /&gt;
&amp;lt;code style=&amp;quot;display:inline-block&amp;quot;&amp;gt;&lt;br /&gt;
 '''function''' siftDown(i : '''int'''):&lt;br /&gt;
     '''while''' 2 * i + 1 &amp;lt;tex&amp;gt;&amp;lt;&amp;lt;/tex&amp;gt; a.heapSize     &amp;lt;font color = &amp;quot;green&amp;quot;&amp;gt;// heapSize {{---}} количество элементов в куче&amp;lt;/font&amp;gt;&lt;br /&gt;
         left = 2 * i + 1             &amp;lt;font color = &amp;quot;green&amp;quot;&amp;gt;// left {{---}} левый сын&amp;lt;/font&amp;gt;&lt;br /&gt;
         right = 2 * i + 2            &amp;lt;font color = &amp;quot;green&amp;quot;&amp;gt;// right {{---}} правый сын&amp;lt;/font&amp;gt;&lt;br /&gt;
         j = left&lt;br /&gt;
         '''if''' right &amp;lt;tex&amp;gt;&amp;lt;&amp;lt;/tex&amp;gt; a.heapSize '''and''' a[right] &amp;lt;tex&amp;gt;&amp;lt;&amp;lt;/tex&amp;gt; A[left]&lt;br /&gt;
             j = right&lt;br /&gt;
         '''if''' a[i] &amp;lt;tex&amp;gt;\leqslant&amp;lt;/tex&amp;gt; a[j]&lt;br /&gt;
             '''break'''&lt;br /&gt;
         swap(a[i], a[j])&lt;br /&gt;
         i = j&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====siftUp====&lt;br /&gt;
Если значение измененного элемента уменьшается, то свойства кучи восстанавливаются функцией &amp;lt;tex&amp;gt; \mathrm {siftUp} &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Работа процедуры: если элемент больше своего отца, условие 1 соблюдено для всего дерева, и больше ничего делать не нужно. Иначе, мы меняем местами его с отцом. После чего выполняем &amp;lt;tex&amp;gt; \mathrm {siftUp} &amp;lt;/tex&amp;gt;&lt;br /&gt;
для этого отца. Иными словами, слишком маленький элемент всплывает наверх.&lt;br /&gt;
Процедура выполняется за время &amp;lt;tex&amp;gt;O(\log{n})&amp;lt;/tex&amp;gt;. &lt;br /&gt;
&amp;lt;code style=&amp;quot;display:inline-block&amp;quot;&amp;gt;&lt;br /&gt;
 '''function''' siftUp(i : '''int'''):&lt;br /&gt;
     '''while''' a[i] &amp;lt;tex&amp;gt;&amp;lt;&amp;lt;/tex&amp;gt; a[(i - 1) / 2]     &amp;lt;font color = &amp;quot;green&amp;quot;&amp;gt;// i &amp;lt;tex&amp;gt;==&amp;lt;/tex&amp;gt; 0 {{---}} мы в корне&amp;lt;/font&amp;gt;&lt;br /&gt;
         swap(a[i], a[(i - 1) / 2])&lt;br /&gt;
         i = (i - 1) / 2&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Извлечение минимального элемента===&lt;br /&gt;
&lt;br /&gt;
Выполняет извлечение минимального элемента из кучи за время &amp;lt;tex&amp;gt;O(\log{n})&amp;lt;/tex&amp;gt;.&lt;br /&gt;
Извлечение выполняется в четыре этапа:&lt;br /&gt;
# Значение корневого элемента (он и является минимальным) сохраняется для последующего возврата.&lt;br /&gt;
# Последний элемент копируется в корень, после чего удаляется из кучи.&lt;br /&gt;
# Вызывается &amp;lt;math&amp;gt; \mathrm {siftDown} &amp;lt;/math&amp;gt; для корня.&lt;br /&gt;
# Сохранённый элемент возвращается.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code style=&amp;quot;display:inline-block&amp;quot;&amp;gt;&lt;br /&gt;
 '''int''' extractMin():&lt;br /&gt;
     '''int''' min = a[0]&lt;br /&gt;
     a[0] = a[a.heapSize - 1]&lt;br /&gt;
     a.heapSize = a.heapSize - 1&lt;br /&gt;
     siftDown(0)&lt;br /&gt;
     '''return''' min&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Добавление нового элемента===&lt;br /&gt;
&lt;br /&gt;
Выполняет добавление элемента в кучу за время &amp;lt;tex&amp;gt;O(\log{n})&amp;lt;/tex&amp;gt;.&lt;br /&gt;
Добавление произвольного элемента в конец кучи, и восстановление свойства упорядоченности с помощью процедуры &amp;lt;math&amp;gt; \mathrm {siftUp} &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code style=&amp;quot;display:inline-block&amp;quot;&amp;gt;&lt;br /&gt;
 '''function''' insert(key : '''int'''):&lt;br /&gt;
     a.heapSize = a.heapSize + 1&lt;br /&gt;
     a[a.heapSize - 1] = key&lt;br /&gt;
     siftUp(a.heapSize - 1)&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Построение кучи за O(n) ===&lt;br /&gt;
{{Определение | definition =&lt;br /&gt;
'''&amp;lt;tex&amp;gt;D&amp;lt;/tex&amp;gt;-куча''' {{---}} это куча, в которой у каждого элемента, кроме, возможно, элементов на последнем уровне, ровно &amp;lt;tex&amp;gt;d&amp;lt;/tex&amp;gt; потомков. &lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Дан массив &amp;lt;tex&amp;gt;a[0.. n - 1].&amp;lt;/tex&amp;gt; Требуется построить &amp;lt;tex&amp;gt;d&amp;lt;/tex&amp;gt;-кучу с минимумом в корне. Наиболее очевидный способ построить такую кучу из неупорядоченного массива {{---}} сделать нулевой элемент массива корнем, а дальше по очереди добавить все его элементы в конец кучи и запускать от каждого добавленного элемента &amp;lt;math&amp;gt;\mathrm {siftUp}&amp;lt;/math&amp;gt;. Временная оценка такого алгоритма &amp;lt;tex&amp;gt; O(n\log{n})&amp;lt;/tex&amp;gt;. Однако можно построить кучу еще быстрее — за &amp;lt;tex&amp;gt; O(n) &amp;lt;/tex&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Представим, что в массиве хранится дерево (&amp;lt;tex&amp;gt;a[0] - &amp;lt;/tex&amp;gt;  корень, а потомками элемента &amp;lt;tex&amp;gt;a[i]&amp;lt;/tex&amp;gt; являются &amp;lt;tex&amp;gt;a[2i+1]...a[2i+d]&amp;lt;/tex&amp;gt;). Сделаем &amp;lt;tex&amp;gt; \mathrm {siftDown} &amp;lt;/tex&amp;gt; для вершин, имеющих хотя бы одного потомка: от &amp;lt;tex dpi=140&amp;gt;\genfrac {}{}{}{}{n}{d}&amp;lt;/tex&amp;gt; до &amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;,{{---}} так как поддеревья, состоящие из одной вершины без потомков, уже упорядочены.&lt;br /&gt;
{{Лемма&lt;br /&gt;
|statement= На выходе получим искомую кучу. &lt;br /&gt;
|proof= При вызове &amp;lt;tex&amp;gt; \mathrm {siftDown} &amp;lt;/tex&amp;gt; для вершины, ее поддеревья являются кучами. После выполнения &amp;lt;tex&amp;gt; \mathrm {siftDown} &amp;lt;/tex&amp;gt; эта вершина с ее поддеревьями будут также являться кучей.  Значит, после выполнения всех &amp;lt;tex&amp;gt; \mathrm {siftDown} &amp;lt;/tex&amp;gt; получится куча.&lt;br /&gt;
}}&lt;br /&gt;
{{Лемма&lt;br /&gt;
|statement= Время работы этого алгоритма &amp;lt;tex&amp;gt; O(n) &amp;lt;/tex&amp;gt;.&lt;br /&gt;
|proof= Число вершин на высоте &amp;lt;tex&amp;gt;h&amp;lt;/tex&amp;gt; в куче из &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt; элементов не превосходит &amp;lt;tex dpi = &amp;quot;160&amp;quot;&amp;gt;  \left \lceil \frac{n}{d^h} \right \rceil &amp;lt;/tex&amp;gt;.  Высота кучи не превосходит &amp;lt;tex&amp;gt; \log_{d}n &amp;lt;/tex&amp;gt;. Обозначим за &amp;lt;tex&amp;gt; H &amp;lt;/tex&amp;gt; высоту дерева, тогда время построения не превосходит&lt;br /&gt;
 &lt;br /&gt;
&amp;lt;tex dpi = &amp;quot;160&amp;quot;&amp;gt; \sum_{h = 1}^H  \limits\frac{n}{d^h} \cdot d &amp;lt;/tex&amp;gt; &amp;lt;tex dpi = &amp;quot;150&amp;quot;&amp;gt;  \cdot  h &amp;lt;/tex&amp;gt; &amp;lt;tex  dpi = &amp;quot;160&amp;quot;&amp;gt; = n \cdot d \cdot {\sum_{h = 1}^H  \limits}\frac{h}{d^h}. &amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Докажем вспомогательную лемму о сумме ряда.&lt;br /&gt;
&lt;br /&gt;
{{Лемма&lt;br /&gt;
|statement= &amp;lt;tex dpi = &amp;quot;160&amp;quot;&amp;gt; {\sum_{h = 1}^\infty  \limits}\frac{h}{d^h} = \frac{d}{(d - 1)^2} . &amp;lt;/tex&amp;gt; &lt;br /&gt;
|proof=&lt;br /&gt;
 Обозначим за &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; сумму ряда. Заметим, что&lt;br /&gt;
&amp;lt;tex dpi = &amp;quot;160&amp;quot;&amp;gt; \frac{n}{d^n} = \frac{1}{d} \cdot \frac{n - 1}{d ^{n - 1}} + \frac{1}{d^n}. &amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex dpi = &amp;quot;160&amp;quot;&amp;gt;{\sum_{n = 1}^\infty  \limits}\frac{1}{d^n}&amp;lt;/tex&amp;gt; {{---}} это сумма бесконечной убывающей геометрической прогрессии, и она равна &amp;lt;tex dpi = &amp;quot;160&amp;quot;&amp;gt; &lt;br /&gt;
\frac{\frac{1}{d}}{1 - \frac{1}{d}} = \frac{1}{d - 1}. &amp;lt;/tex&amp;gt; &lt;br /&gt;
&lt;br /&gt;
Получаем  &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; &amp;lt;tex dpi = &amp;quot;160&amp;quot; &amp;gt;=\frac{1}{d}&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;\cdot s +&amp;lt;/tex&amp;gt;  &amp;lt;tex dpi = &amp;quot;160&amp;quot; &amp;gt; \frac{1}{d - 1}. &amp;lt;/tex&amp;gt; Откуда &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; &amp;lt;tex dpi = &amp;quot;160&amp;quot;&amp;gt;  = \frac{d}{(d - 1)^2}. &amp;lt;/tex&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Подставляя в нашу формулу результат леммы, получаем &amp;lt;tex &amp;gt;n&amp;lt;/tex&amp;gt; &amp;lt;tex dpi = &amp;quot;160&amp;quot;&amp;gt;\cdot (\frac {d}{d - 1})^2 &amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;  \leqslant  4 \cdot n &amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;=O(n).&amp;lt;/tex&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code style=&amp;quot;display:inline-block&amp;quot;&amp;gt;&lt;br /&gt;
 '''function''' heapify():&lt;br /&gt;
     '''for''' i = a.heapSize / 2 '''downto''' 0&lt;br /&gt;
         siftDown(i)&lt;br /&gt;
&amp;lt;/code&amp;gt; &lt;br /&gt;
===Слияние двух куч===&lt;br /&gt;
Даны две кучи &amp;lt;tex&amp;gt;a&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt;, размерами &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt;, требуется объединить эти две кучи. &lt;br /&gt;
====Наивная реализация====&lt;br /&gt;
Поочередно добавим все элементы из &amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt; в &amp;lt;tex&amp;gt;a&amp;lt;/tex&amp;gt;. Время работы {{---}} &amp;lt;tex&amp;gt;O(m \log(n+m))&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&amp;lt;code style=&amp;quot;display:inline-block&amp;quot;&amp;gt;&lt;br /&gt;
 '''function''' merge(a, b : '''Heap'''):&lt;br /&gt;
     '''while''' b.heapSize &amp;lt;tex&amp;gt;\neq&amp;lt;/tex&amp;gt; 0  &lt;br /&gt;
         a.insert(b.extractMin())&lt;br /&gt;
&amp;lt;/code&amp;gt; &lt;br /&gt;
====Реализация с помощью построения кучи====&lt;br /&gt;
Добавим все элементы кучи &amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt; в конец массива &amp;lt;tex&amp;gt;a&amp;lt;/tex&amp;gt;, после чего вызовем функцию построения кучи. Процедура выполняется за время &amp;lt;tex&amp;gt;O(n + m)&amp;lt;/tex&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code style=&amp;quot;display:inline-block&amp;quot;&amp;gt;&lt;br /&gt;
 '''function''' merge(a, b : '''Heap'''):&lt;br /&gt;
     '''for''' i = 0 '''to''' b.heapSize - 1  &lt;br /&gt;
         a.heapSize = a.heapSize + 1&lt;br /&gt;
         a[a.heapSize - 1] = b[i]&lt;br /&gt;
     heapify(a)&lt;br /&gt;
&amp;lt;/code&amp;gt; &lt;br /&gt;
&lt;br /&gt;
===Поиск k-ого элемента===&lt;br /&gt;
Требуется найти &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt;-ый по величине элемент в куче.&lt;br /&gt;
&lt;br /&gt;
# Создаем новую кучу, в которой будем хранить пару &amp;lt;tex&amp;gt;\langle \mathtt{value}, \mathtt{index} \rangle&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;\mathtt{value}&amp;lt;/tex&amp;gt; {{---}} значение элемента, а &amp;lt;tex&amp;gt;\mathtt{index}&amp;lt;/tex&amp;gt; {{---}} индекс элемента в основном массиве, и добавляем в нее корень кучи. &lt;br /&gt;
# Возьмем корень новой кучи и добавим её детей из основной кучи, после чего удалим корень. Проделаем этот шаг &amp;lt;tex&amp;gt;k - 1&amp;lt;/tex&amp;gt; раз.&lt;br /&gt;
# В корне новой кучи будет находиться ответ.&lt;br /&gt;
&lt;br /&gt;
[[Файл:Min_heap_kth.png‎|thumb|center|650px|Пример при &amp;lt;tex&amp;gt;k = 5&amp;lt;/tex&amp;gt;, красные {{---}} уже удаленные из кучи элементы, зеленые находятся в куче, а голубые {{---}} еще не рассмотрены.]]&lt;br /&gt;
&lt;br /&gt;
== См. также ==&lt;br /&gt;
* [[Биномиальная куча]]&lt;br /&gt;
* [[Фибоначчиева куча]]&lt;br /&gt;
* [[Левосторонняя куча]]&lt;br /&gt;
&lt;br /&gt;
== Источники информации ==&lt;br /&gt;
* [[wikipedia:ru:Двоичная куча|Википедия {{---}} Двоичная куча]]&lt;br /&gt;
* [[wikipedia:ru:Очередь с приоритетом|Википедия {{---}} Очередь с приоритетом]]&lt;br /&gt;
* [[wikipedia:en:Binary heap|Wikipedia {{---}} Binary heap]]&lt;br /&gt;
* [[wikipedia:en:Priority queue|Wikipedia {{---}} Priority queue]]&lt;br /&gt;
&lt;br /&gt;
[[Категория: Дискретная математика и алгоритмы]]&lt;br /&gt;
[[Категория: Приоритетные очереди]]&lt;br /&gt;
[[Категория: Структуры данных]]&lt;/div&gt;</summary>
		<author><name>Ильнар</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%94%D0%B2%D0%BE%D0%B8%D1%87%D0%BD%D0%B0%D1%8F_%D0%BA%D1%83%D1%87%D0%B0&amp;diff=47675</id>
		<title>Двоичная куча</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%94%D0%B2%D0%BE%D0%B8%D1%87%D0%BD%D0%B0%D1%8F_%D0%BA%D1%83%D1%87%D0%B0&amp;diff=47675"/>
				<updated>2015-06-05T19:24:09Z</updated>
		
		<summary type="html">&lt;p&gt;Ильнар: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Определение==&lt;br /&gt;
{{Определение&lt;br /&gt;
|definition=&lt;br /&gt;
'''Двоичная куча''' или '''пирамида''' (англ. ''Binary heap'') — такое двоичное [[Дерево, эквивалентные определения|подвешенное дерево]], для которого выполнены следующие три условия:&lt;br /&gt;
&lt;br /&gt;
* Значение в любой вершине не меньше, (если куча для максимума), чем значения её потомков.&lt;br /&gt;
* На &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt;-ом слое &amp;lt;tex&amp;gt;2^i&amp;lt;/tex&amp;gt; вершин, кроме последнего. Слои нумеруются с нуля.&lt;br /&gt;
* Последний слой заполнен слева направо (как показано на рисунке)&lt;br /&gt;
}}&lt;br /&gt;
[[Файл:Min_heap.png‎|thumb|325px|Пример кучи для минимума]]&lt;br /&gt;
[[Файл:Min_heap_array.png‎|thumb|325px|Хранение кучи в массиве, красная стрелка {{---}} левый сын, зеленая {{---}} правый]]&lt;br /&gt;
Удобнее всего двоичную кучу хранить в виде массива &amp;lt;tex&amp;gt;a[0..n-1]&amp;lt;/tex&amp;gt;, у которого нулевой элемент, &amp;lt;tex&amp;gt;a[0]&amp;lt;/tex&amp;gt; — элемент в корне, а потомками элемента &amp;lt;tex&amp;gt;a[i]&amp;lt;/tex&amp;gt; являются &amp;lt;tex&amp;gt;a[2i+1]&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;a[2i+2]&amp;lt;/tex&amp;gt;. Высота кучи определяется как высота двоичного дерева. То есть она равна количеству рёбер в самом длинном простом пути, соединяющем корень кучи с одним из её листьев. Высота кучи есть &amp;lt;tex&amp;gt;O(\log{n})&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt; — количество узлов дерева.&lt;br /&gt;
&lt;br /&gt;
Чаще всего используют кучи для минимума (когда предок не больше детей) и для максимума (когда предок не меньше детей).&lt;br /&gt;
&lt;br /&gt;
Двоичные кучи используют, например, для того, чтобы извлекать минимум из набора чисел за &amp;lt;tex&amp;gt;O(\log{n})&amp;lt;/tex&amp;gt;. Они являются частным случаем приоритетных очередей.&lt;br /&gt;
&lt;br /&gt;
==Базовые процедуры==&lt;br /&gt;
&lt;br /&gt;
===Восстановление свойств кучи===&lt;br /&gt;
&lt;br /&gt;
Если в куче изменяется один из элементов, то она может перестать удовлетворять свойству упорядоченности. Для восстановления этого свойства служат процедуры &amp;lt;tex&amp;gt; \mathrm {siftDown} &amp;lt;/tex&amp;gt; (просеивание вниз)&lt;br /&gt;
и &amp;lt;tex&amp;gt; \mathrm {siftUp} &amp;lt;/tex&amp;gt; (просеивание вверх). &lt;br /&gt;
Если значение измененного элемента увеличивается, то свойства кучи восстанавливаются функцией &amp;lt;tex&amp;gt; \mathrm {siftDown} &amp;lt;/tex&amp;gt;.&lt;br /&gt;
Работа процедуры: если &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt;-й элемент меньше, чем его сыновья, всё поддерево уже является кучей, и делать ничего не надо. В противном случае меняем местами &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt;-й элемент с наименьшим из его сыновей, после чего выполняем &amp;lt;tex&amp;gt; \mathrm {siftDown} &amp;lt;/tex&amp;gt; для этого сына.&lt;br /&gt;
Процедура выполняется за время &amp;lt;tex&amp;gt;O(\log{n})&amp;lt;/tex&amp;gt;.&lt;br /&gt;
====siftDown====&lt;br /&gt;
&amp;lt;code style=&amp;quot;display:inline-block&amp;quot;&amp;gt;&lt;br /&gt;
 '''function''' siftDown(i : '''int'''):&lt;br /&gt;
     '''while''' 2 * i + 1 &amp;lt;tex&amp;gt;&amp;lt;&amp;lt;/tex&amp;gt; a.heapSize     &amp;lt;font color = &amp;quot;green&amp;quot;&amp;gt;// heapSize {{---}} количество элементов в куче&amp;lt;/font&amp;gt;&lt;br /&gt;
         left = 2 * i + 1             &amp;lt;font color = &amp;quot;green&amp;quot;&amp;gt;// left {{---}} левый сын&amp;lt;/font&amp;gt;&lt;br /&gt;
         right = 2 * i + 2            &amp;lt;font color = &amp;quot;green&amp;quot;&amp;gt;// right {{---}} правый сын&amp;lt;/font&amp;gt;&lt;br /&gt;
         j = left&lt;br /&gt;
         '''if''' right &amp;lt;tex&amp;gt;&amp;lt;&amp;lt;/tex&amp;gt; a.heapSize '''and''' a[right] &amp;lt;tex&amp;gt;&amp;lt;&amp;lt;/tex&amp;gt; A[left]&lt;br /&gt;
             j = right&lt;br /&gt;
         '''if''' a[i] &amp;lt;tex&amp;gt;\leqslant&amp;lt;/tex&amp;gt; a[j]&lt;br /&gt;
             '''break'''&lt;br /&gt;
         swap(a[i], a[j])&lt;br /&gt;
         i = j&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====siftUp====&lt;br /&gt;
Если значение измененного элемента уменьшается, то свойства кучи восстанавливаются функцией &amp;lt;tex&amp;gt; \mathrm {siftUp} &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Работа процедуры: если элемент больше своего отца, условие 1 соблюдено для всего дерева, и больше ничего делать не нужно. Иначе, мы меняем местами его с отцом. После чего выполняем &amp;lt;tex&amp;gt; \mathrm {siftUp} &amp;lt;/tex&amp;gt;&lt;br /&gt;
для этого отца. Иными словами, слишком маленький элемент всплывает наверх.&lt;br /&gt;
Процедура выполняется за время &amp;lt;tex&amp;gt;O(\log{n})&amp;lt;/tex&amp;gt;. &lt;br /&gt;
&amp;lt;code style=&amp;quot;display:inline-block&amp;quot;&amp;gt;&lt;br /&gt;
 '''function''' siftUp(i : '''int'''):&lt;br /&gt;
     '''while''' a[i] &amp;lt;tex&amp;gt;&amp;lt;&amp;lt;/tex&amp;gt; a[(i - 1) / 2]     &amp;lt;font color = &amp;quot;green&amp;quot;&amp;gt;// i &amp;lt;tex&amp;gt;==&amp;lt;/tex&amp;gt; 0 {{---}} мы в корне&amp;lt;/font&amp;gt;&lt;br /&gt;
         swap(a[i], a[(i - 1) / 2])&lt;br /&gt;
         i = (i - 1) / 2&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Извлечение минимального элемента===&lt;br /&gt;
&lt;br /&gt;
Выполняет извлечение минимального элемента из кучи за время &amp;lt;tex&amp;gt;O(\log{n})&amp;lt;/tex&amp;gt;.&lt;br /&gt;
Извлечение выполняется в четыре этапа:&lt;br /&gt;
# Значение корневого элемента (он и является минимальным) сохраняется для последующего возврата.&lt;br /&gt;
# Последний элемент копируется в корень, после чего удаляется из кучи.&lt;br /&gt;
# Вызывается &amp;lt;math&amp;gt; \mathrm {siftDown} &amp;lt;/math&amp;gt; для корня.&lt;br /&gt;
# Сохранённый элемент возвращается.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code style=&amp;quot;display:inline-block&amp;quot;&amp;gt;&lt;br /&gt;
 '''int''' extractMin():&lt;br /&gt;
     '''int''' min = a[0]&lt;br /&gt;
     a[0] = a[a.heapSize - 1]&lt;br /&gt;
     a.heapSize = a.heapSize - 1&lt;br /&gt;
     siftDown(0)&lt;br /&gt;
     '''return''' min&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Добавление нового элемента===&lt;br /&gt;
&lt;br /&gt;
Выполняет добавление элемента в кучу за время &amp;lt;tex&amp;gt;O(\log{n})&amp;lt;/tex&amp;gt;.&lt;br /&gt;
Добавление произвольного элемента в конец кучи, и восстановление свойства упорядоченности с помощью процедуры &amp;lt;math&amp;gt; \mathrm {siftUp} &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code style=&amp;quot;display:inline-block&amp;quot;&amp;gt;&lt;br /&gt;
 '''function''' insert(key : '''int'''):&lt;br /&gt;
     a.heapSize = a.heapSize + 1&lt;br /&gt;
     a[a.heapSize - 1] = key&lt;br /&gt;
     siftUp(a.heapSize - 1)&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Построение кучи за O(n) ==&lt;br /&gt;
{{Определение | definition =&lt;br /&gt;
'''&amp;lt;tex&amp;gt;D&amp;lt;/tex&amp;gt;-куча''' {{---}} это куча, в которой у каждого элемента, кроме, возможно, элементов на последнем уровне, ровно &amp;lt;tex&amp;gt;d&amp;lt;/tex&amp;gt; потомков. &lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Дан массив &amp;lt;tex&amp;gt;a[0.. n - 1].&amp;lt;/tex&amp;gt; Требуется построить &amp;lt;tex&amp;gt;d&amp;lt;/tex&amp;gt;-кучу с минимумом в корне. Наиболее очевидный способ построить такую кучу из неупорядоченного массива {{---}} сделать нулевой элемент массива корнем, а дальше по очереди добавить все его элементы в конец кучи и запускать от каждого добавленного элемента &amp;lt;math&amp;gt;\mathrm {siftUp}&amp;lt;/math&amp;gt;. Временная оценка такого алгоритма &amp;lt;tex&amp;gt; O(n\log{n})&amp;lt;/tex&amp;gt;. Однако можно построить кучу еще быстрее — за &amp;lt;tex&amp;gt; O(n) &amp;lt;/tex&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Представим, что в массиве хранится дерево (&amp;lt;tex&amp;gt;a[0] - &amp;lt;/tex&amp;gt;  корень, а потомками элемента &amp;lt;tex&amp;gt;a[i]&amp;lt;/tex&amp;gt; являются &amp;lt;tex&amp;gt;a[2i+1]...a[2i+d]&amp;lt;/tex&amp;gt;). Сделаем &amp;lt;tex&amp;gt; \mathrm {siftDown} &amp;lt;/tex&amp;gt; для вершин, имеющих хотя бы одного потомка: от &amp;lt;tex dpi=140&amp;gt;\genfrac {}{}{}{}{n}{d}&amp;lt;/tex&amp;gt; до &amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;,{{---}} так как поддеревья, состоящие из одной вершины без потомков, уже упорядочены.&lt;br /&gt;
{{Лемма&lt;br /&gt;
|statement= На выходе получим искомую кучу. &lt;br /&gt;
|proof= При вызове &amp;lt;tex&amp;gt; \mathrm {siftDown} &amp;lt;/tex&amp;gt; для вершины, ее поддеревья являются кучами. После выполнения &amp;lt;tex&amp;gt; \mathrm {siftDown} &amp;lt;/tex&amp;gt; эта вершина с ее поддеревьями будут также являться кучей.  Значит, после выполнения всех &amp;lt;tex&amp;gt; \mathrm {siftDown} &amp;lt;/tex&amp;gt; получится куча.&lt;br /&gt;
}}&lt;br /&gt;
{{Лемма&lt;br /&gt;
|statement= Время работы этого алгоритма &amp;lt;tex&amp;gt; O(n) &amp;lt;/tex&amp;gt;.&lt;br /&gt;
|proof= Число вершин на высоте &amp;lt;tex&amp;gt;h&amp;lt;/tex&amp;gt; в куче из &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt; элементов не превосходит &amp;lt;tex dpi = &amp;quot;160&amp;quot;&amp;gt;  \left \lceil \frac{n}{d^h} \right \rceil &amp;lt;/tex&amp;gt;.  Высота кучи не превосходит &amp;lt;tex&amp;gt; \log_{d}n &amp;lt;/tex&amp;gt;. Обозначим за &amp;lt;tex&amp;gt; H &amp;lt;/tex&amp;gt; высоту дерева, тогда время построения не превосходит&lt;br /&gt;
 &lt;br /&gt;
&amp;lt;tex dpi = &amp;quot;160&amp;quot;&amp;gt; \sum_{h = 1}^H  \limits\frac{n}{d^h} \cdot d &amp;lt;/tex&amp;gt; &amp;lt;tex dpi = &amp;quot;150&amp;quot;&amp;gt;  \cdot  h &amp;lt;/tex&amp;gt; &amp;lt;tex  dpi = &amp;quot;160&amp;quot;&amp;gt; = n \cdot d \cdot {\sum_{h = 1}^H  \limits}\frac{h}{d^h}. &amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Докажем вспомогательную лемму о сумме ряда.&lt;br /&gt;
&lt;br /&gt;
{{Лемма&lt;br /&gt;
|statement= &amp;lt;tex dpi = &amp;quot;160&amp;quot;&amp;gt; {\sum_{h = 1}^\infty  \limits}\frac{h}{d^h} = \frac{d}{(d - 1)^2} . &amp;lt;/tex&amp;gt; &lt;br /&gt;
|proof=&lt;br /&gt;
 Обозначим за &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; сумму ряда. Заметим, что&lt;br /&gt;
&amp;lt;tex dpi = &amp;quot;160&amp;quot;&amp;gt; \frac{n}{d^n} = \frac{1}{d} \cdot \frac{n - 1}{d ^{n - 1}} + \frac{1}{d^n}. &amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex dpi = &amp;quot;160&amp;quot;&amp;gt;{\sum_{n = 1}^\infty  \limits}\frac{1}{d^n}&amp;lt;/tex&amp;gt; {{---}} это сумма бесконечной убывающей геометрической прогрессии, и она равна &amp;lt;tex dpi = &amp;quot;160&amp;quot;&amp;gt; &lt;br /&gt;
\frac{\frac{1}{d}}{1 - \frac{1}{d}} = \frac{1}{d - 1}. &amp;lt;/tex&amp;gt; &lt;br /&gt;
&lt;br /&gt;
Получаем  &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; &amp;lt;tex dpi = &amp;quot;160&amp;quot; &amp;gt;=\frac{1}{d}&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;\cdot s +&amp;lt;/tex&amp;gt;  &amp;lt;tex dpi = &amp;quot;160&amp;quot; &amp;gt; \frac{1}{d - 1}. &amp;lt;/tex&amp;gt; Откуда &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; &amp;lt;tex dpi = &amp;quot;160&amp;quot;&amp;gt;  = \frac{d}{(d - 1)^2}. &amp;lt;/tex&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Подставляя в нашу формулу результат леммы, получаем &amp;lt;tex &amp;gt;n&amp;lt;/tex&amp;gt; &amp;lt;tex dpi = &amp;quot;160&amp;quot;&amp;gt;\cdot (\frac {d}{d - 1})^2 &amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;  \leqslant  4 \cdot n &amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;=O(n).&amp;lt;/tex&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
==Слияние двух куч==&lt;br /&gt;
Даны две кучи &amp;lt;tex&amp;gt;a&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt;, требуется объединить эти две кучи. &lt;br /&gt;
&lt;br /&gt;
Добавим все элементы кучи &amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt; в конец массива &amp;lt;tex&amp;gt;a&amp;lt;/tex&amp;gt;, после чего вызовем функцию построения кучи. Процедура выполняется за время &amp;lt;tex&amp;gt;O(a.heapSize + b.heapSize)&amp;lt;/tex&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code style=&amp;quot;display:inline-block&amp;quot;&amp;gt;&lt;br /&gt;
 '''function''' merge(a, b : '''heap'''):&lt;br /&gt;
     '''for''' i = 0 '''to''' b.heapSize - 1  &lt;br /&gt;
         a.heapSize = a.heapSize + 1&lt;br /&gt;
         a[a.heapSize - 1] = b[i]&lt;br /&gt;
     heapify(a)&lt;br /&gt;
&amp;lt;/code&amp;gt; &lt;br /&gt;
&lt;br /&gt;
==Поиск k-ого элемента==&lt;br /&gt;
Требуется найти &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt;-ый по величине элемент в куче.&lt;br /&gt;
&lt;br /&gt;
# Создаем новую кучу, в которой будем хранить пару &amp;lt;tex&amp;gt;\langle value, index \rangle&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;value&amp;lt;/tex&amp;gt; {{---}} значение элемента, а &amp;lt;tex&amp;gt;index&amp;lt;/tex&amp;gt; {{---}} индекс элемента в основном массиве, и добавляем в нее корень кучи. &lt;br /&gt;
# Возьмем корень новой кучи и добавим её детей из основной кучи, после чего удалим корень. Проделаем этот шаг &amp;lt;tex&amp;gt;k - 1&amp;lt;/tex&amp;gt; раз.&lt;br /&gt;
# В корне новой кучи будет находиться ответ.&lt;br /&gt;
&lt;br /&gt;
[[Файл:Min_heap_kth.png‎|thumb|center|650px|Пример при &amp;lt;tex&amp;gt;k = 5&amp;lt;/tex&amp;gt;, красные {{---}} уже удаленные из кучи элементы, зеленые находятся в куче, а голубые {{---}} еще не рассмотрены.]]&lt;br /&gt;
&lt;br /&gt;
== См. также ==&lt;br /&gt;
* [[Биномиальная куча]]&lt;br /&gt;
* [[Фибоначчиева куча]]&lt;br /&gt;
* [[Левосторонняя куча]]&lt;br /&gt;
&lt;br /&gt;
== Источники информации ==&lt;br /&gt;
* [[wikipedia:ru:Двоичная куча|Википедия {{---}} Двоичная куча]]&lt;br /&gt;
* [[wikipedia:ru:Очередь с приоритетом|Википедия {{---}} Очередь с приоритетом]]&lt;br /&gt;
* [[wikipedia:en:Binary heap|Wikipedia {{---}} Binary heap]]&lt;br /&gt;
* [[wikipedia:en:Priority queue|Wikipedia {{---}} Priority queue]]&lt;br /&gt;
&lt;br /&gt;
[[Категория: Дискретная математика и алгоритмы]]&lt;br /&gt;
[[Категория: Приоритетные очереди]]&lt;/div&gt;</summary>
		<author><name>Ильнар</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:Min_heap_kth.png&amp;diff=47667</id>
		<title>Файл:Min heap kth.png</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:Min_heap_kth.png&amp;diff=47667"/>
				<updated>2015-06-05T19:13:47Z</updated>
		
		<summary type="html">&lt;p&gt;Ильнар: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Ильнар</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:Min_heap_array.png&amp;diff=47658</id>
		<title>Файл:Min heap array.png</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:Min_heap_array.png&amp;diff=47658"/>
				<updated>2015-06-05T18:26:42Z</updated>
		
		<summary type="html">&lt;p&gt;Ильнар: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Ильнар</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:Min_heap.png&amp;diff=47656</id>
		<title>Файл:Min heap.png</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:Min_heap.png&amp;diff=47656"/>
				<updated>2015-06-05T18:23:28Z</updated>
		
		<summary type="html">&lt;p&gt;Ильнар: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Ильнар</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%94%D0%B2%D0%BE%D0%B8%D1%87%D0%BD%D0%B0%D1%8F_%D0%BA%D1%83%D1%87%D0%B0&amp;diff=47592</id>
		<title>Двоичная куча</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%94%D0%B2%D0%BE%D0%B8%D1%87%D0%BD%D0%B0%D1%8F_%D0%BA%D1%83%D1%87%D0%B0&amp;diff=47592"/>
				<updated>2015-06-05T14:08:45Z</updated>
		
		<summary type="html">&lt;p&gt;Ильнар: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Определение==&lt;br /&gt;
&lt;br /&gt;
{{Определение&lt;br /&gt;
|definition=&lt;br /&gt;
'''Двоичная куча''' или '''пирамида''' (англ. ''Binary heap'') — такое двоичное [[Дерево, эквивалентные определения|подвешенное дерево]], для которого выполнены следующие три условия:&lt;br /&gt;
&lt;br /&gt;
* Значение в любой вершине не меньше, (если куча для максимума), чем значения её потомков.&lt;br /&gt;
* На &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt;-ом слое &amp;lt;tex&amp;gt;2^i&amp;lt;/tex&amp;gt; вершин, кроме последнего. Слои нумеруются с нуля.&lt;br /&gt;
* Последний слой заполнен слева направо (как показано на рисунке)&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
[[Файл:Heap.png|thumb|325px|Пример кучи для максимума]]&lt;br /&gt;
&lt;br /&gt;
Удобнее всего двоичную кучу хранить в виде массива &amp;lt;tex&amp;gt;a[0..n-1]&amp;lt;/tex&amp;gt;, у которого нулевой элемент, &amp;lt;tex&amp;gt;a[0]&amp;lt;/tex&amp;gt; — элемент в корне, а потомками элемента &amp;lt;tex&amp;gt;a[i]&amp;lt;/tex&amp;gt; являются &amp;lt;tex&amp;gt;a[2i+1]&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;a[2i+2]&amp;lt;/tex&amp;gt;. Высота кучи определяется как высота двоичного дерева. То есть она равна количеству рёбер в самом длинном простом пути, соединяющем корень кучи с одним из её листьев. Высота кучи есть &amp;lt;tex&amp;gt;O(\log{n})&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt; — количество узлов дерева.&lt;br /&gt;
&lt;br /&gt;
Чаще всего используют кучи для минимума (когда предок не больше детей) и для максимума (когда предок не меньше детей).&lt;br /&gt;
&lt;br /&gt;
Двоичные кучи используют, например, для того, чтобы извлекать минимум из набора чисел за &amp;lt;tex&amp;gt;O(\log{n})&amp;lt;/tex&amp;gt;. Они являются частным случаем приоритетных очередей.&lt;br /&gt;
&lt;br /&gt;
==Базовые процедуры==&lt;br /&gt;
&lt;br /&gt;
===Восстановление свойств кучи===&lt;br /&gt;
&lt;br /&gt;
Если в куче изменяется один из элементов, то она может перестать удовлетворять свойству упорядоченности. Для восстановления этого свойства служат процедуры &amp;lt;tex&amp;gt; \mathrm {siftDown} &amp;lt;/tex&amp;gt; (просеивание вниз)&lt;br /&gt;
и &amp;lt;tex&amp;gt; \mathrm {siftUp} &amp;lt;/tex&amp;gt; (просеивание вверх). &lt;br /&gt;
Если значение измененного элемента увеличивается, то свойства кучи восстанавливаются функцией &amp;lt;tex&amp;gt; \mathrm {siftDown} &amp;lt;/tex&amp;gt;.&lt;br /&gt;
Работа процедуры: если &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt;-й элемент меньше, чем его сыновья, всё поддерево уже является кучей, и делать ничего не надо. В противном случае меняем местами &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt;-й элемент с наименьшим из его сыновей, после чего выполняем &amp;lt;tex&amp;gt; \mathrm {siftDown} &amp;lt;/tex&amp;gt; для этого сына.&lt;br /&gt;
Процедура выполняется за время &amp;lt;tex&amp;gt;O(\log{n})&amp;lt;/tex&amp;gt;.&lt;br /&gt;
====siftDown====&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 '''function''' siftDown(i : '''int'''):&lt;br /&gt;
     '''while''' 2 * i + 1 &amp;lt;tex&amp;gt;&amp;lt;&amp;lt;/tex&amp;gt; a.heapSize     &amp;lt;font color = &amp;quot;green&amp;quot;&amp;gt;// heapSize {{---}} количество элементов в куче&amp;lt;/font&amp;gt;&lt;br /&gt;
         left = 2 * i + 1             &amp;lt;font color = &amp;quot;green&amp;quot;&amp;gt;// left {{---}} левый сын&amp;lt;/font&amp;gt;&lt;br /&gt;
         right = 2 * i + 2            &amp;lt;font color = &amp;quot;green&amp;quot;&amp;gt;// right {{---}} правый сын&amp;lt;/font&amp;gt;&lt;br /&gt;
         j = left&lt;br /&gt;
         '''if''' right &amp;lt;tex&amp;gt;&amp;lt;&amp;lt;/tex&amp;gt; a.heapSize '''and''' a[right] &amp;lt;tex&amp;gt;&amp;lt;&amp;lt;/tex&amp;gt; A[left]&lt;br /&gt;
             j = right&lt;br /&gt;
         '''if''' a[i] &amp;lt;tex&amp;gt;\leqslant&amp;lt;/tex&amp;gt; a[j]&lt;br /&gt;
             '''break'''&lt;br /&gt;
         swap(a[i], a[j])&lt;br /&gt;
         i = j&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====siftUp====&lt;br /&gt;
Если значение измененного элемента уменьшается, то свойства кучи восстанавливаются функцией &amp;lt;tex&amp;gt; \mathrm {siftUp} &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Работа процедуры: если элемент больше своего отца, условие 1 соблюдено для всего дерева, и больше ничего делать не нужно. Иначе, мы меняем местами его с отцом. После чего выполняем &amp;lt;tex&amp;gt; \mathrm {siftUp} &amp;lt;/tex&amp;gt;&lt;br /&gt;
для этого отца. Иными словами, слишком маленький элемент всплывает наверх.&lt;br /&gt;
Процедура выполняется за время &amp;lt;tex&amp;gt;O(\log{n})&amp;lt;/tex&amp;gt;. &lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 '''function''' siftUp(i : '''int'''):&lt;br /&gt;
     '''while''' a[i] &amp;lt;tex&amp;gt;&amp;lt;&amp;lt;/tex&amp;gt; a[(i - 1) / 2]     &amp;lt;font color = &amp;quot;green&amp;quot;&amp;gt;// i &amp;lt;tex&amp;gt;==&amp;lt;/tex&amp;gt; 0 {{---}} мы в корне&amp;lt;/font&amp;gt;&lt;br /&gt;
         swap(a[i], a[(i - 1) / 2])&lt;br /&gt;
         i = (i - 1) / 2&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Извлечение минимального элемента===&lt;br /&gt;
&lt;br /&gt;
Выполняет извлечение минимального элемента из кучи за время &amp;lt;tex&amp;gt;O(\log{n})&amp;lt;/tex&amp;gt;.&lt;br /&gt;
Извлечение выполняется в четыре этапа:&lt;br /&gt;
# Значение корневого элемента (он и является минимальным) сохраняется для последующего возврата.&lt;br /&gt;
# Последний элемент копируется в корень, после чего удаляется из кучи.&lt;br /&gt;
# Вызывается &amp;lt;math&amp;gt; \mathrm {siftDown} &amp;lt;/math&amp;gt; для корня.&lt;br /&gt;
# Сохранённый элемент возвращается.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 '''int''' extractMin():&lt;br /&gt;
     '''int''' min = a[0]&lt;br /&gt;
     a[0] = a[A.heapSize - 1]&lt;br /&gt;
     a.heapSize = a.heapSize - 1&lt;br /&gt;
     siftDown(0)&lt;br /&gt;
     '''return''' min&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Добавление нового элемента===&lt;br /&gt;
&lt;br /&gt;
Выполняет добавление элемента в кучу за время &amp;lt;tex&amp;gt;O(\log{n})&amp;lt;/tex&amp;gt;.&lt;br /&gt;
Добавление произвольного элемента в конец кучи, и восстановление свойства упорядоченности с помощью процедуры &amp;lt;math&amp;gt; \mathrm {siftUp} &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 '''function''' insert(key : '''int'''):&lt;br /&gt;
     a.heapSize = a.heapSize + 1&lt;br /&gt;
     a[a.heapSize - 1] = key&lt;br /&gt;
     siftUp(a.heapSize - 1)&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Построение кучи за O(n) ==&lt;br /&gt;
{{Определение | definition =&lt;br /&gt;
'''&amp;lt;tex&amp;gt;D&amp;lt;/tex&amp;gt;-куча''' {{---}} это куча, в которой у каждого элемента, кроме, возможно, элементов на последнем уровне, ровно &amp;lt;tex&amp;gt;d&amp;lt;/tex&amp;gt; потомков. &lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Дан массив &amp;lt;tex&amp;gt;a[0.. n - 1].&amp;lt;/tex&amp;gt; Требуется построить &amp;lt;tex&amp;gt;d&amp;lt;/tex&amp;gt;-кучу с минимумом в корне. Наиболее очевидный способ построить такую кучу из неупорядоченного массива {{---}} сделать нулевой элемент массива корнем, а дальше по очереди добавить все его элементы в конец кучи и запускать от каждого добавленного элемента &amp;lt;math&amp;gt;\mathrm {siftUp}&amp;lt;/math&amp;gt;. Временная оценка такого алгоритма &amp;lt;tex&amp;gt; O(n\log{n})&amp;lt;/tex&amp;gt;. Однако можно построить кучу еще быстрее — за &amp;lt;tex&amp;gt; O(n) &amp;lt;/tex&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Представим, что в массиве хранится дерево (&amp;lt;tex&amp;gt;a[0] - &amp;lt;/tex&amp;gt;  корень, а потомками элемента &amp;lt;tex&amp;gt;a[i]&amp;lt;/tex&amp;gt; являются &amp;lt;tex&amp;gt;a[2i+1]...a[2i+d]&amp;lt;/tex&amp;gt;). Сделаем &amp;lt;tex&amp;gt; \mathrm {siftDown} &amp;lt;/tex&amp;gt; для вершин, имеющих хотя бы одного потомка: от &amp;lt;tex dpi=140&amp;gt;\genfrac {}{}{}{}{n}{d}&amp;lt;/tex&amp;gt; до &amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;,{{---}} так как поддеревья, состоящие из одной вершины без потомков, уже упорядочены.&lt;br /&gt;
{{Лемма&lt;br /&gt;
|statement= На выходе получим искомую кучу. &lt;br /&gt;
|proof= При вызове &amp;lt;tex&amp;gt; \mathrm {siftDown} &amp;lt;/tex&amp;gt; для вершины, ее поддеревья являются кучами. После выполнения &amp;lt;tex&amp;gt; \mathrm {siftDown} &amp;lt;/tex&amp;gt; эта вершина с ее поддеревьями будут также являться кучей.  Значит, после выполнения всех &amp;lt;tex&amp;gt; \mathrm {siftDown} &amp;lt;/tex&amp;gt; получится куча.&lt;br /&gt;
}}&lt;br /&gt;
{{Лемма&lt;br /&gt;
|statement= Время работы этого алгоритма &amp;lt;tex&amp;gt; O(n) &amp;lt;/tex&amp;gt;.&lt;br /&gt;
|proof= Число вершин на высоте &amp;lt;tex&amp;gt;h&amp;lt;/tex&amp;gt; в куче из &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt; элементов не превосходит &amp;lt;tex dpi = &amp;quot;160&amp;quot;&amp;gt;  \left \lceil \frac{n}{d^h} \right \rceil &amp;lt;/tex&amp;gt;.  Высота кучи не превосходит &amp;lt;tex&amp;gt; \log_{d}n &amp;lt;/tex&amp;gt;. Обозначим за &amp;lt;tex&amp;gt; H &amp;lt;/tex&amp;gt; высоту дерева, тогда время построения не превосходит&lt;br /&gt;
 &lt;br /&gt;
&amp;lt;tex dpi = &amp;quot;160&amp;quot;&amp;gt; \sum_{h = 1}^H  \limits\frac{n}{d^h} \cdot d &amp;lt;/tex&amp;gt; &amp;lt;tex dpi = &amp;quot;150&amp;quot;&amp;gt;  \cdot  h &amp;lt;/tex&amp;gt; &amp;lt;tex  dpi = &amp;quot;160&amp;quot;&amp;gt; = n \cdot d \cdot {\sum_{h = 1}^H  \limits}\frac{h}{d^h}. &amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Докажем вспомогательную лемму о сумме ряда.&lt;br /&gt;
&lt;br /&gt;
{{Лемма&lt;br /&gt;
|statement= &amp;lt;tex dpi = &amp;quot;160&amp;quot;&amp;gt; {\sum_{h = 1}^\infty  \limits}\frac{h}{d^h} = \frac{d}{(d - 1)^2} . &amp;lt;/tex&amp;gt; &lt;br /&gt;
|proof=&lt;br /&gt;
 Обозначим за &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; сумму ряда. Заметим, что&lt;br /&gt;
&amp;lt;tex dpi = &amp;quot;160&amp;quot;&amp;gt; \frac{n}{d^n} = \frac{1}{d} \cdot \frac{n - 1}{d ^{n - 1}} + \frac{1}{d^n}. &amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex dpi = &amp;quot;160&amp;quot;&amp;gt;{\sum_{n = 1}^\infty  \limits}\frac{1}{d^n}&amp;lt;/tex&amp;gt; {{---}} это сумма бесконечной убывающей геометрической прогрессии, и она равна &amp;lt;tex dpi = &amp;quot;160&amp;quot;&amp;gt; &lt;br /&gt;
\frac{\frac{1}{d}}{1 - \frac{1}{d}} = \frac{1}{d - 1}. &amp;lt;/tex&amp;gt; &lt;br /&gt;
&lt;br /&gt;
Получаем  &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; &amp;lt;tex dpi = &amp;quot;160&amp;quot; &amp;gt;=\frac{1}{d}&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;\cdot s +&amp;lt;/tex&amp;gt;  &amp;lt;tex dpi = &amp;quot;160&amp;quot; &amp;gt; \frac{1}{d - 1}. &amp;lt;/tex&amp;gt; Откуда &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; &amp;lt;tex dpi = &amp;quot;160&amp;quot;&amp;gt;  = \frac{d}{(d - 1)^2}. &amp;lt;/tex&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Подставляя в нашу формулу результат леммы, получаем &amp;lt;tex &amp;gt;n&amp;lt;/tex&amp;gt; &amp;lt;tex dpi = &amp;quot;160&amp;quot;&amp;gt;\cdot (\frac {d}{d - 1})^2 &amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;  \leqslant  4 \cdot n &amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;=O(n).&amp;lt;/tex&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
==Слияние двух куч==&lt;br /&gt;
Даны две кучи &amp;lt;tex&amp;gt;a&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt;, требуется объединить эти две кучи. &lt;br /&gt;
&lt;br /&gt;
Добавим все элементы кучи &amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt; в конец массива &amp;lt;tex&amp;gt;a&amp;lt;/tex&amp;gt;, после чего вызовем функцию построения кучи. Процедура выполняется за время &amp;lt;tex&amp;gt;O(a.heapSize + b.heapSize)&amp;lt;/tex&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 '''function''' merge(a, b : '''heap'''):&lt;br /&gt;
     '''for''' i = 0 '''to''' b.heapSize - 1  &lt;br /&gt;
         a.heapSize = a.heapSize + 1&lt;br /&gt;
         a[a.heapSize - 1] = b[i]&lt;br /&gt;
     heapify(a)&lt;br /&gt;
&amp;lt;/code&amp;gt; &lt;br /&gt;
&lt;br /&gt;
== См. также ==&lt;br /&gt;
* [[Биномиальная куча]]&lt;br /&gt;
* [[Фибоначчиева куча]]&lt;br /&gt;
* [[Левосторонняя куча]]&lt;br /&gt;
&lt;br /&gt;
== Источники информации ==&lt;br /&gt;
* [[wikipedia:ru:Двоичная куча|Википедия {{---}} Двоичная куча]]&lt;br /&gt;
* [[wikipedia:ru:Очередь с приоритетом|Википедия {{---}} Очередь с приоритетом]]&lt;br /&gt;
* [[wikipedia:en:Binary heap|Wikipedia {{---}} Binary heap]]&lt;br /&gt;
* [[wikipedia:en:Priority queue|Wikipedia {{---}} Priority queue]]&lt;br /&gt;
&lt;br /&gt;
[[Категория: Дискретная математика и алгоритмы]]&lt;br /&gt;
[[Категория: Приоритетные очереди]]&lt;/div&gt;</summary>
		<author><name>Ильнар</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%A1%D0%BE%D1%80%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B0&amp;diff=46811</id>
		<title>Сортировка</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%A1%D0%BE%D1%80%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B0&amp;diff=46811"/>
				<updated>2015-05-23T18:27:12Z</updated>
		
		<summary type="html">&lt;p&gt;Ильнар: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;wikitex&amp;gt;&lt;br /&gt;
''Сортировкой'' (англ. ''sorting'') называется процесс упорядочивания множества объектов по какому-либо признаку.&lt;br /&gt;
&lt;br /&gt;
Так как данные могут хранится в разных структурах, то и алгоритмы для каждой структуры могут отличаться. Например, при хранении данных в списке сортировка кучей потребует $O(n^2 \log n)$ времени против $O(n \log n)$ с использованием массива; а вот сортировка пузырьком не изменится.&lt;br /&gt;
&lt;br /&gt;
Также есть алгоритмы параллельной сортировки данных (т.н. [[Сортирующие сети]]), время работы которых в лучшем случае $O(\log n)$. &lt;br /&gt;
== Классификация сортировок ==&lt;br /&gt;
&lt;br /&gt;
=== Время работы ===&lt;br /&gt;
&lt;br /&gt;
Эту классификацию обычно считают самой важной. Оценивают худшее время алгоритма, среднее и лучшее. Лучшее время — минимальное время работы алгоритма на каком-либо наборе, обычно этим набором является тривиальный $\big[ 1 \ldots n \big] $. Худшее время — наибольшее время.&lt;br /&gt;
У большинства алгоритмов временные оценки бывают $O(n \log n)$ и $O(n^2)$.&lt;br /&gt;
&lt;br /&gt;
=== Память ===&lt;br /&gt;
&lt;br /&gt;
Параметр сортировки, показывающий, сколько '''дополнительной''' памяти требуется алгоритму. Сюда входят и дополнительный массив, и переменные, и затраты на стек вызовов. Обычно затраты бывают $O(1)$, $O(\log n)$, $O(n)$.&lt;br /&gt;
&lt;br /&gt;
=== Устойчивость ===&lt;br /&gt;
&lt;br /&gt;
''Устойчивой сортировкой'' называется сортировка, не меняющая порядка объектов с одинаковыми ключами. Ключ — поле элемента, по которому мы производим сортировку. &lt;br /&gt;
&lt;br /&gt;
=== Количество обменов ===&lt;br /&gt;
&lt;br /&gt;
Количество обменов может быть важным параметром в случае, если объекты имеют большой размер. В таком случае при большом количестве обменов время алгоритма заметно увеличивается.&lt;br /&gt;
&lt;br /&gt;
=== Детерминированность ===&lt;br /&gt;
&lt;br /&gt;
Алгоритм сортировки называется ''детерминированным'', если каждая операция присваивания, обмена и т.д. не зависит от предыдущих.&lt;br /&gt;
Все сортирующие сети являются детерминированными.&lt;br /&gt;
&lt;br /&gt;
== Сравнение сортировок ==&lt;br /&gt;
&lt;br /&gt;
Рассмотрим массив $\big[ 1 \ldots n \big]$. Для элементов должно выполняться отношение порядка.&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
!width=&amp;quot;15%&amp;quot;|Название !!width=&amp;quot;8%&amp;quot;| Лучшее время !!width=&amp;quot;8%&amp;quot;| Среднее !!width=&amp;quot;8%&amp;quot;| Худшее !!width=&amp;quot;8%&amp;quot;| Память !! width=&amp;quot;8%&amp;quot;|Устойчивость !! width=&amp;quot;10%| Обмены (в среднем) !! &amp;quot;width=&amp;quot;35%&amp;quot;| Описание&lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|[[Сортировка пузырьком| Сортировка пузырьком &amp;lt;br&amp;gt;(Bubble Sort)]]&lt;br /&gt;
|$O(n)$&lt;br /&gt;
|$O(n^2)$&lt;br /&gt;
|$O(n^2)$&lt;br /&gt;
|$O(1)$&lt;br /&gt;
|Да&lt;br /&gt;
|$O(n^2)$&lt;br /&gt;
|Алгоритм состоит в повторяющихся проходах по сортируемому массиву. На каждой итерации последовательно сравниваются соседние элементы, и, если порядок в паре неверный, то элементы меняют местами.&lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|[[Сортировка вставками| Сортировка вставками &amp;lt;br&amp;gt;(Insertion Sort)]]&lt;br /&gt;
|$O(n)$&lt;br /&gt;
|$O(n^2)$&lt;br /&gt;
|$O(n^2)$&lt;br /&gt;
|$O(1)$&lt;br /&gt;
|Да&lt;br /&gt;
|$O(n^2)$&lt;br /&gt;
|На каждом шаге алгоритма мы выбираем один из элементов входных данных и вставляем его на нужную позицию в уже отсортированной части массива до тех пор, пока весь набор входных данных не будет отсортирован.&lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|[[Сортировка Шелла| Сортировка Шелла &amp;lt;br&amp;gt;(Shellsort)]]&lt;br /&gt;
|$O(n\log^2{n})$&lt;br /&gt;
|Зависит от выбора шага&lt;br /&gt;
|$O(n^2)$&lt;br /&gt;
|$O(1)$&lt;br /&gt;
|Нет&lt;br /&gt;
|$O(n^2)$&lt;br /&gt;
|Является модификацией сортировки вставками, сортируем между собой элементы, стоящие на кратных нашему шагу местах. &lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|[[Сортировка выбором| Сортировка выбором&amp;lt;br&amp;gt; (Selection Sort)]]&lt;br /&gt;
|$O(n^2)$&lt;br /&gt;
|$O(n^2)$&lt;br /&gt;
|$O(n^2)$&lt;br /&gt;
|$O(1)$&lt;br /&gt;
|Нет&lt;br /&gt;
|$O(n)$&lt;br /&gt;
|На $i$-ом шаге алгоритма находим минимальный среди последних $n - i + 1$, и меняем его местами с $i$-ым элементом в массиве.&lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|[[Быстрая сортировка|Быстрая сортировка&amp;lt;br&amp;gt; (Quick Sort)]]&lt;br /&gt;
|$O(n \log n)$&lt;br /&gt;
|$O(n \log n)$&lt;br /&gt;
|$O(n^2)$&amp;lt;br&amp;gt;(маловероятно)&lt;br /&gt;
|$O(\log n)$&amp;lt;br&amp;gt;(стек вызовов)&lt;br /&gt;
|Нет&lt;br /&gt;
|$O(n \log n)$&lt;br /&gt;
|Один из самых известных и широко используемых алгоритмов сортировки. Алгоритм состоит в выборе опорного элемента, разделении массива на 2 части относительно опорного (одна — все элементы, меньшие опорного элемента, вторая — большие), и в сортировке полученных частей рекурсивным вызовом себя от них.&lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|[[Сортировка слиянием|Сортировка слиянием &amp;lt;br&amp;gt;(Merge Sort)]]&lt;br /&gt;
|$O(n \log n)$&lt;br /&gt;
|$O(n \log n)$&lt;br /&gt;
|$O(n \log n)$&lt;br /&gt;
|$O(n)$ (обычная реализация)&amp;lt;br&amp;gt;$O(1)$&amp;lt;br&amp;gt; ([[Cортировка слиянием с использованием O(1) дополнительной памяти|модифицированная реализация]])&lt;br /&gt;
|Да&lt;br /&gt;
|$O(n \log n)$&lt;br /&gt;
|Алгоритм состоит в разделении массива пополам, сортировки половин и их слиянии.&lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|[[Timsort| Timsort]]&lt;br /&gt;
|$O(n)$&lt;br /&gt;
|$O(n\log{n})$&lt;br /&gt;
|$O(n\log{n})$&lt;br /&gt;
|$O(n)$&lt;br /&gt;
|Да&lt;br /&gt;
|$O(n\log{n})$&lt;br /&gt;
|Гибрид сортировки слиянием. Разбиваем массив на подмассивы фиксированной длины и сортируем каждый подмассив любой устойчивой сортировкой. После чего объединяем отсортированные подмассивы модифицированной сортировкой слиянием.&lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|[[Сортировка кучей|Сортировка кучей &amp;lt;br&amp;gt;(Heap Sort)]]&lt;br /&gt;
|$O(n \log n)$&lt;br /&gt;
|$O(n \log n)$&lt;br /&gt;
|$O(n \log n)$&lt;br /&gt;
|$O(1)$&lt;br /&gt;
|Нет&lt;br /&gt;
|$O(n \log n)$&lt;br /&gt;
|Строим из массива кучу, по очереди извлекаем минимум кучи.&lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|[[Smoothsort| Плавная сортировка &amp;lt;br&amp;gt;(Smoothsort)]]&lt;br /&gt;
|$O(n)$&lt;br /&gt;
|$O(n\log{n})$&lt;br /&gt;
|$O(n\log{n})$&lt;br /&gt;
|$O(1)$&lt;br /&gt;
|Нет&lt;br /&gt;
|$O(n\log{n})$&lt;br /&gt;
|Модификация сортировки кучей. Вместо двоичной кучи используем K-ую кучу Леонардо.&lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|[[Терпеливая сортировка| Терпеливая сортировка &amp;lt;br&amp;gt;(Patience sorting)]]&lt;br /&gt;
|$O(n\log{n})$&lt;br /&gt;
|$O(n\log{n})$&lt;br /&gt;
|$O(n\log{n})$&lt;br /&gt;
|$O(n)$&lt;br /&gt;
|Нет&lt;br /&gt;
|$O(n\log{n})$&lt;br /&gt;
|Раскидываем элементы массива по стопкам, после чего строим двоичную кучу из стопок. Позволяет также вычислить длину наибольшей возрастающей подпоследовательности данного массива. &lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|[[Дерево поиска, наивная реализация|Сортировка с помощью бинарного дерева &amp;lt;br&amp;gt;(Tree Sort)]]&lt;br /&gt;
|$O(n)$&lt;br /&gt;
|$O(n \log n)$&lt;br /&gt;
|$O(n \log n)$&lt;br /&gt;
|$O(n)$&lt;br /&gt;
|Да&lt;br /&gt;
|$O(n)$&lt;br /&gt;
|Добавляем по очереди вершины в сбалансированное дерево поиска, проходим по всем вершинам в порядке возрастания.&lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|[[Карманная сортировка|Карманная сортировка &amp;lt;br&amp;gt;(Bucket Sort)]]&lt;br /&gt;
|$O(n + k)$&lt;br /&gt;
|$O(n \log_k n)$&lt;br /&gt;
|$O(n \cdot k)$&lt;br /&gt;
|$O(n)$&lt;br /&gt;
|Да&lt;br /&gt;
| -&lt;br /&gt;
|Распределяем элементы в $k$ карманов, сортируем элементы внутри карманов, из каждого кармана данные записываются в массив в порядке разбиения.&lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|[[Цифровая сортировка|Цифровая сортировка &amp;lt;br&amp;gt;(Radix Sort)]]&lt;br /&gt;
|$O(n \lg n)$&lt;br /&gt;
|$O(n \lg n)$&lt;br /&gt;
|$O(n \lg n)$&lt;br /&gt;
|$O(n)$&lt;br /&gt;
|Да&lt;br /&gt;
| -&lt;br /&gt;
|Сортировка объектов равной длины, имеющих &amp;quot;разряды&amp;quot;. обычно это строки или целые числа. Алгоритм состоит в том, чтобы отсортировать объекты по разрядам, начиная от младших к старшим.&lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|[[Сортировка подсчетом|Сортировка подсчетом &amp;lt;br&amp;gt;(Counting Sort)]]&lt;br /&gt;
|$O(n)$&lt;br /&gt;
|$O(n + k)$&lt;br /&gt;
|$O(k)$&lt;br /&gt;
|$O(k)$&lt;br /&gt;
|Да&lt;br /&gt;
|$O(n + k)$&lt;br /&gt;
|Сортировка целых чисел, входящих в какой-то небольшой диапазон. Создаем массив длины диапазона $k$, каждый элемент которого будет показывать, сколько исходных элементов равны данному. Бежим по массиву и считаем количество вхождений каждого числа.&lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|[[Сортировка Хэна (или Хана?)|Сортировка Хэна &amp;lt;br&amp;gt;(Han's Sort)]]&lt;br /&gt;
|$O(n \log \log n)$&lt;br /&gt;
|$O(n \log \log n)$&lt;br /&gt;
|$O(n \log \log n)$&lt;br /&gt;
|$O(n)$&lt;br /&gt;
|Да&lt;br /&gt;
|$O(n \log \log n)$&lt;br /&gt;
|Очень сложная сортировка, основанная на принадлежности ключей к целым числам. использует экспоненциальное поисковое дерево Андерсона.&lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|[[Многопоточная сортировка слиянием|Многопоточная сортировка слиянием &amp;lt;br&amp;gt;(Multithreaded merge sort)]]&lt;br /&gt;
|$O(\frac{n}{N_{ind}}\log \frac{n}{N_{ind}})$&lt;br /&gt;
|$O(\frac{n}{N_{ind}}\log \frac{n}{N_{ind}})$&lt;br /&gt;
|$O(\frac{n}{N_{ind}}\log \frac{n}{N_{ind}})$&lt;br /&gt;
|$O(n)$&lt;br /&gt;
|Да&lt;br /&gt;
|$O(n \log n)$&lt;br /&gt;
|Отличается от сортировки слиянием только тем, что при рекурсивном вызове будет создавать новый поток.&lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|[[PSRS-сортировка|PSRS-сортировка &amp;lt;br&amp;gt;(PSRS-sorting)]]&lt;br /&gt;
|$O(\frac{n}{N_{ind}}\log \frac{n}{N_{ind}})$&lt;br /&gt;
|$O(\frac{n}{N_{ind}}\log \frac{n}{N_{ind}})$&lt;br /&gt;
|$O(\frac{n}{N_{ind}}\log \frac{n}{N_{ind}})$&lt;br /&gt;
|$O(N_{ind}^2)$&lt;br /&gt;
|Нет&lt;br /&gt;
|$O(n \log n)$&lt;br /&gt;
|Разделим массив на $N_{ind}$ подмассива и запустим в каждой быструю сортировку. После этого объединим все эти подмассивы.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==См. также==&lt;br /&gt;
*[[Поисковые структуры данных]]&lt;br /&gt;
*[[Приоритетные очереди]]&lt;br /&gt;
*[[Поиск подстроки в строке]]&lt;br /&gt;
&lt;br /&gt;
==Источники информации==&lt;br /&gt;
*[http://ru.wikipedia.org/wiki/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D1%81%D0%BE%D1%80%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B8 Википедия {{---}} Алгоритмы сортировки]&lt;br /&gt;
*[https://en.wikipedia.org/wiki/Sorting_algorithm Wikipedia {{---}}Sorting algorithm]&lt;br /&gt;
*[http://habrahabr.ru/post/221807/ Хабрахабр {{---}} Бенчмарк алгоритмов сортировки]&lt;br /&gt;
* Томас Х. Кормен, Чарльз И. Лейзерсон, Рональд Л. Ривест, Клиффорд Штайн Алгоритмы: построение и анализ — 3-е изд. — М.: «Вильямс», 2013. — с. 174. — ISBN 978-5-8459-1794-2&lt;br /&gt;
&amp;lt;/wikitex&amp;gt;&lt;br /&gt;
[[Категория: Дискретная математика и алгоритмы]]&lt;br /&gt;
[[Категория: Сортировки]]&lt;br /&gt;
[[Категория: Квадратичные сортировки]]&lt;br /&gt;
[[Категория: Сортировки на сравнениях]]&lt;br /&gt;
[[Категория: Многопоточные сортировки]]&lt;br /&gt;
[[Категория: Другие сортировки]]&lt;/div&gt;</summary>
		<author><name>Ильнар</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%A1%D0%BE%D1%80%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B0&amp;diff=46810</id>
		<title>Сортировка</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%A1%D0%BE%D1%80%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B0&amp;diff=46810"/>
				<updated>2015-05-23T18:23:23Z</updated>
		
		<summary type="html">&lt;p&gt;Ильнар: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;wikitex&amp;gt;&lt;br /&gt;
''Сортировкой'' (англ. ''sorting'') называется процесс упорядочивания множества объектов по какому-либо признаку.&lt;br /&gt;
&lt;br /&gt;
Так как данные могут хранится в разных структурах, то и алгоритмы для каждой структуры могут отличаться. Например, при хранении данных в списке сортировка кучей потребует $O(n^2 \log n)$ времени против $O(n \log n)$ с использованием массива; а вот сортировка пузырьком не изменится.&lt;br /&gt;
&lt;br /&gt;
Также есть алгоритмы параллельной сортировки данных (т.н. [[Сортирующие сети]]), время работы которых в лучшем случае $O(\log n)$. &lt;br /&gt;
== Классификация сортировок ==&lt;br /&gt;
&lt;br /&gt;
=== Время работы ===&lt;br /&gt;
&lt;br /&gt;
Эту классификацию обычно считают самой важной. Оценивают худшее время алгоритма, среднее и лучшее. Лучшее время — минимальное время работы алгоритма на каком-либо наборе, обычно этим набором является тривиальный $\big[ 1 \ldots n \big] $. Худшее время — наибольшее время.&lt;br /&gt;
У большинства алгоритмов временные оценки бывают $O(n \log n)$ и $O(n^2)$.&lt;br /&gt;
&lt;br /&gt;
=== Память ===&lt;br /&gt;
&lt;br /&gt;
Параметр сортировки, показывающий, сколько '''дополнительной''' памяти требуется алгоритму. Сюда входят и дополнительный массив, и переменные, и затраты на стек вызовов. Обычно затраты бывают $O(1)$, $O(\log n)$, $O(n)$.&lt;br /&gt;
&lt;br /&gt;
=== Устойчивость ===&lt;br /&gt;
&lt;br /&gt;
''Устойчивой сортировкой'' называется сортировка, не меняющая порядка объектов с одинаковыми ключами. Ключ — поле элемента, по которому мы производим сортировку. &lt;br /&gt;
&lt;br /&gt;
=== Количество обменов ===&lt;br /&gt;
&lt;br /&gt;
Количество обменов может быть важным параметром в случае, если объекты имеют большой размер. В таком случае при большом количестве обменов время алгоритма заметно увеличивается.&lt;br /&gt;
&lt;br /&gt;
=== Детерминированность ===&lt;br /&gt;
&lt;br /&gt;
Алгоритм сортировки называется ''детерминированным'', если каждая операция присваивания, обмена и т.д. не зависит от предыдущих.&lt;br /&gt;
Все сортирующие сети являются детерминированными.&lt;br /&gt;
&lt;br /&gt;
== Сравнение сортировок ==&lt;br /&gt;
&lt;br /&gt;
Рассмотрим массив $\big[ 1 \ldots n \big]$. Для элементов должно выполняться отношение порядка.&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
!width=&amp;quot;15%&amp;quot;|Название !!width=&amp;quot;8%&amp;quot;| Лучшее время !!width=&amp;quot;8%&amp;quot;| Среднее !!width=&amp;quot;8%&amp;quot;| Худшее !!width=&amp;quot;8%&amp;quot;| Память !! width=&amp;quot;8%&amp;quot;|Устойчивость !! width=&amp;quot;10%| Обмены (в среднем) !! &amp;quot;width=&amp;quot;35%&amp;quot;| Описание&lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|[[Сортировка пузырьком| Сортировка пузырьком &amp;lt;br&amp;gt;(Bubble Sort)]]&lt;br /&gt;
|$O(n)$&lt;br /&gt;
|$O(n^2)$&lt;br /&gt;
|$O(n^2)$&lt;br /&gt;
|$O(1)$&lt;br /&gt;
|Да&lt;br /&gt;
|$O(n^2)$&lt;br /&gt;
|Алгоритм состоит в повторяющихся проходах по сортируемому массиву. На каждой итерации последовательно сравниваются соседние элементы, и, если порядок в паре неверный, то элементы меняют местами.&lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|[[Сортировка вставками| Сортировка вставками &amp;lt;br&amp;gt;(Insertion Sort)]]&lt;br /&gt;
|$O(n)$&lt;br /&gt;
|$O(n^2)$&lt;br /&gt;
|$O(n^2)$&lt;br /&gt;
|$O(1)$&lt;br /&gt;
|Да&lt;br /&gt;
|$O(n^2)$&lt;br /&gt;
|На каждом шаге алгоритма мы выбираем один из элементов входных данных и вставляем его на нужную позицию в уже отсортированной части массива до тех пор, пока весь набор входных данных не будет отсортирован.&lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|[[Сортировка Шелла| Сортировка Шелла &amp;lt;br&amp;gt;(Shellsort)]]&lt;br /&gt;
|$O(n\log^2{n})$&lt;br /&gt;
|Зависит от выбора шага&lt;br /&gt;
|$O(n^2)$&lt;br /&gt;
|$O(1)$&lt;br /&gt;
|Нет&lt;br /&gt;
|$O(n^2)$&lt;br /&gt;
|Является модификацией сортировки вставками, сортируем между собой элементы, стоящие на кратных нашему шагу местах. &lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|[[Сортировка выбором| Сортировка выбором&amp;lt;br&amp;gt; (Selection Sort)]]&lt;br /&gt;
|$O(n^2)$&lt;br /&gt;
|$O(n^2)$&lt;br /&gt;
|$O(n^2)$&lt;br /&gt;
|$O(1)$&lt;br /&gt;
|Нет&lt;br /&gt;
|$O(n)$&lt;br /&gt;
|На $i$-ом шаге алгоритма находим минимальный среди последних $n - i + 1$, и меняем его местами с $i$-ым элементом в массиве.&lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|[[Быстрая сортировка|Быстрая сортировка&amp;lt;br&amp;gt; (Quick Sort)]]&lt;br /&gt;
|$O(n \log n)$&lt;br /&gt;
|$O(n \log n)$&lt;br /&gt;
|$O(n^2)$&amp;lt;br&amp;gt;(маловероятно)&lt;br /&gt;
|$O(\log n)$&amp;lt;br&amp;gt;(стек вызовов)&lt;br /&gt;
|Нет&lt;br /&gt;
|$O(n \log n)$&lt;br /&gt;
|Один из самых известных и широко используемых алгоритмов сортировки. Алгоритм состоит в выборе опорного элемента, разделении массива на 2 части относительно опорного (одна — все элементы, меньшие опорного элемента, вторая — большие), и в сортировке полученных частей рекурсивным вызовом себя от них.&lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|[[Сортировка слиянием|Сортировка слиянием &amp;lt;br&amp;gt;(Merge Sort)]]&lt;br /&gt;
|$O(n \log n)$&lt;br /&gt;
|$O(n \log n)$&lt;br /&gt;
|$O(n \log n)$&lt;br /&gt;
|$O(n)$ (обычная реализация)&amp;lt;br&amp;gt;$O(1)$&amp;lt;br&amp;gt; ([[Cортировка слиянием с использованием O(1) дополнительной памяти|модифицированная реализация]])&lt;br /&gt;
|Да&lt;br /&gt;
|$O(n \log n)$&lt;br /&gt;
|Алгоритм состоит в разделении массива пополам, сортировки половин и их слиянии.&lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|[[Timsort| Timsort]]&lt;br /&gt;
|$O(n)$&lt;br /&gt;
|$O(n\log{n})$&lt;br /&gt;
|$O(n\log{n})$&lt;br /&gt;
|$O(n)$&lt;br /&gt;
|Да&lt;br /&gt;
|$O(n\log{n})$&lt;br /&gt;
|Гибрид сортировки слиянием. Разбиваем массив на подмассивы фиксированной длины и сортируем каждый подмассив любой устойчивой сортировкой. После чего объединяем отсортированные подмассивы модифицированной сортировкой слиянием.&lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|[[Сортировка кучей|Сортировка кучей &amp;lt;br&amp;gt;(Heap Sort)]]&lt;br /&gt;
|$O(n \log n)$&lt;br /&gt;
|$O(n \log n)$&lt;br /&gt;
|$O(n \log n)$&lt;br /&gt;
|$O(1)$&lt;br /&gt;
|Нет&lt;br /&gt;
|$O(n \log n)$&lt;br /&gt;
|Строим из массива кучу, по очереди извлекаем минимум кучи.&lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|[[Smoothsort| Плавная сортировка &amp;lt;br&amp;gt;(Smoothsort)]]&lt;br /&gt;
|$O(n)$&lt;br /&gt;
|$O(n\log{n})$&lt;br /&gt;
|$O(n\log{n})$&lt;br /&gt;
|$O(1)$&lt;br /&gt;
|Нет&lt;br /&gt;
|$O(n\log{n})$&lt;br /&gt;
|Модификация сортировки кучей. Вместо двоичной кучи используем K-ую кучу Леонардо.&lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|[[Терпеливая сортировка| Терпеливая сортировка &amp;lt;br&amp;gt;(Patience sorting)]]&lt;br /&gt;
|$O(n\log{n})$&lt;br /&gt;
|$O(n\log{n})$&lt;br /&gt;
|$O(n\log{n})$&lt;br /&gt;
|$O(n)$&lt;br /&gt;
|Нет&lt;br /&gt;
|$O(n\log{n})$&lt;br /&gt;
|Раскидываем элементы массива по стопкам, после чего строим двоичную кучу из стопок. Позволяет также вычислить длину наибольшей возрастающей подпоследовательности данного массива. &lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|[[Дерево поиска, наивная реализация|Сортировка с помощью бинарного дерева &amp;lt;br&amp;gt;(Tree Sort)]]&lt;br /&gt;
|$O(n)$&lt;br /&gt;
|$O(n \log n)$&lt;br /&gt;
|$O(n \log n)$&lt;br /&gt;
|$O(n)$&lt;br /&gt;
|Да&lt;br /&gt;
|$O(n)$&lt;br /&gt;
|Добавляем по очереди вершины в сбалансированное дерево поиска, проходим по всем вершинам в порядке возрастания.&lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|[[Карманная сортировка|Карманная сортировка &amp;lt;br&amp;gt;(Bucket Sort)]]&lt;br /&gt;
|$O(n + k)$&lt;br /&gt;
|$O(n \log_k n)$&lt;br /&gt;
|$O(n \cdot k)$&lt;br /&gt;
|$O(n)$&lt;br /&gt;
|Да&lt;br /&gt;
| -&lt;br /&gt;
|Распределяем элементы в $k$ карманов, сортируем элементы внутри карманов, из каждого кармана данные записываются в массив в порядке разбиения.&lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|[[Цифровая сортировка|Цифровая сортировка &amp;lt;br&amp;gt;(Radix Sort)]]&lt;br /&gt;
|$O(n \lg n)$&lt;br /&gt;
|$O(n \lg n)$&lt;br /&gt;
|$O(n \lg n)$&lt;br /&gt;
|$O(n)$&lt;br /&gt;
|Да&lt;br /&gt;
| -&lt;br /&gt;
|Сортировка объектов равной длины, имеющих &amp;quot;разряды&amp;quot;. обычно это строки или целые числа. Алгоритм состоит в том, чтобы отсортировать объекты по разрядам, начиная от младших к старшим.&lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|[[Сортировка подсчетом|Сортировка подсчетом &amp;lt;br&amp;gt;(Counting Sort)]]&lt;br /&gt;
|$O(n)$&lt;br /&gt;
|$O(n + k)$&lt;br /&gt;
|$O(k)$&lt;br /&gt;
|$O(k)$&lt;br /&gt;
|Да&lt;br /&gt;
|$O(n + k)$&lt;br /&gt;
|Сортировка целых чисел, входящих в какой-то небольшой диапазон. Создаем массив длины диапазона $k$, каждый элемент которого будет показывать, сколько исходных элементов равны данному. Бежим по массиву и считаем количество вхождений каждого числа.&lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|[[Сортировка Хэна (или Хана?)|Сортировка Хэна &amp;lt;br&amp;gt;(Han's Sort)]]&lt;br /&gt;
|$O(n \log \log n)$&lt;br /&gt;
|$O(n \log \log n)$&lt;br /&gt;
|$O(n \log \log n)$&lt;br /&gt;
|$O(n)$&lt;br /&gt;
|Да&lt;br /&gt;
|$O(n \log \log n)$&lt;br /&gt;
|Очень сложная сортировка, основанная на принадлежности ключей к целым числам. использует экспоненциальное поисковое дерево Андерсона.&lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|[[Многопоточная сортировка слиянием|Многопоточная сортировка слиянием &amp;lt;br&amp;gt;(Multithreaded merge sort)]]&lt;br /&gt;
|$O(\frac{n}{N_{ind}}\log \frac{n}{N_{ind}})$&lt;br /&gt;
|$O(\frac{n}{N_{ind}}\log \frac{n}{N_{ind}})$&lt;br /&gt;
|$O(\frac{n}{N_{ind}}\log \frac{n}{N_{ind}})$&lt;br /&gt;
|$O(n)$&lt;br /&gt;
|Да&lt;br /&gt;
|$O(n \log n)$&lt;br /&gt;
|Отличается от сортировки слиянием только тем, что при рекурсивном вызове будет создавать новый поток.&lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|[[PSRS-сортировка|PSRS-сортировка &amp;lt;br&amp;gt;(PSRS-sorting)]]&lt;br /&gt;
|$O(\frac{n}{N_{ind}}\log \frac{n}{N_{ind}})$&lt;br /&gt;
|$O(\frac{n}{N_{ind}}\log \frac{n}{N_{ind}})$&lt;br /&gt;
|$O(\frac{n}{N_{ind}}\log \frac{n}{N_{ind}})$&lt;br /&gt;
|$O(N_{ind}^2)$&lt;br /&gt;
|Нет&lt;br /&gt;
|$O(n \log n)$&lt;br /&gt;
|Разделим массив на $N_{ind}$ подмассива и запустим в каждой быструю сортировку. После этого объединим все эти подмассивы.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==См. также==&lt;br /&gt;
*[[Поисковые структуры данных]]&lt;br /&gt;
*[[Приоритетные очереди]]&lt;br /&gt;
&lt;br /&gt;
==Источники информации==&lt;br /&gt;
*[http://ru.wikipedia.org/wiki/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D1%81%D0%BE%D1%80%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B8 Википедия {{---}} Алгоритмы сортировки]&lt;br /&gt;
*[https://en.wikipedia.org/wiki/Sorting_algorithm Wikipedia {{---}}Sorting algorithm]&lt;br /&gt;
*[http://habrahabr.ru/post/221807/ Хабрахабр {{---}} Бенчмарк алгоритмов сортировки]&lt;br /&gt;
* Томас Х. Кормен, Чарльз И. Лейзерсон, Рональд Л. Ривест, Клиффорд Штайн Алгоритмы: построение и анализ — 3-е изд. — М.: «Вильямс», 2013. — с. 174. — ISBN 978-5-8459-1794-2&lt;br /&gt;
&amp;lt;/wikitex&amp;gt;&lt;br /&gt;
[[Категория: Дискретная математика и алгоритмы]]&lt;br /&gt;
[[Категория: Сортировки]]&lt;br /&gt;
[[Категория: Квадратичные сортировки]]&lt;br /&gt;
[[Категория: Сортировки на сравнениях]]&lt;br /&gt;
[[Категория: Многопоточные сортировки]]&lt;br /&gt;
[[Категория: Другие сортировки]]&lt;/div&gt;</summary>
		<author><name>Ильнар</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%A1%D0%BE%D1%80%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B0&amp;diff=46809</id>
		<title>Сортировка</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%A1%D0%BE%D1%80%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B0&amp;diff=46809"/>
				<updated>2015-05-23T17:58:43Z</updated>
		
		<summary type="html">&lt;p&gt;Ильнар: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;wikitex&amp;gt;&lt;br /&gt;
''Сортировкой'' (англ. ''sorting'') называется процесс упорядочивания множества объектов по какому-либо признаку.&lt;br /&gt;
&lt;br /&gt;
Так как данные могут хранится в разных структурах, то и алгоритмы для каждой структуры могут отличаться. Например, при хранении данных в списке сортировка кучей потребует $O(n^2 \log n)$ времени против $O(n \log n)$ с использованием массива; а вот сортировка пузырьком не изменится.&lt;br /&gt;
&lt;br /&gt;
Также есть алгоритмы параллельной сортировки данных (т.н. [[Сортирующие сети]]), время работы которых в лучшем случае $O(\log n)$. &lt;br /&gt;
== Классификация сортировок ==&lt;br /&gt;
&lt;br /&gt;
=== Время работы ===&lt;br /&gt;
&lt;br /&gt;
Эту классификацию обычно считают самой важной. Оценивают худшее время алгоритма, среднее и лучшее. Лучшее время — минимальное время работы алгоритма на каком-либо наборе, обычно этим набором является тривиальный $\big[ 1 \ldots n \big] $. Худшее время — наибольшее время.&lt;br /&gt;
У большинства алгоритмов временные оценки бывают $O(n \log n)$ и $O(n^2)$.&lt;br /&gt;
&lt;br /&gt;
=== Память ===&lt;br /&gt;
&lt;br /&gt;
Параметр сортировки, показывающий, сколько '''дополнительной''' памяти требуется алгоритму. Сюда входят и дополнительный массив, и переменные, и затраты на стек вызовов. Обычно затраты бывают $O(1)$, $O(\log n)$, $O(n)$.&lt;br /&gt;
&lt;br /&gt;
=== Устойчивость ===&lt;br /&gt;
&lt;br /&gt;
''Устойчивой сортировкой'' называется сортировка, не меняющая порядка объектов с одинаковыми ключами. Ключ — поле элемента, по которому мы производим сортировку. &lt;br /&gt;
&lt;br /&gt;
=== Количество обменов ===&lt;br /&gt;
&lt;br /&gt;
Количество обменов может быть важным параметром в случае, если объекты имеют большой размер. В таком случае при большом количестве обменов время алгоритма заметно увеличивается.&lt;br /&gt;
&lt;br /&gt;
=== Детерминированность ===&lt;br /&gt;
&lt;br /&gt;
Алгоритм сортировки называется ''детерминированным'', если каждая операция присваивания, обмена и т.д. не зависит от предыдущих.&lt;br /&gt;
Все сортирующие сети являются детерминированными.&lt;br /&gt;
&lt;br /&gt;
== Сравнение сортировок ==&lt;br /&gt;
&lt;br /&gt;
Рассмотрим массив $\big[ 1 \ldots n \big]$. Для элементов должно выполняться отношение порядка.&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
!width=&amp;quot;15%&amp;quot;|Название !!width=&amp;quot;8%&amp;quot;| Лучшее время !!width=&amp;quot;8%&amp;quot;| Среднее !!width=&amp;quot;8%&amp;quot;| Худшее !!width=&amp;quot;8%&amp;quot;| Память !! width=&amp;quot;8%&amp;quot;|Устойчивость !! width=&amp;quot;10%| Обмены (в среднем) !! &amp;quot;width=&amp;quot;35%&amp;quot;| Описание&lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|[[Сортировка пузырьком| Сортировка пузырьком &amp;lt;br&amp;gt;(Bubble Sort)]]&lt;br /&gt;
|$O(n)$&lt;br /&gt;
|$O(n^2)$&lt;br /&gt;
|$O(n^2)$&lt;br /&gt;
|$O(1)$&lt;br /&gt;
|Да&lt;br /&gt;
|$O(n^2)$&lt;br /&gt;
|Алгоритм состоит в повторяющихся проходах по сортируемому массиву. На каждой итерации последовательно сравниваются соседние элементы, и, если порядок в паре неверный, то элементы меняют местами.&lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|[[Сортировка вставками| Сортировка вставками &amp;lt;br&amp;gt;(Insertion Sort)]]&lt;br /&gt;
|$O(n)$&lt;br /&gt;
|$O(n^2)$&lt;br /&gt;
|$O(n^2)$&lt;br /&gt;
|$O(1)$&lt;br /&gt;
|Да&lt;br /&gt;
|$O(n^2)$&lt;br /&gt;
|На каждом шаге алгоритма мы выбираем один из элементов входных данных и вставляем его на нужную позицию в уже отсортированной части массива до тех пор, пока весь набор входных данных не будет отсортирован.&lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|[[Сортировка Шелла| Сортировка Шелла &amp;lt;br&amp;gt;(Shellsort)]]&lt;br /&gt;
|$O(n\log^2{n})$&lt;br /&gt;
|Зависит от выбора шага&lt;br /&gt;
|$O(n^2)$&lt;br /&gt;
|$O(1)$&lt;br /&gt;
|Нет&lt;br /&gt;
|$O(n^2)$&lt;br /&gt;
|Является модификацией сортировки вставками, сортируем между собой элементы, стоящие на кратных нашему шагу местах. &lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|[[Сортировка выбором| Сортировка выбором&amp;lt;br&amp;gt; (Selection Sort)]]&lt;br /&gt;
|$O(n^2)$&lt;br /&gt;
|$O(n^2)$&lt;br /&gt;
|$O(n^2)$&lt;br /&gt;
|$O(1)$&lt;br /&gt;
|Нет&lt;br /&gt;
|$O(n)$&lt;br /&gt;
|На $i$-ом шаге алгоритма находим минимальный среди последних $n - i + 1$, и меняем его местами с $i$-ым элементом в массиве.&lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|[[Быстрая сортировка|Быстрая сортировка&amp;lt;br&amp;gt; (Quick Sort)]]&lt;br /&gt;
|$O(n \log n)$&lt;br /&gt;
|$O(n \log n)$&lt;br /&gt;
|$O(n^2)$&amp;lt;br&amp;gt;(маловероятно)&lt;br /&gt;
|$O(\log n)$&amp;lt;br&amp;gt;(стек вызовов)&lt;br /&gt;
|Нет&lt;br /&gt;
|$O(n \log n)$&lt;br /&gt;
|Один из самых известных и широко используемых алгоритмов сортировки. Алгоритм состоит в выборе опорного элемента, разделении массива на 2 части относительно опорного (одна — все элементы, меньшие опорного элемента, вторая — большие), и в сортировке полученных частей рекурсивным вызовом себя от них.&lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|[[Сортировка слиянием|Сортировка слиянием &amp;lt;br&amp;gt;(Merge Sort)]]&lt;br /&gt;
|$O(n \log n)$&lt;br /&gt;
|$O(n \log n)$&lt;br /&gt;
|$O(n \log n)$&lt;br /&gt;
|$O(n)$ (обычная реализация)&amp;lt;br&amp;gt;$O(1)$&amp;lt;br&amp;gt; ([[Cортировка слиянием с использованием O(1) дополнительной памяти|модифицированная реализация]])&lt;br /&gt;
|Да&lt;br /&gt;
|$O(n \log n)$&lt;br /&gt;
|Алгоритм состоит в разделении массива пополам, сортировки половин и их слиянии.&lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|[[Timsort| Timsort]]&lt;br /&gt;
|$O(n)$&lt;br /&gt;
|$O(n\log{n})$&lt;br /&gt;
|$O(n\log{n})$&lt;br /&gt;
|$O(n)$&lt;br /&gt;
|Да&lt;br /&gt;
|$O(n\log{n})$&lt;br /&gt;
|Гибрид сортировки слиянием. Разбиваем массив на подмассивы фиксированной длины и сортируем каждый подмассив любой устойчивой сортировкой. После чего объединяем отсортированные подмассивы модифицированной сортировкой слиянием.&lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|[[Сортировка кучей|Сортировка кучей &amp;lt;br&amp;gt;(Heap Sort)]]&lt;br /&gt;
|$O(n \log n)$&lt;br /&gt;
|$O(n \log n)$&lt;br /&gt;
|$O(n \log n)$&lt;br /&gt;
|$O(1)$&lt;br /&gt;
|Нет&lt;br /&gt;
|$O(n \log n)$&lt;br /&gt;
|Строим из массива кучу, по очереди извлекаем минимум кучи.&lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|[[Smoothsort| Плавная сортировка &amp;lt;br&amp;gt;(Smoothsort)]]&lt;br /&gt;
|$O(n)$&lt;br /&gt;
|$O(n\log{n})$&lt;br /&gt;
|$O(n\log{n})$&lt;br /&gt;
|$O(1)$&lt;br /&gt;
|Нет&lt;br /&gt;
|$O(n\log{n})$&lt;br /&gt;
|Модификация сортировки кучей. Вместо двоичной кучи используем K-ую кучу Леонардо.&lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|[[Терпеливая сортировка| Терпеливая сортировка &amp;lt;br&amp;gt;(Patience sorting)]]&lt;br /&gt;
|$O(n\log{n})$&lt;br /&gt;
|$O(n\log{n})$&lt;br /&gt;
|$O(n\log{n})$&lt;br /&gt;
|$O(n)$&lt;br /&gt;
|Нет&lt;br /&gt;
|$O(n\log{n})$&lt;br /&gt;
|Раскидываем элементы массива по стопкам, после чего строим двоичную кучу из стопок. Позволяет также вычислить длину наибольшей возрастающей подпоследовательности данного массива. &lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|[[Дерево поиска, наивная реализация|Сортировка с помощью бинарного дерева &amp;lt;br&amp;gt;(Tree Sort)]]&lt;br /&gt;
|$O(n)$&lt;br /&gt;
|$O(n \log n)$&lt;br /&gt;
|$O(n \log n)$&lt;br /&gt;
|$O(n)$&lt;br /&gt;
|Да&lt;br /&gt;
|$O(n)$&lt;br /&gt;
|Добавляем по очереди вершины в сбалансированное дерево поиска, проходим по всем вершинам в порядке возрастания.&lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|[[Карманная сортировка|Карманная сортировка &amp;lt;br&amp;gt;(Bucket Sort)]]&lt;br /&gt;
|$O(n + k)$&lt;br /&gt;
|$O(n \log_k n)$&lt;br /&gt;
|$O(n \cdot k)$&lt;br /&gt;
|$O(n)$&lt;br /&gt;
|Да&lt;br /&gt;
| -&lt;br /&gt;
|Распределяем элементы в $k$ карманов, сортируем элементы внутри карманов, из каждого кармана данные записываются в массив в порядке разбиения.&lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|[[Цифровая сортировка|Цифровая сортировка &amp;lt;br&amp;gt;(Radix Sort)]]&lt;br /&gt;
|$O(n \lg n)$&lt;br /&gt;
|$O(n \lg n)$&lt;br /&gt;
|$O(n \lg n)$&lt;br /&gt;
|$O(n)$&lt;br /&gt;
|Да&lt;br /&gt;
| -&lt;br /&gt;
|Сортировка объектов равной длины, имеющих &amp;quot;разряды&amp;quot;. обычно это строки или целые числа. Алгоритм состоит в том, чтобы отсортировать объекты по разрядам, начиная от младших к старшим.&lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|[[Сортировка подсчетом|Сортировка подсчетом &amp;lt;br&amp;gt;(Counting Sort)]]&lt;br /&gt;
|$O(n)$&lt;br /&gt;
|$O(n + k)$&lt;br /&gt;
|$O(k)$&lt;br /&gt;
|$O(k)$&lt;br /&gt;
|Да&lt;br /&gt;
|$O(n + k)$&lt;br /&gt;
|Сортировка целых чисел, входящих в какой-то небольшой диапазон. Создаем массив длины диапазона $k$, каждый элемент которого будет показывать, сколько исходных элементов равны данному. Бежим по массиву и считаем количество вхождений каждого числа.&lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|[[Сортировка Хэна (или Хана?)|Сортировка Хэна &amp;lt;br&amp;gt;(Han's Sort)]]&lt;br /&gt;
|$O(n \log \log n)$&lt;br /&gt;
|$O(n \log \log n)$&lt;br /&gt;
|$O(n \log \log n)$&lt;br /&gt;
|$O(n)$&lt;br /&gt;
|Да&lt;br /&gt;
|$O(n \log \log n)$&lt;br /&gt;
|Очень сложная сортировка, основанная на принадлежности ключей к целым числам. использует экспоненциальное поисковое дерево Андерсона.&lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|[[Многопоточная сортировка слиянием|Многопоточная сортировка слиянием &amp;lt;br&amp;gt;(Multithreaded merge sort)]]&lt;br /&gt;
|$O(\frac{n}{N_{ind}}\log \frac{n}{N_{ind}})$&lt;br /&gt;
|$O(\frac{n}{N_{ind}}\log \frac{n}{N_{ind}})$&lt;br /&gt;
|$O(\frac{n}{N_{ind}}\log \frac{n}{N_{ind}})$&lt;br /&gt;
|$O(n)$&lt;br /&gt;
|Да&lt;br /&gt;
|$O(n \log n)$&lt;br /&gt;
|Отличается от сортировки слиянием только тем, что при рекурсивном вызове будет создавать новый поток.&lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|[[PSRS-сортировка|PSRS-сортировка &amp;lt;br&amp;gt;(PSRS-sorting)]]&lt;br /&gt;
|$O(\frac{n}{N_{ind}}\log \frac{n}{N_{ind}})$&lt;br /&gt;
|$O(\frac{n}{N_{ind}}\log \frac{n}{N_{ind}})$&lt;br /&gt;
|$O(\frac{n}{N_{ind}}\log \frac{n}{N_{ind}})$&lt;br /&gt;
|$O(N_{ind}^2)$&lt;br /&gt;
|Нет&lt;br /&gt;
|$O(n \log n)$&lt;br /&gt;
|Разделим массив на $N_{ind}$ подмассива и запустим в каждой быструю сортировку. После этого объединим все эти подмассивы.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==См. также==&lt;br /&gt;
*[[Поисковые структуры данных]]&lt;br /&gt;
*[[Приоритетные очереди]]&lt;br /&gt;
&lt;br /&gt;
==Источники информации==&lt;br /&gt;
*[http://ru.wikipedia.org/wiki/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D1%81%D0%BE%D1%80%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B8 Википедия {{---}} Алгоритмы сортировки]&lt;br /&gt;
*[https://en.wikipedia.org/wiki/Sorting_algorithm Wikipedia {{---}}Sorting algorithm]&lt;br /&gt;
*[http://habrahabr.ru/post/221807/ Хабрахабр {{---}} Бенчмарк алгоритмов сортировки]&lt;br /&gt;
* Томас Х. Кормен, Чарльз И. Лейзерсон, Рональд Л. Ривест, Клиффорд Штайн Алгоритмы: построение и анализ — 3-е изд. — М.: «Вильямс», 2013. — с. 174. — ISBN 978-5-8459-1794-2&lt;br /&gt;
&amp;lt;/wikitex&amp;gt;&lt;br /&gt;
[[Категория: Дискретная математика и алгоритмы]]&lt;br /&gt;
[[Категория: Сортировки]]&lt;/div&gt;</summary>
		<author><name>Ильнар</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%A1%D0%BE%D1%80%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B0_%D1%81%D0%BB%D0%B8%D1%8F%D0%BD%D0%B8%D0%B5%D0%BC&amp;diff=46808</id>
		<title>Сортировка слиянием</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%A1%D0%BE%D1%80%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B0_%D1%81%D0%BB%D0%B8%D1%8F%D0%BD%D0%B8%D0%B5%D0%BC&amp;diff=46808"/>
				<updated>2015-05-23T17:57:45Z</updated>
		
		<summary type="html">&lt;p&gt;Ильнар: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''Сортировка слиянием''' (англ. ''Merge sort'') {{---}} алгоритм сортировки, пред­ло­женный Джо­ном фон Ней­ма­ном в 1945 го­ду.&lt;br /&gt;
&lt;br /&gt;
Это устойчивый алгоритм, использующий &amp;lt;tex&amp;gt;O(n)&amp;lt;/tex&amp;gt; дополнительной памяти и работающий за &amp;lt;tex&amp;gt;O(n&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;\log n)&amp;lt;/tex&amp;gt; времени.&lt;br /&gt;
&lt;br /&gt;
==Принцип работы==&lt;br /&gt;
[[Файл:Merging_two_arrays.png|270px|right|thumb|Пример работы процедуры слияния.]]&lt;br /&gt;
Алгоритм использует принцип «разделяй и властвуй»: задача разбивается на подзадачи меньшего размера, которые решаются по отдельности, после чего их решения комбинируются для получения решения исходной задачи. Конкретно процедуру сортировки слиянием можно описать следующим образом:&lt;br /&gt;
&lt;br /&gt;
# Если в рассматриваемом массиве один элемент, то он уже отсортирован {{---}} алгоритм завершает работу.&lt;br /&gt;
# Иначе массив разбивается на две части, которые сортируются рекурсивно.&lt;br /&gt;
# После сортировки двух частей массива к ним применяется процедура слияния, которая по двум отсортированным частям получает исходный отсортированный массив.&lt;br /&gt;
&lt;br /&gt;
===Слияние двух массивов===&lt;br /&gt;
У нас есть два массива &amp;lt;tex&amp;gt;a&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt; (фактически это будут две части одного массива, но для удобства будем писать, что у нас просто два массива). Нам надо получить массив &amp;lt;tex&amp;gt;c&amp;lt;/tex&amp;gt; размером &amp;lt;tex&amp;gt;|a| + |b|&amp;lt;/tex&amp;gt;. Для этого можно применить процедуру слияния. Эта процедура заключается в том, что мы сравниваем элементы массивов (начиная с начала) и меньший из них записываем в финальный. И затем, в массиве у которого оказался меньший элемент, переходим к следующему элементу и сравниваем теперь его. В конце, если один из массивов закончился, мы просто дописываем в финальный другой массив. После мы наш финальный массив записываем заместо двух исходных и получаем отсортированный участок.&lt;br /&gt;
&lt;br /&gt;
Множество отсортированных списков с операцией &amp;lt;tex&amp;gt;\mathrm{merge}&amp;lt;/tex&amp;gt; является [[Моноид|моноидом]], где нейтральным элементом будет пустой список.&lt;br /&gt;
&lt;br /&gt;
Ниже приведён псевдокод процедуры слияния, который сливает две части массива &amp;lt;tex&amp;gt;a&amp;lt;/tex&amp;gt; {{---}} &amp;lt;tex&amp;gt;[left; mid)&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;[mid; right)&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 '''function''' merge(a : '''int[n]'''; left, mid, right : '''int'''):&lt;br /&gt;
     it1 = 0&lt;br /&gt;
     it2 = 0&lt;br /&gt;
     result : '''int[right - left]'''&lt;br /&gt;
   &lt;br /&gt;
     '''while''' left + it1 &amp;lt; mid '''and''' mid + it2 &amp;lt; right&lt;br /&gt;
         '''if''' a[left + it1] &amp;lt; a[mid + it2]&lt;br /&gt;
             result[it1 + it2] = a[left + it1]&lt;br /&gt;
             it1 += 1&lt;br /&gt;
         '''else'''&lt;br /&gt;
             result[it1 + it2] = a[mid + it2]&lt;br /&gt;
             it2 += 1&lt;br /&gt;
   &lt;br /&gt;
     '''while''' left + it1 &amp;lt; mid&lt;br /&gt;
         result[it1 + it2] = a[left + it1]&lt;br /&gt;
         it1 += 1&lt;br /&gt;
   &lt;br /&gt;
     '''while''' mid + it2 &amp;lt; right&lt;br /&gt;
         result[it1 + it2] = a[mid + it2]&lt;br /&gt;
         it2 += 1&lt;br /&gt;
   &lt;br /&gt;
     '''for''' i = 0 '''to''' it1 + it2&lt;br /&gt;
         a[left + i] = result[i]&lt;br /&gt;
&lt;br /&gt;
===Рекурсивный алгоритм===&lt;br /&gt;
[[Файл:Merge sort1.png|300px|right|thumb|Пример работы рекурсивного алгоритма сортировки слиянием]]&lt;br /&gt;
Функция сортирует подотрезок массива с индексами в полуинтервале &amp;lt;tex&amp;gt;[left; right)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&amp;lt;code style=&amp;quot;display: inline-block&amp;quot;&amp;gt;&lt;br /&gt;
 '''function''' mergeSortRecursive(a : '''int[n]'''; left, right : '''int'''):&lt;br /&gt;
     '''if''' left + 1 &amp;gt;= right&lt;br /&gt;
         '''return'''&lt;br /&gt;
     mid = (left + right) / 2&lt;br /&gt;
     mergeSortRecursive(a, left, mid)&lt;br /&gt;
     mergeSortRecursive(a, mid, right)&lt;br /&gt;
     merge(a, left, mid, right)&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
===Итеративный алгоритм===&lt;br /&gt;
[[Файл:Merge sort itearative.png|300px|right|thumb|Пример работы итеративного алгоритма сортировки слиянием]]&lt;br /&gt;
При итеративном алгоритме используется на &amp;lt;tex&amp;gt;O(\log n)&amp;lt;/tex&amp;gt; меньше памяти, которая раньше тратилась на рекурсивные вызовы.&lt;br /&gt;
&amp;lt;code style=&amp;quot;display: inline-block&amp;quot;&amp;gt;&lt;br /&gt;
 '''function''' mergeSortIterative(a : '''int[n]'''):&lt;br /&gt;
     '''for''' i = 1 '''to''' n, i *= 2&lt;br /&gt;
         '''for''' j = 0 '''to''' n - i, j += 2 * i&lt;br /&gt;
             merge(a, j, j + i, min(j + 2 * i, n))&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Время работы==&lt;br /&gt;
Чтобы оценить время работы этого алгоритма, составим рекуррентное соотношение. Пускай &amp;lt;tex&amp;gt;T(n)&amp;lt;/tex&amp;gt; {{---}} время сортировки массива длины &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt;, тогда для сортировки слиянием справедливо &amp;lt;tex&amp;gt;T(n)=2T(n/2)+O(n)&amp;lt;/tex&amp;gt; &amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;tex&amp;gt;O(n)&amp;lt;/tex&amp;gt; {{---}} время, необходимое на то, чтобы слить два массива. Распишем это соотношение:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;T(n)=2T(n/2)+O(n)=4T(n/4)+2O(n)=\dots=2^kT(1)+kO(n)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Осталось оценить &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt;. Мы знаем, что &amp;lt;tex&amp;gt;2^k=n&amp;lt;/tex&amp;gt;, а значит &amp;lt;tex&amp;gt;k=\log n&amp;lt;/tex&amp;gt;. Уравнение примет вид &amp;lt;tex&amp;gt;T(n)=nT(1)+ \log n&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;O(n)&amp;lt;/tex&amp;gt;. Так как &amp;lt;tex&amp;gt;T(1)&amp;lt;/tex&amp;gt; {{---}} константа, то &amp;lt;tex&amp;gt;T(n)=O(n)+\log n &amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;O(n)=O(n\log n)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==Сравнение с другими алгоритмами==&lt;br /&gt;
===Достоинства===&lt;br /&gt;
* Устойчивая.&lt;br /&gt;
===Недостатки===&lt;br /&gt;
* При любых входных данных время работы {{---}} &amp;lt;tex&amp;gt;O(n\log{n})&amp;lt;/tex&amp;gt;,&lt;br /&gt;
* требуется дополнительно &amp;lt;tex&amp;gt;O(n)&amp;lt;/tex&amp;gt; памяти, но можно модифицировать до &amp;lt;tex&amp;gt;O(1)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==См. также==&lt;br /&gt;
* [[Сортировка кучей]]&lt;br /&gt;
* [[Быстрая сортировка]]&lt;br /&gt;
* [[Timsort]]&lt;br /&gt;
*[[Cортировка слиянием с использованием O(1) дополнительной памяти]]&lt;br /&gt;
&lt;br /&gt;
==Источники информации==&lt;br /&gt;
*[http://ru.wikipedia.org/wiki/Mergesort Википедия {{---}} сортировка слиянием]&lt;br /&gt;
*[http://www.sorting-algorithms.com/merge-sort Визуализатор]&lt;br /&gt;
*[http://ru.wikibooks.org/wiki/%D0%9F%D1%80%D0%B8%D0%BC%D0%B5%D1%80%D1%8B_%D1%80%D0%B5%D0%B0%D0%BB%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D0%B8_%D1%81%D0%BE%D1%80%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B8_%D1%81%D0%BB%D0%B8%D1%8F%D0%BD%D0%B8%D0%B5%D0%BC Викиучебник {{---}} Примеры реализации на различных языках программирования]&lt;br /&gt;
&lt;br /&gt;
[[Категория: Дискретная математика и алгоритмы]]&lt;br /&gt;
[[Категория: Сортировки]]&lt;br /&gt;
[[Категория: Сортировки на сравнениях]]&lt;/div&gt;</summary>
		<author><name>Ильнар</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%A1%D0%BE%D1%80%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B0&amp;diff=46807</id>
		<title>Сортировка</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%A1%D0%BE%D1%80%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B0&amp;diff=46807"/>
				<updated>2015-05-23T16:57:24Z</updated>
		
		<summary type="html">&lt;p&gt;Ильнар: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;wikitex&amp;gt;&lt;br /&gt;
''Сортировкой'' (англ. ''sorting'') называется процесс упорядочивания множества объектов по какому-либо признаку.&lt;br /&gt;
&lt;br /&gt;
Так как данные могут хранится в разных структурах, то и алгоритмы для каждой структуры могут отличаться. Например, при хранении данных в списке сортировка кучей потребует $O(n^2 \log n)$ времени против $O(n \log n)$ с использованием массива; а вот сортировка пузырьком не изменится.&lt;br /&gt;
&lt;br /&gt;
Также есть алгоритмы параллельной сортировки данных (т.н. [[Сортирующие сети]]), время работы которых в лучшем случае $O(\log n)$. &lt;br /&gt;
== Классификация сортировок ==&lt;br /&gt;
&lt;br /&gt;
=== Время работы ===&lt;br /&gt;
&lt;br /&gt;
Эту классификацию обычно считают самой важной. Оценивают худшее время алгоритма, среднее и лучшее. Лучшее время — минимальное время работы алгоритма на каком-либо наборе, обычно этим набором является тривиальный $\big[ 1 \ldots n \big] $. Худшее время — наибольшее время.&lt;br /&gt;
У большинства алгоритмов временные оценки бывают $O(n \log n)$ и $O(n^2)$.&lt;br /&gt;
&lt;br /&gt;
=== Память ===&lt;br /&gt;
&lt;br /&gt;
Параметр сортировки, показывающий, сколько '''дополнительной''' памяти требуется алгоритму. Сюда входят и дополнительный массив, и переменные, и затраты на стек вызовов. Обычно затраты бывают $O(1)$, $O(\log n)$, $O(n)$.&lt;br /&gt;
&lt;br /&gt;
=== Устойчивость ===&lt;br /&gt;
&lt;br /&gt;
''Устойчивой сортировкой'' называется сортировка, не меняющая порядка объектов с одинаковыми ключами. Ключ — поле элемента, по которому мы производим сортировку. &lt;br /&gt;
&lt;br /&gt;
=== Количество обменов ===&lt;br /&gt;
&lt;br /&gt;
Количество обменов может быть важным параметром в случае, если объекты имеют большой размер. В таком случае при большом количестве обменов время алгоритма заметно увеличивается.&lt;br /&gt;
&lt;br /&gt;
=== Детерминированность ===&lt;br /&gt;
&lt;br /&gt;
Алгоритм сортировки называется ''детерминированным'', если каждая операция присваивания, обмена и т.д. не зависит от предыдущих.&lt;br /&gt;
Все сортирующие сети являются детерминированными.&lt;br /&gt;
&lt;br /&gt;
== Сравнение сортировок ==&lt;br /&gt;
&lt;br /&gt;
Рассмотрим массив $\big[ 1 \ldots n \big]$. Для элементов должно выполняться отношение порядка.&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
!width=&amp;quot;15%&amp;quot;|Название !!width=&amp;quot;8%&amp;quot;| Лучшее время !!width=&amp;quot;8%&amp;quot;| Среднее !!width=&amp;quot;8%&amp;quot;| Худшее !!width=&amp;quot;8%&amp;quot;| Память !! width=&amp;quot;8%&amp;quot;|Устойчивость !! width=&amp;quot;10%| Обмены (в среднем) !! &amp;quot;width=&amp;quot;35%&amp;quot;| Описание&lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|[[Сортировка пузырьком| Сортировка пузырьком &amp;lt;br&amp;gt;(Bubble Sort)]]&lt;br /&gt;
|$O(n)$&lt;br /&gt;
|$O(n^2)$&lt;br /&gt;
|$O(n^2)$&lt;br /&gt;
|$O(1)$&lt;br /&gt;
|Да&lt;br /&gt;
|$O(n^2)$&lt;br /&gt;
|Алгоритм состоит в повторяющихся проходах по сортируемому массиву. На каждой итерации последовательно сравниваются соседние элементы, и, если порядок в паре неверный, то элементы меняют местами.&lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|[[Сортировка вставками| Сортировка вставками &amp;lt;br&amp;gt;(Insertion Sort)]]&lt;br /&gt;
|$O(n)$&lt;br /&gt;
|$O(n^2)$&lt;br /&gt;
|$O(n^2)$&lt;br /&gt;
|$O(1)$&lt;br /&gt;
|Да&lt;br /&gt;
|$O(n^2)$&lt;br /&gt;
|На каждом шаге алгоритма мы выбираем один из элементов входных данных и вставляем его на нужную позицию в уже отсортированной части массива до тех пор, пока весь набор входных данных не будет отсортирован.&lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|[[Сортировка Шелла| Сортировка Шелла &amp;lt;br&amp;gt;(Shellsort)]]&lt;br /&gt;
|$O(n\log^2{n})$&lt;br /&gt;
|Зависит от выбора шага&lt;br /&gt;
|$O(n^2)$&lt;br /&gt;
|$O(1)$&lt;br /&gt;
|Нет&lt;br /&gt;
|$O(n^2)$&lt;br /&gt;
|Является модификацией сортировки вставками, сортируем между собой элементы, стоящие на кратных нашему шагу местах. &lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|[[Сортировка выбором| Сортировка выбором&amp;lt;br&amp;gt; (Selection Sort)]]&lt;br /&gt;
|$O(n^2)$&lt;br /&gt;
|$O(n^2)$&lt;br /&gt;
|$O(n^2)$&lt;br /&gt;
|$O(1)$&lt;br /&gt;
|Нет&lt;br /&gt;
|$O(n)$&lt;br /&gt;
|На $i$-ом шаге алгоритма находим минимальный среди последних $n - i + 1$, и меняем его местами с $i$-ым элементом в массиве.&lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|[[Быстрая сортировка|Быстрая сортировка&amp;lt;br&amp;gt; (Quick Sort)]]&lt;br /&gt;
|$O(n \log n)$&lt;br /&gt;
|$O(n \log n)$&lt;br /&gt;
|$O(n^2)$&amp;lt;br&amp;gt;(маловероятно)&lt;br /&gt;
|$O(\log n)$&amp;lt;br&amp;gt;(стек вызовов)&lt;br /&gt;
|Нет&lt;br /&gt;
|$O(n \log n)$&lt;br /&gt;
|Один из самых известных и широко используемых алгоритмов сортировки. Алгоритм состоит в выборе опорного элемента, разделении массива на 2 части относительно опорного (одна — все элементы, меньшие опорного элемента, вторая — большие), и в сортировке полученных частей рекурсивным вызовом себя от них.&lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|[[Сортировка слиянием|Сортировка слиянием &amp;lt;br&amp;gt;(Merge Sort)]]&lt;br /&gt;
|$O(n \log n)$&lt;br /&gt;
|$O(n \log n)$&lt;br /&gt;
|$O(n \log n)$&lt;br /&gt;
|$O(n)$ (обычная реализация)&amp;lt;br&amp;gt;$O(\log n)$&amp;lt;br&amp;gt; ([[Cортировка слиянием с использованием O(1) дополнительной памяти|модифицированная реализация]])&lt;br /&gt;
|Да&lt;br /&gt;
|$O(n \log n)$&lt;br /&gt;
|Алгоритм состоит в разделении массива пополам, сортировки половин и их слиянии.&lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|[[Timsort| Timsort]]&lt;br /&gt;
|$O(n)$&lt;br /&gt;
|$O(n\log{n})$&lt;br /&gt;
|$O(n\log{n})$&lt;br /&gt;
|$O(n)$&lt;br /&gt;
|Да&lt;br /&gt;
|$O(n\log{n})$&lt;br /&gt;
|Гибрид сортировки слиянием. Разбиваем массив на подмассивы фиксированной длины и сортируем каждый подмассив любой устойчивой сортировкой. После чего объединяем отсортированные подмассивы модифицированной сортировкой слиянием.&lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|[[Сортировка кучей|Сортировка кучей &amp;lt;br&amp;gt;(Heap Sort)]]&lt;br /&gt;
|$O(n \log n)$&lt;br /&gt;
|$O(n \log n)$&lt;br /&gt;
|$O(n \log n)$&lt;br /&gt;
|$O(1)$&lt;br /&gt;
|Нет&lt;br /&gt;
|$O(n \log n)$&lt;br /&gt;
|Строим из массива кучу, по очереди извлекаем минимум кучи.&lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|[[Smoothsort| Плавная сортировка &amp;lt;br&amp;gt;(Smoothsort)]]&lt;br /&gt;
|$O(n)$&lt;br /&gt;
|$O(n\log{n})$&lt;br /&gt;
|$O(n\log{n})$&lt;br /&gt;
|$O(1)$&lt;br /&gt;
|Нет&lt;br /&gt;
|$O(n\log{n})$&lt;br /&gt;
|Модификация сортировки кучей. Вместо двоичной кучи используем K-ую кучу Леонардо.&lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|[[Терпеливая сортировка| Терпеливая сортировка &amp;lt;br&amp;gt;(Patience sorting)]]&lt;br /&gt;
|$O(n\log{n})$&lt;br /&gt;
|$O(n\log{n})$&lt;br /&gt;
|$O(n\log{n})$&lt;br /&gt;
|$O(n)$&lt;br /&gt;
|Нет&lt;br /&gt;
|$O(n\log{n})$&lt;br /&gt;
|Раскидываем элементы массива по стопкам, после чего строим двоичную кучу из стопок. Позволяет также вычислить длину наибольшей возрастающей подпоследовательности данного массива. &lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|[[Дерево поиска, наивная реализация|Сортировка с помощью бинарного дерева &amp;lt;br&amp;gt;(Tree Sort)]]&lt;br /&gt;
|$O(n)$&lt;br /&gt;
|$O(n \log n)$&lt;br /&gt;
|$O(n \log n)$&lt;br /&gt;
|$O(n)$&lt;br /&gt;
|Да&lt;br /&gt;
|$O(n)$&lt;br /&gt;
|Добавляем по очереди вершины в сбалансированное дерево поиска, проходим по всем вершинам в порядке возрастания.&lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|[[Карманная сортировка|Карманная сортировка &amp;lt;br&amp;gt;(Bucket Sort)]]&lt;br /&gt;
|$O(n + k)$&lt;br /&gt;
|$O(n \log_k n)$&lt;br /&gt;
|$O(n \cdot k)$&lt;br /&gt;
|$O(n)$&lt;br /&gt;
|Да&lt;br /&gt;
| -&lt;br /&gt;
|Распределяем элементы в $k$ карманов, сортируем элементы внутри карманов, из каждого кармана данные записываются в массив в порядке разбиения.&lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|[[Цифровая сортировка|Цифровая сортировка &amp;lt;br&amp;gt;(Radix Sort)]]&lt;br /&gt;
|$O(n \lg n)$&lt;br /&gt;
|$O(n \lg n)$&lt;br /&gt;
|$O(n \lg n)$&lt;br /&gt;
|$O(n)$&lt;br /&gt;
|Да&lt;br /&gt;
| -&lt;br /&gt;
|Сортировка объектов равной длины, имеющих &amp;quot;разряды&amp;quot;. обычно это строки или целые числа. Алгоритм состоит в том, чтобы отсортировать объекты по разрядам, начиная от младших к старшим.&lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|[[Сортировка подсчетом|Сортировка подсчетом &amp;lt;br&amp;gt;(Counting Sort)]]&lt;br /&gt;
|$O(n)$&lt;br /&gt;
|$O(n + k)$&lt;br /&gt;
|$O(k)$&lt;br /&gt;
|$O(k)$&lt;br /&gt;
|Да&lt;br /&gt;
|$O(n + k)$&lt;br /&gt;
|Сортировка целых чисел, входящих в какой-то небольшой диапазон. Создаем массив длины диапазона $k$, каждый элемент которого будет показывать, сколько исходных элементов равны данному. Бежим по массиву и считаем количество вхождений каждого числа.&lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|[[Сортировка Хэна (или Хана?)|Сортировка Хэна &amp;lt;br&amp;gt;(Han's Sort)]]&lt;br /&gt;
|$O(n \log \log n)$&lt;br /&gt;
|$O(n \log \log n)$&lt;br /&gt;
|$O(n \log \log n)$&lt;br /&gt;
|$O(n)$&lt;br /&gt;
|Да&lt;br /&gt;
|$O(n \log \log n)$&lt;br /&gt;
|Очень сложная сортировка, основанная на принадлежности ключей к целым числам. использует экспоненциальное поисковое дерево Андерсона.&lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|[[Многопоточная сортировка слиянием|Многопоточная сортировка слиянием &amp;lt;br&amp;gt;(Multithreaded merge sort)]]&lt;br /&gt;
|$O(\frac{n}{N_{ind}}\log \frac{n}{N_{ind}})$&lt;br /&gt;
|$O(\frac{n}{N_{ind}}\log \frac{n}{N_{ind}})$&lt;br /&gt;
|$O(\frac{n}{N_{ind}}\log \frac{n}{N_{ind}})$&lt;br /&gt;
|$O(n)$&lt;br /&gt;
|Да&lt;br /&gt;
|$O(n \log n)$&lt;br /&gt;
|Отличается от сортировки слиянием только тем, что при рекурсивном вызове будет создавать новый поток.&lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|[[PSRS-сортировка|PSRS-сортировка &amp;lt;br&amp;gt;(PSRS-sorting)]]&lt;br /&gt;
|$O(\frac{n}{N_{ind}}\log \frac{n}{N_{ind}})$&lt;br /&gt;
|$O(\frac{n}{N_{ind}}\log \frac{n}{N_{ind}})$&lt;br /&gt;
|$O(\frac{n}{N_{ind}}\log \frac{n}{N_{ind}})$&lt;br /&gt;
|$O(N_{ind}^2)$&lt;br /&gt;
|Нет&lt;br /&gt;
|$O(n \log n)$&lt;br /&gt;
|Разделим массив на $N_{ind}$ подмассива и запустим в каждой быструю сортировку. После этого объединим все эти подмассивы.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Источники информации==&lt;br /&gt;
&lt;br /&gt;
[http://ru.wikipedia.org/wiki/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D1%81%D0%BE%D1%80%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B8 Википедия {{---}} Алгоритмы сортировки]&lt;br /&gt;
&amp;lt;/wikitex&amp;gt;&lt;br /&gt;
[[Категория: Дискретная математика и алгоритмы]]&lt;br /&gt;
[[Категория: Сортировки]]&lt;/div&gt;</summary>
		<author><name>Ильнар</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%A1%D0%BE%D1%80%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B0&amp;diff=46806</id>
		<title>Сортировка</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%A1%D0%BE%D1%80%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B0&amp;diff=46806"/>
				<updated>2015-05-23T14:23:42Z</updated>
		
		<summary type="html">&lt;p&gt;Ильнар: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;wikitex&amp;gt;&lt;br /&gt;
''Сортировкой'' (англ. ''sorting'') называется процесс упорядочивания множества объектов по какому-либо признаку.&lt;br /&gt;
&lt;br /&gt;
Так как данные могут хранится в разных структурах, то и алгоритмы для каждой структуры могут отличаться. Например, при хранении данных в списке сортировка кучей потребует $O(n^2 \log n)$ времени против $O(n \log n)$ с использованием массива; а вот сортировка пузырьком не изменится.&lt;br /&gt;
&lt;br /&gt;
Также есть алгоритмы параллельной сортировки данных (т.н. [[Сортирующие сети]]), время работы которых в лучшем случае $O(\log n)$. &lt;br /&gt;
== Классификация сортировок ==&lt;br /&gt;
&lt;br /&gt;
=== Время работы ===&lt;br /&gt;
&lt;br /&gt;
Эту классификацию обычно считают самой важной. Оценивают худшее время алгоритма, среднее и лучшее. Лучшее время — минимальное время работы алгоритма на каком-либо наборе, обычно этим набором является тривиальный $\big[ 1 \ldots n \big] $. Худшее время — наибольшее время.&lt;br /&gt;
У большинства алгоритмов временные оценки бывают $O(n \log n)$ и $O(n^2)$.&lt;br /&gt;
&lt;br /&gt;
=== Память ===&lt;br /&gt;
&lt;br /&gt;
Параметр сортировки, показывающий, сколько '''дополнительной''' памяти требуется алгоритму. Сюда входят и дополнительный массив, и переменные, и затраты на стек вызовов. Обычно затраты бывают $O(1)$, $O(\log n)$, $O(n)$.&lt;br /&gt;
&lt;br /&gt;
=== Устойчивость ===&lt;br /&gt;
&lt;br /&gt;
''Устойчивой сортировкой'' называется сортировка, не меняющая порядка объектов с одинаковыми ключами. Ключ — поле элемента, по которому мы производим сортировку. &lt;br /&gt;
&lt;br /&gt;
=== Количество обменов ===&lt;br /&gt;
&lt;br /&gt;
Количество обменов может быть важным параметром в случае, если объекты имеют большой размер. В таком случае при большом количестве обменов время алгоритма заметно увеличивается.&lt;br /&gt;
&lt;br /&gt;
=== Детерминированность ===&lt;br /&gt;
&lt;br /&gt;
Алгоритм сортировки называется ''детерминированным'', если каждая операция присваивания, обмена и т.д. не зависит от предыдущих.&lt;br /&gt;
Все сортирующие сети являются детерминированными.&lt;br /&gt;
&lt;br /&gt;
== Сравнение сортировок ==&lt;br /&gt;
&lt;br /&gt;
Рассмотрим массив $\big[ 1 \ldots n \big]$. Для элементов должно выполняться отношение порядка.&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
!width=&amp;quot;15%&amp;quot;|Название !!width=&amp;quot;8%&amp;quot;| Лучшее время !!width=&amp;quot;8%&amp;quot;| Среднее !!width=&amp;quot;8%&amp;quot;| Худшее !!width=&amp;quot;8%&amp;quot;| Память !! width=&amp;quot;8%&amp;quot;|Устойчивость !! width=&amp;quot;10%| Обмены (в среднем) !! &amp;quot;width=&amp;quot;35%&amp;quot;| Описание&lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|[[Сортировка пузырьком| Сортировка пузырьком &amp;lt;br&amp;gt;(Bubble Sort)]]&lt;br /&gt;
|$O(n)$&lt;br /&gt;
|$O(n^2)$&lt;br /&gt;
|$O(n^2)$&lt;br /&gt;
|$O(1)$&lt;br /&gt;
|Да&lt;br /&gt;
|$O(n^2)$&lt;br /&gt;
|Алгоритм состоит в повторяющихся проходах по сортируемому массиву. На каждой итерации последовательно сравниваются соседние элементы, и, если порядок в паре неверный, то элементы меняют местами.&lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|[[Сортировка вставками| Сортировка вставками &amp;lt;br&amp;gt;(Insertion Sort)]]&lt;br /&gt;
|$O(n)$&lt;br /&gt;
|$O(n^2)$&lt;br /&gt;
|$O(n^2)$&lt;br /&gt;
|$O(1)$&lt;br /&gt;
|Да&lt;br /&gt;
|$O(n^2)$&lt;br /&gt;
|На каждом шаге алгоритма мы выбираем один из элементов входных данных и вставляем его на нужную позицию в уже отсортированной части массива до тех пор, пока весь набор входных данных не будет отсортирован.&lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|[[Сортировка Шелла| Сортировка Шелла &amp;lt;br&amp;gt;(Shellsort)]]&lt;br /&gt;
|$O(n\log^2{n})$&lt;br /&gt;
|Зависит от выбора шага&lt;br /&gt;
|$O(n^2)$&lt;br /&gt;
|$O(1)$&lt;br /&gt;
|Нет&lt;br /&gt;
|$O(n^2)$&lt;br /&gt;
|Является модификацией сортировки вставками, сортируем между собой элементы, стоящие на кратных нашему шагу местах. &lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|[[Сортировка выбором| Сортировка выбором&amp;lt;br&amp;gt; (Selection Sort)]]&lt;br /&gt;
|$O(n^2)$&lt;br /&gt;
|$O(n^2)$&lt;br /&gt;
|$O(n^2)$&lt;br /&gt;
|$O(1)$&lt;br /&gt;
|Нет&lt;br /&gt;
|$O(n)$&lt;br /&gt;
|На $i$-ом шаге алгоритма находим минимальный среди последних $n - i + 1$, и меняем его местами с $i$-ым элементом в массиве.&lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|[[Быстрая сортировка|Быстрая сортировка&amp;lt;br&amp;gt; (Quick Sort)]]&lt;br /&gt;
|$O(n \log n)$&lt;br /&gt;
|$O(n \log n)$&lt;br /&gt;
|$O(n^2)$&amp;lt;br&amp;gt;(маловероятно)&lt;br /&gt;
|$O(\log n)$&amp;lt;br&amp;gt;(стек вызовов)&lt;br /&gt;
|Нет&lt;br /&gt;
|$O(n \log n)$&lt;br /&gt;
|Один из самых известных и широко используемых алгоритмов сортировки. Алгоритм состоит в выборе опорного элемента, разделении массива на 2 части относительно опорного (одна — все элементы, меньшие опорного элемента, вторая — большие), и в сортировке полученных частей рекурсивным вызовом себя от них.&lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|[[Сортировка слиянием|Сортировка слиянием &amp;lt;br&amp;gt;(Merge Sort)]]&lt;br /&gt;
|$O(n \log n)$&lt;br /&gt;
|$O(n \log n)$&lt;br /&gt;
|$O(n \log n)$&lt;br /&gt;
|$O(n)$ (обычная реализация)&amp;lt;br&amp;gt;$O(\log n)$&amp;lt;br&amp;gt; ([[Cортировка слиянием с использованием O(1) дополнительной памяти|модифицированная реализация]])&lt;br /&gt;
|Да&lt;br /&gt;
|$O(n \log n)$&lt;br /&gt;
|Алгоритм состоит в разделении массива пополам, сортировки половин и их слиянии.&lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|[[Timsort| Timsort]]&lt;br /&gt;
|$O(n)$&lt;br /&gt;
|$O(n\log{n})$&lt;br /&gt;
|$O(n\log{n})$&lt;br /&gt;
|$O(n)$&lt;br /&gt;
|Да&lt;br /&gt;
|$O(n\log{n})$&lt;br /&gt;
|Гибрид сортировки слиянием. Разбиваем массив на подмассивы фиксированной длины и сортируем каждый подмассив любой устойчивой сортировкой. После чего объединяем отсортированные подмассивы модифицированной сортировкой слиянием.&lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|[[Сортировка кучей|Сортировка кучей &amp;lt;br&amp;gt;(Heap Sort)]]&lt;br /&gt;
|$O(n \log n)$&lt;br /&gt;
|$O(n \log n)$&lt;br /&gt;
|$O(n \log n)$&lt;br /&gt;
|$O(1)$&lt;br /&gt;
|Нет&lt;br /&gt;
|$O(n \log n)$&lt;br /&gt;
|Строим из массива кучу, по очереди извлекаем минимум кучи.&lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|[[Smoothsort| Плавная сортировка &amp;lt;br&amp;gt;(Smoothsort)]]&lt;br /&gt;
|$O(n)$&lt;br /&gt;
|$O(n\log{n})$&lt;br /&gt;
|$O(n\log{n})$&lt;br /&gt;
|$O(1)$&lt;br /&gt;
|Нет&lt;br /&gt;
|$O(n\log{n})$&lt;br /&gt;
|Модификация сортировки кучей. Вместо двоичной кучи используем K-ую кучу Леонардо.&lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|[[Терпеливая сортировка| Терпеливая сортировка &amp;lt;br&amp;gt;(Patience sorting)]]&lt;br /&gt;
|$O(n\log{n})$&lt;br /&gt;
|$O(n\log{n})$&lt;br /&gt;
|$O(n\log{n})$&lt;br /&gt;
|$O(n)$&lt;br /&gt;
|Нет&lt;br /&gt;
|$O(n\log{n})$&lt;br /&gt;
|Раскидываем элементы массива по стопкам, после чего строим двоичную кучу из стопок. Позволяет также вычислить длину наибольшей возрастающей подпоследовательности данного массива. &lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|[[Дерево поиска, наивная реализация|Сортировка с помощью бинарного дерева &amp;lt;br&amp;gt;(Tree Sort)]]&lt;br /&gt;
|$O(n)$&lt;br /&gt;
|$O(n \log n)$&lt;br /&gt;
|$O(n \log n)$&lt;br /&gt;
|$O(n)$&lt;br /&gt;
|Да&lt;br /&gt;
|$O(n)$&lt;br /&gt;
|Добавляем по очереди вершины в сбалансированное дерево поиска, проходим по всем вершинам в порядке возрастания.&lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|[[Карманная сортировка|Карманная сортировка &amp;lt;br&amp;gt;(Bucket Sort)]]&lt;br /&gt;
|$O(n + k)$&lt;br /&gt;
|$O(n \log_k n)$&lt;br /&gt;
|$O(n \cdot k)$&lt;br /&gt;
|$O(n)$&lt;br /&gt;
|Да&lt;br /&gt;
| -&lt;br /&gt;
|Распределяем элементы в $k$ карманов, сортируем элементы внутри карманов, из каждого кармана данные записываются в массив в порядке разбиения.&lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|[[Цифровая сортировка|Цифровая сортировка &amp;lt;br&amp;gt;(Radix Sort)]]&lt;br /&gt;
|$O(n \lg n)$&lt;br /&gt;
|$O(n \lg n)$&lt;br /&gt;
|$O(n \lg n)$&lt;br /&gt;
|$O(n)$&lt;br /&gt;
|Да&lt;br /&gt;
| -&lt;br /&gt;
|Сортировка объектов равной длины, имеющих &amp;quot;разряды&amp;quot;. обычно это строки или целые числа. Алгоритм состоит в том, чтобы отсортировать объекты по разрядам, начиная от младших к старшим.&lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|[[Сортировка подсчетом|Сортировка подсчетом &amp;lt;br&amp;gt;(Counting Sort)]]&lt;br /&gt;
|$O(n)$&lt;br /&gt;
|$O(n + k)$&lt;br /&gt;
|$O(k)$&lt;br /&gt;
|$O(k)$&lt;br /&gt;
|Да&lt;br /&gt;
|$O(n + k)$&lt;br /&gt;
|Сортировка целых чисел, входящих в какой-то небольшой диапазон. Создаем массив длины диапазона $k$, каждый элемент которого будет показывать, сколько исходных элементов равны данному. Бежим по массиву и считаем количество вхождений каждого числа.&lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|[[Сортировка Хэна (или Хана?)|Сортировка Хэна &amp;lt;br&amp;gt;(Han's Sort)]]&lt;br /&gt;
|$O(n \log \log n)$&lt;br /&gt;
|$O(n \log \log n)$&lt;br /&gt;
|$O(n \log \log n)$&lt;br /&gt;
|$O(n)$&lt;br /&gt;
|Да&lt;br /&gt;
|$O(n \log \log n)$&lt;br /&gt;
|Очень сложная сортировка, основанная на принадлежности ключей к целым числам. использует экспоненциальное поисковое дерево Андерсона.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Источники информации==&lt;br /&gt;
&lt;br /&gt;
[http://ru.wikipedia.org/wiki/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D1%81%D0%BE%D1%80%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B8 Википедия {{---}} Алгоритмы сортировки]&lt;br /&gt;
&amp;lt;/wikitex&amp;gt;&lt;br /&gt;
[[Категория: Дискретная математика и алгоритмы]]&lt;br /&gt;
[[Категория: Сортировки]]&lt;/div&gt;</summary>
		<author><name>Ильнар</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%A1%D0%BE%D1%80%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B0&amp;diff=46805</id>
		<title>Сортировка</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%A1%D0%BE%D1%80%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B0&amp;diff=46805"/>
				<updated>2015-05-23T14:19:01Z</updated>
		
		<summary type="html">&lt;p&gt;Ильнар: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;wikitex&amp;gt;&lt;br /&gt;
''Сортировкой'' называется процесс упорядочивания множества объектов по какому-либо признаку.&lt;br /&gt;
&lt;br /&gt;
Так как данные могут хранится в разных структурах, то и алгоритмы для каждой структуры могут отличаться. Например, при хранении данных в списке сортировка кучей потребует $O(n^2 \log n)$ времени против $O(n \log n)$ с использованием массива; а вот сортировка пузырьком не изменится.&lt;br /&gt;
&lt;br /&gt;
Также есть алгоритмы параллельной сортировки данных (т.н. [[Сортирующие сети]]), время работы которых в лучшем случае $O(\log n)$. &lt;br /&gt;
== Классификация сортировок ==&lt;br /&gt;
&lt;br /&gt;
=== Время работы ===&lt;br /&gt;
&lt;br /&gt;
Эту классификацию обычно считают самой важной. Оценивают худшее время алгоритма, среднее и лучшее. Лучшее время — минимальное время работы алгоритма на каком-либо наборе, обычно этим набором является тривиальный $\big[ 1 \ldots n \big] $. Худшее время — наибольшее время.&lt;br /&gt;
У большинства алгоритмов временные оценки бывают $O(n \log n)$ и $O(n^2)$.&lt;br /&gt;
&lt;br /&gt;
=== Память ===&lt;br /&gt;
&lt;br /&gt;
Параметр сортировки, показывающий, сколько '''дополнительной''' памяти требуется алгоритму. Сюда входят и дополнительный массив, и переменные, и затраты на стек вызовов. Обычно затраты бывают $O(1)$, $O(\log n)$, $O(n)$.&lt;br /&gt;
&lt;br /&gt;
=== Устойчивость ===&lt;br /&gt;
&lt;br /&gt;
''Устойчивой сортировкой'' называется сортировка, не меняющая порядка объектов с одинаковыми ключами. Ключ — поле элемента, по которому мы производим сортировку. &lt;br /&gt;
&lt;br /&gt;
=== Количество обменов ===&lt;br /&gt;
&lt;br /&gt;
Количество обменов может быть важным параметром в случае, если объекты имеют большой размер. В таком случае при большом количестве обменов время алгоритма заметно увеличивается.&lt;br /&gt;
&lt;br /&gt;
=== Детерминированность ===&lt;br /&gt;
&lt;br /&gt;
Алгоритм сортировки называется ''детерминированным'', если каждая операция присваивания, обмена и т.д. не зависит от предыдущих.&lt;br /&gt;
Все сортирующие сети являются детерминированными.&lt;br /&gt;
&lt;br /&gt;
== Сравнение сортировок ==&lt;br /&gt;
&lt;br /&gt;
Рассмотрим массив $\big[ 1 \ldots n \big]$. Для элементов должно выполняться отношение порядка.&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
!width=&amp;quot;15%&amp;quot;|Название !!width=&amp;quot;8%&amp;quot;| Лучшее время !!width=&amp;quot;8%&amp;quot;| Среднее !!width=&amp;quot;8%&amp;quot;| Худшее !!width=&amp;quot;8%&amp;quot;| Память !! width=&amp;quot;8%&amp;quot;|Устойчивость !! width=&amp;quot;10%| Обмены (в среднем) !! &amp;quot;width=&amp;quot;35%&amp;quot;| Описание&lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|[[Сортировка пузырьком| Сортировка пузырьком &amp;lt;br&amp;gt;(Bubble Sort)]]&lt;br /&gt;
|$O(n)$&lt;br /&gt;
|$O(n^2)$&lt;br /&gt;
|$O(n^2)$&lt;br /&gt;
|$O(1)$&lt;br /&gt;
|Да&lt;br /&gt;
|$O(n^2)$&lt;br /&gt;
|Алгоритм состоит в повторяющихся проходах по сортируемому массиву. На каждой итерации последовательно сравниваются соседние элементы, и, если порядок в паре неверный, то элементы меняют местами.&lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|[[Сортировка вставками| Сортировка вставками &amp;lt;br&amp;gt;(Insertion Sort)]]&lt;br /&gt;
|$O(n)$&lt;br /&gt;
|$O(n^2)$&lt;br /&gt;
|$O(n^2)$&lt;br /&gt;
|$O(1)$&lt;br /&gt;
|Да&lt;br /&gt;
|$O(n^2)$&lt;br /&gt;
|На каждом шаге алгоритма мы выбираем один из элементов входных данных и вставляем его на нужную позицию в уже отсортированной части массива до тех пор, пока весь набор входных данных не будет отсортирован.&lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|[[Сортировка Шелла| Сортировка Шелла &amp;lt;br&amp;gt;(Shellsort)]]&lt;br /&gt;
|$O(n\log^2{n})$&lt;br /&gt;
|Зависит от выбора шага&lt;br /&gt;
|$O(n^2)$&lt;br /&gt;
|$O(1)$&lt;br /&gt;
|Нет&lt;br /&gt;
|$O(n^2)$&lt;br /&gt;
|Является модификацией сортировки вставками, сортируем между собой элементы, стоящие на кратных нашему шагу местах. &lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|[[Сортировка выбором| Сортировка выбором&amp;lt;br&amp;gt; (Selection Sort)]]&lt;br /&gt;
|$O(n^2)$&lt;br /&gt;
|$O(n^2)$&lt;br /&gt;
|$O(n^2)$&lt;br /&gt;
|$O(1)$&lt;br /&gt;
|Нет&lt;br /&gt;
|$O(n)$&lt;br /&gt;
|На $i$-ом шаге алгоритма находим минимальный среди последних $n - i + 1$, и меняем его местами с $i$-ым элементом в массиве.&lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|[[Быстрая сортировка|Быстрая сортировка&amp;lt;br&amp;gt; (Quick Sort)]]&lt;br /&gt;
|$O(n \log n)$&lt;br /&gt;
|$O(n \log n)$&lt;br /&gt;
|$O(n^2)$&amp;lt;br&amp;gt;(маловероятно)&lt;br /&gt;
|$O(\log n)$&amp;lt;br&amp;gt;(стек вызовов)&lt;br /&gt;
|Нет&lt;br /&gt;
|$O(n \log n)$&lt;br /&gt;
|Один из самых известных и широко используемых алгоритмов сортировки. Алгоритм состоит в выборе опорного элемента, разделении массива на 2 части относительно опорного (одна — все элементы, меньшие опорного элемента, вторая — большие), и в сортировке полученных частей рекурсивным вызовом себя от них.&lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|[[Сортировка слиянием|Сортировка слиянием &amp;lt;br&amp;gt;(Merge Sort)]]&lt;br /&gt;
|$O(n \log n)$&lt;br /&gt;
|$O(n \log n)$&lt;br /&gt;
|$O(n \log n)$&lt;br /&gt;
|$O(n)$ (обычная реализация)&amp;lt;br&amp;gt;$O(\log n)$&amp;lt;br&amp;gt; ([[Cортировка слиянием с использованием O(1) дополнительной памяти|модифицированная реализация]])&lt;br /&gt;
|Да&lt;br /&gt;
|$O(n \log n)$&lt;br /&gt;
|Алгоритм состоит в разделении массива пополам, сортировки половин и их слиянии.&lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|[[Timsort| Timsort]]&lt;br /&gt;
|$O(n)$&lt;br /&gt;
|$O(n\log{n})$&lt;br /&gt;
|$O(n\log{n})$&lt;br /&gt;
|$O(n)$&lt;br /&gt;
|Да&lt;br /&gt;
|$O(n\log{n})$&lt;br /&gt;
|Гибрид сортировки слиянием. Разбиваем массив на подмассивы фиксированной длины и сортируем каждый подмассив любой устойчивой сортировкой. После чего объединяем отсортированные подмассивы модифицированной сортировкой слиянием.&lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|[[Сортировка кучей|Сортировка кучей &amp;lt;br&amp;gt;(Heap Sort)]]&lt;br /&gt;
|$O(n \log n)$&lt;br /&gt;
|$O(n \log n)$&lt;br /&gt;
|$O(n \log n)$&lt;br /&gt;
|$O(1)$&lt;br /&gt;
|Нет&lt;br /&gt;
|$O(n \log n)$&lt;br /&gt;
|Строим из массива кучу, по очереди извлекаем минимум кучи.&lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|[[Smoothsort| Плавная сортировка &amp;lt;br&amp;gt;(Smoothsort)]]&lt;br /&gt;
|$O(n)$&lt;br /&gt;
|$O(n\log{n})$&lt;br /&gt;
|$O(n\log{n})$&lt;br /&gt;
|$O(1)$&lt;br /&gt;
|Нет&lt;br /&gt;
|$O(n\log{n})$&lt;br /&gt;
|Модификация сортировки кучей. Вместо двоичной кучи используем K-ую кучу Леонардо.&lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|[[Терпеливая сортировка| Терпеливая сортировка &amp;lt;br&amp;gt;(Patience sorting)]]&lt;br /&gt;
|$O(n\log{n})$&lt;br /&gt;
|$O(n\log{n})$&lt;br /&gt;
|$O(n\log{n})$&lt;br /&gt;
|$O(n)$&lt;br /&gt;
|Нет&lt;br /&gt;
|$O(n\log{n})$&lt;br /&gt;
|Раскидываем элементы массива по стопкам, после чего строим двоичную кучу из стопок. Позволяет также вычислить длину наибольшей возрастающей подпоследовательности данного массива. &lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|[[Дерево поиска, наивная реализация|Сортировка с помощью бинарного дерева &amp;lt;br&amp;gt;(Tree Sort)]]&lt;br /&gt;
|$O(n)$&lt;br /&gt;
|$O(n \log n)$&lt;br /&gt;
|$O(n \log n)$&lt;br /&gt;
|$O(n)$&lt;br /&gt;
|Да&lt;br /&gt;
|$O(n)$&lt;br /&gt;
|Добавляем по очереди вершины в сбалансированное дерево поиска, проходим по всем вершинам в порядке возрастания.&lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|[[Карманная сортировка|Карманная сортировка &amp;lt;br&amp;gt;(Bucket Sort)]]&lt;br /&gt;
|$O(n + k)$&lt;br /&gt;
|$O(n \log_k n)$&lt;br /&gt;
|$O(n \cdot k)$&lt;br /&gt;
|$O(n)$&lt;br /&gt;
|Да&lt;br /&gt;
| -&lt;br /&gt;
|Распределяем элементы в $k$ карманов, сортируем элементы внутри карманов, из каждого кармана данные записываются в массив в порядке разбиения.&lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|[[Цифровая сортировка|Цифровая сортировка &amp;lt;br&amp;gt;(Radix Sort)]]&lt;br /&gt;
|$O(n \lg n)$&lt;br /&gt;
|$O(n \lg n)$&lt;br /&gt;
|$O(n \lg n)$&lt;br /&gt;
|$O(n)$&lt;br /&gt;
|Да&lt;br /&gt;
| -&lt;br /&gt;
|Сортировка объектов равной длины, имеющих &amp;quot;разряды&amp;quot;. обычно это строки или целые числа. Алгоритм состоит в том, чтобы отсортировать объекты по разрядам, начиная от младших к старшим.&lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|[[Сортировка подсчетом|Сортировка подсчетом &amp;lt;br&amp;gt;(Counting Sort)]]&lt;br /&gt;
|$O(n)$&lt;br /&gt;
|$O(n + k)$&lt;br /&gt;
|$O(k)$&lt;br /&gt;
|$O(k)$&lt;br /&gt;
|Да&lt;br /&gt;
|$O(n + k)$&lt;br /&gt;
|Сортировка целых чисел, входящих в какой-то небольшой диапазон. Создаем массив длины диапазона $k$, каждый элемент которого будет показывать, сколько исходных элементов равны данному. Бежим по массиву и считаем количество вхождений каждого числа.&lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|[[Сортировка Хэна (или Хана?)|Сортировка Хэна &amp;lt;br&amp;gt;(Han's Sort)]]&lt;br /&gt;
|$O(n \log \log n)$&lt;br /&gt;
|$O(n \log \log n)$&lt;br /&gt;
|$O(n \log \log n)$&lt;br /&gt;
|$O(n)$&lt;br /&gt;
|Да&lt;br /&gt;
|$O(n \log \log n)$&lt;br /&gt;
|Очень сложная сортировка, основанная на принадлежности ключей к целым числам. использует экспоненциальное поисковое дерево Андерсона.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Источники информации==&lt;br /&gt;
&lt;br /&gt;
[http://ru.wikipedia.org/wiki/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D1%81%D0%BE%D1%80%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B8 Википедия {{---}} Алгоритмы сортировки]&lt;br /&gt;
&amp;lt;/wikitex&amp;gt;&lt;br /&gt;
[[Категория: Дискретная математика и алгоритмы]]&lt;br /&gt;
[[Категория: Сортировки]]&lt;/div&gt;</summary>
		<author><name>Ильнар</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%A1%D0%BE%D1%80%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B0&amp;diff=46804</id>
		<title>Сортировка</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%A1%D0%BE%D1%80%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B0&amp;diff=46804"/>
				<updated>2015-05-23T14:15:01Z</updated>
		
		<summary type="html">&lt;p&gt;Ильнар: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;wikitex&amp;gt;&lt;br /&gt;
''Сортировкой'' называется процесс упорядочивания множества объектов по какому-либо признаку.&lt;br /&gt;
&lt;br /&gt;
Так как данные могут хранится в разных структурах, то и алгоритмы для каждой структуры могут отличаться. Например, при хранении данных в списке сортировка кучей потребует $O(n^2 \log n)$ времени против $O(n \log n)$ с использованием массива; а вот сортировка пузырьком не изменится.&lt;br /&gt;
&lt;br /&gt;
Также есть алгоритмы параллельной сортировки данных (т.н. [[Сортирующие сети]]), время работы которых в лучшем случае $O(\log n)$. &lt;br /&gt;
== Классификация сортировок ==&lt;br /&gt;
&lt;br /&gt;
=== Время работы ===&lt;br /&gt;
&lt;br /&gt;
Эту классификацию обычно считают самой важной. Оценивают худшее время алгоритма, среднее и лучшее. Лучшее время — минимальное время работы алгоритма на каком-либо наборе, обычно этим набором является тривиальный $\big[ 1 \ldots n \big] $. Худшее время — наибольшее время.&lt;br /&gt;
У большинства алгоритмов временные оценки бывают $O(n \log n)$ и $O(n^2)$.&lt;br /&gt;
&lt;br /&gt;
=== Память ===&lt;br /&gt;
&lt;br /&gt;
Параметр сортировки, показывающий, сколько '''дополнительной''' памяти требуется алгоритму. Сюда входят и дополнительный массив, и переменные, и затраты на стек вызовов. Обычно затраты бывают $O(1)$, $O(\log n)$, $O(n)$.&lt;br /&gt;
&lt;br /&gt;
=== Устойчивость ===&lt;br /&gt;
&lt;br /&gt;
''Устойчивой сортировкой'' называется сортировка, не меняющая порядка объектов с одинаковыми ключами. Ключ — поле элемента, по которому мы производим сортировку. &lt;br /&gt;
&lt;br /&gt;
=== Количество обменов ===&lt;br /&gt;
&lt;br /&gt;
Количество обменов может быть важным параметром в случае, если объекты имеют большой размер. В таком случае при большом количестве обменов время алгоритма заметно увеличивается.&lt;br /&gt;
&lt;br /&gt;
=== Детерминированность ===&lt;br /&gt;
&lt;br /&gt;
Алгоритм сортировки называется ''детерминированным'', если каждая операция присваивания, обмена и т.д. не зависит от предыдущих.&lt;br /&gt;
Все сортирующие сети являются детерминированными.&lt;br /&gt;
&lt;br /&gt;
== Сравнение сортировок ==&lt;br /&gt;
&lt;br /&gt;
Рассмотрим массив $\big[ 1 \ldots n \big]$. Для элементов должно выполняться отношение порядка.&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
!width=&amp;quot;15%&amp;quot;|Название !!width=&amp;quot;8%&amp;quot;| Лучшее время !!width=&amp;quot;8%&amp;quot;| Среднее !!width=&amp;quot;8%&amp;quot;| Худшее !!width=&amp;quot;8%&amp;quot;| Память !! width=&amp;quot;8%&amp;quot;|Устойчивость !! width=&amp;quot;10%| Обмены (в среднем) !! &amp;quot;width=&amp;quot;35%&amp;quot;| Описание&lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|[[Сортировка пузырьком| Сортировка пузырьком &amp;lt;br&amp;gt;(Bubble Sort)]]&lt;br /&gt;
|$O(n)$&lt;br /&gt;
|$O(n^2)$&lt;br /&gt;
|$O(n^2)$&lt;br /&gt;
|$O(1)$&lt;br /&gt;
|Да&lt;br /&gt;
|$O(n^2)$&lt;br /&gt;
|Алгоритм состоит в повторяющихся проходах по сортируемому массиву. На каждой итерации последовательно сравниваются соседние элементы, и, если порядок в паре неверный, то элементы меняют местами.&lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|[[Сортировка вставками| Сортировка вставками &amp;lt;br&amp;gt;(Insertion Sort)]]&lt;br /&gt;
|$O(n)$&lt;br /&gt;
|$O(n^2)$&lt;br /&gt;
|$O(n^2)$&lt;br /&gt;
|$O(1)$&lt;br /&gt;
|Да&lt;br /&gt;
|$O(n^2)$&lt;br /&gt;
|На каждом шаге алгоритма мы выбираем один из элементов входных данных и вставляем его на нужную позицию в уже отсортированной части массива до тех пор, пока весь набор входных данных не будет отсортирован.&lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|[[Сортировка выбором| Сортировка выбором&amp;lt;br&amp;gt; (Selection Sort)]]&lt;br /&gt;
|$O(n^2)$&lt;br /&gt;
|$O(n^2)$&lt;br /&gt;
|$O(n^2)$&lt;br /&gt;
|$O(1)$&lt;br /&gt;
|Нет&lt;br /&gt;
|$O(n)$&lt;br /&gt;
|На $i$-ом шаге алгоритма находим минимальный среди последних $n - i + 1$, и меняем его местами с $i$-ым элементом в массиве.&lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|[[Быстрая сортировка|Быстрая сортировка&amp;lt;br&amp;gt; (Quick Sort)]]&lt;br /&gt;
|$O(n \log n)$&lt;br /&gt;
|$O(n \log n)$&lt;br /&gt;
|$O(n^2)$&amp;lt;br&amp;gt;(маловероятно)&lt;br /&gt;
|$O(\log n)$&amp;lt;br&amp;gt;(стек вызовов)&lt;br /&gt;
|Нет&lt;br /&gt;
|$O(n \log n)$&lt;br /&gt;
|Один из самых известных и широко используемых алгоритмов сортировки. Алгоритм состоит в выборе опорного элемента, разделении массива на 2 части относительно опорного (одна — все элементы, меньшие опорного элемента, вторая — большие), и в сортировке полученных частей рекурсивным вызовом себя от них.&lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|[[Сортировка слиянием|Сортировка слиянием &amp;lt;br&amp;gt;(Merge Sort)]]&lt;br /&gt;
|$O(n \log n)$&lt;br /&gt;
|$O(n \log n)$&lt;br /&gt;
|$O(n \log n)$&lt;br /&gt;
|$O(n)$ (обычная реализация)&amp;lt;br&amp;gt;$O(\log n)$&amp;lt;br&amp;gt; ([[Cортировка слиянием с использованием O(1) дополнительной памяти|модифицированная реализация]])&lt;br /&gt;
|Да&lt;br /&gt;
|$O(n \log n)$&lt;br /&gt;
|Алгоритм состоит в разделении массива пополам, сортировки половин и их слиянии.&lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|[[Сортировка кучей|Сортировка кучей &amp;lt;br&amp;gt;(Heap Sort)]]&lt;br /&gt;
|$O(n \log n)$&lt;br /&gt;
|$O(n \log n)$&lt;br /&gt;
|$O(n \log n)$&lt;br /&gt;
|$O(1)$&lt;br /&gt;
|Нет&lt;br /&gt;
|$O(n \log n)$&lt;br /&gt;
|Строим из массива кучу, по очереди извлекаем минимум кучи.&lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|[[Дерево поиска, наивная реализация|Сортировка с помощью бинарного дерева &amp;lt;br&amp;gt;(Tree Sort)]]&lt;br /&gt;
|$O(n)$&lt;br /&gt;
|$O(n \log n)$&lt;br /&gt;
|$O(n \log n)$&lt;br /&gt;
|$O(n)$&lt;br /&gt;
|Да&lt;br /&gt;
|$O(n)$&lt;br /&gt;
|Добавляем по очереди вершины в сбалансированное дерево поиска, проходим по всем вершинам в порядке возрастания.&lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|[[Карманная сортировка|Карманная сортировка &amp;lt;br&amp;gt;(Bucket Sort)]]&lt;br /&gt;
|$O(n + k)$&lt;br /&gt;
|$O(n \log_k n)$&lt;br /&gt;
|$O(n \cdot k)$&lt;br /&gt;
|$O(n)$&lt;br /&gt;
|Да&lt;br /&gt;
| -&lt;br /&gt;
|Распределяем элементы в $k$ карманов, сортируем элементы внутри карманов, из каждого кармана данные записываются в массив в порядке разбиения.&lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|[[Цифровая сортировка|Цифровая сортировка &amp;lt;br&amp;gt;(Radix Sort)]]&lt;br /&gt;
|$O(n \lg n)$&lt;br /&gt;
|$O(n \lg n)$&lt;br /&gt;
|$O(n \lg n)$&lt;br /&gt;
|$O(n)$&lt;br /&gt;
|Да&lt;br /&gt;
| -&lt;br /&gt;
|Сортировка объектов равной длины, имеющих &amp;quot;разряды&amp;quot;. обычно это строки или целые числа. Алгоритм состоит в том, чтобы отсортировать объекты по разрядам, начиная от младших к старшим.&lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|[[Сортировка подсчетом|Сортировка подсчетом &amp;lt;br&amp;gt;(Counting Sort)]]&lt;br /&gt;
|$O(n)$&lt;br /&gt;
|$O(n + k)$&lt;br /&gt;
|$O(k)$&lt;br /&gt;
|$O(k)$&lt;br /&gt;
|Да&lt;br /&gt;
|$O(n + k)$&lt;br /&gt;
|Сортировка целых чисел, входящих в какой-то небольшой диапазон. Создаем массив длины диапазона $k$, каждый элемент которого будет показывать, сколько исходных элементов равны данному. Бежим по массиву и считаем количество вхождений каждого числа.&lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|[[Сортировка Хэна (или Хана?)|Сортировка Хэна &amp;lt;br&amp;gt;(Han's Sort)]]&lt;br /&gt;
|$O(n \log \log n)$&lt;br /&gt;
|$O(n \log \log n)$&lt;br /&gt;
|$O(n \log \log n)$&lt;br /&gt;
|$O(n)$&lt;br /&gt;
|Да&lt;br /&gt;
|$O(n \log \log n)$&lt;br /&gt;
|Очень сложная сортировка, основанная на принадлежности ключей к целым числам. использует экспоненциальное поисковое дерево Андерсона.&lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|[[Сортировка Шелла| Сортировка Шелла &amp;lt;br&amp;gt;(Shellsort)]]&lt;br /&gt;
|$O(n\log^2{n})$&lt;br /&gt;
|Зависит от выбора шага&lt;br /&gt;
|$O(n^2)$&lt;br /&gt;
|$O(1)$&lt;br /&gt;
|Нет&lt;br /&gt;
|$O(n^2)$&lt;br /&gt;
|Является улучшением сортировки вставками, сортируем между собой элементы, стоящие на кратных нашему шагу местах. &lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|[[Терпеливая сортировка| Терпеливая сортировка &amp;lt;br&amp;gt;(Patience sorting)]]&lt;br /&gt;
|$O(n\log{n})$&lt;br /&gt;
|$O(n\log{n})$&lt;br /&gt;
|$O(n\log{n})$&lt;br /&gt;
|$O(n)$&lt;br /&gt;
|Нет&lt;br /&gt;
|$O(n\log{n})$&lt;br /&gt;
|Раскидываем элементы массива по стопкам, после чего строим двоичную кучу из стопок. Позволяет также вычислить длину наибольшей возрастающей подпоследовательности данного массива. &lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|[[Timsort| Timsort]]&lt;br /&gt;
|$O(n)$&lt;br /&gt;
|$O(n\log{n})$&lt;br /&gt;
|$O(n\log{n})$&lt;br /&gt;
|$O(n)$&lt;br /&gt;
|Да&lt;br /&gt;
|$O(n\log{n})$&lt;br /&gt;
|Гибрид сортировки слиянием. Разбиваем массив на подмассивы фиксированной длины и сортируем каждый подмассив любой устойчивой сортировкой. После чего объединяем отсортированные подмассивы модифицированной сортировкой слиянием.&lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|[[Smoothsort| Плавная сортировка &amp;lt;br&amp;gt;(Smoothsort)]]&lt;br /&gt;
|$O(n)$&lt;br /&gt;
|$O(n\log{n})$&lt;br /&gt;
|$O(n\log{n})$&lt;br /&gt;
|$O(1)$&lt;br /&gt;
|Нет&lt;br /&gt;
|$O(n\log{n})$&lt;br /&gt;
|Модификация сортировки кучей. &lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Источники информации==&lt;br /&gt;
&lt;br /&gt;
[http://ru.wikipedia.org/wiki/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D1%81%D0%BE%D1%80%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B8 Википедия {{---}} Алгоритмы сортировки]&lt;br /&gt;
&amp;lt;/wikitex&amp;gt;&lt;br /&gt;
[[Категория: Дискретная математика и алгоритмы]]&lt;br /&gt;
[[Категория: Сортировки]]&lt;/div&gt;</summary>
		<author><name>Ильнар</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%A1%D0%BE%D1%80%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B0_%D1%81%D0%BB%D0%B8%D1%8F%D0%BD%D0%B8%D0%B5%D0%BC&amp;diff=46802</id>
		<title>Сортировка слиянием</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%A1%D0%BE%D1%80%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B0_%D1%81%D0%BB%D0%B8%D1%8F%D0%BD%D0%B8%D0%B5%D0%BC&amp;diff=46802"/>
				<updated>2015-05-23T13:32:54Z</updated>
		
		<summary type="html">&lt;p&gt;Ильнар: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''Сортировка слиянием''' (англ. ''Merge sort'') {{---}} алгоритм сортировки, пред­ло­женный Джо­ном фон Ней­ма­ном в 1945 го­ду.&lt;br /&gt;
&lt;br /&gt;
Это устойчивый алгоритм, использующий &amp;lt;tex&amp;gt;O(n)&amp;lt;/tex&amp;gt; дополнительной памяти и работающий за &amp;lt;tex&amp;gt;O(n&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;\log n)&amp;lt;/tex&amp;gt; времени.&lt;br /&gt;
&lt;br /&gt;
==Принцип работы==&lt;br /&gt;
[[Файл:Merging_two_arrays.png|270px|right|thumb|Пример работы процедуры слияния.]]&lt;br /&gt;
Алгоритм использует принцип «разделяй и властвуй»: задача разбивается на подзадачи меньшего размера, которые решаются по отдельности, после чего их решения комбинируются для получения решения исходной задачи. Конкретно процедуру сортировки слиянием можно описать следующим образом:&lt;br /&gt;
&lt;br /&gt;
# Если в рассматриваемом массиве один элемент, то он уже отсортирован {{---}} алгоритм завершает работу.&lt;br /&gt;
# Иначе массив разбивается на две части, которые сортируются рекурсивно.&lt;br /&gt;
# После сортировки двух частей массива к ним применяется процедура слияния, которая по двум отсортированным частям получает исходный отсортированный массив.&lt;br /&gt;
&lt;br /&gt;
===Слияние двух массивов===&lt;br /&gt;
У нас есть два массива &amp;lt;tex&amp;gt;a&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt; (фактически это будут две части одного массива, но для удобства будем писать, что у нас просто два массива). Нам надо получить массив &amp;lt;tex&amp;gt;c&amp;lt;/tex&amp;gt; размером &amp;lt;tex&amp;gt;|a| + |b|&amp;lt;/tex&amp;gt;. Для этого можно применить процедуру слияния. Эта процедура заключается в том, что мы сравниваем элементы массивов (начиная с начала) и меньший из них записываем в финальный. И затем, в массиве у которого оказался меньший элемент, переходим к следующему элементу и сравниваем теперь его. В конце, если один из массивов закончился, мы просто дописываем в финальный другой массив. После мы наш финальный массив записываем заместо двух исходных и получаем отсортированный участок.&lt;br /&gt;
&lt;br /&gt;
Множество отсортированных списков с операцией &amp;lt;tex&amp;gt;\mathrm{merge}&amp;lt;/tex&amp;gt; является [[Моноид|моноидом]], где нейтральным элементом будет пустой список.&lt;br /&gt;
&lt;br /&gt;
Ниже приведён псевдокод процедуры слияния, который сливает две части массива &amp;lt;tex&amp;gt;a&amp;lt;/tex&amp;gt; {{---}} &amp;lt;tex&amp;gt;[left; mid)&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;[mid; right)&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 '''function''' merge(a : '''int[n]'''; left, mid, right : '''int'''):&lt;br /&gt;
     it1 = 0&lt;br /&gt;
     it2 = 0&lt;br /&gt;
     result : '''int[right - left]'''&lt;br /&gt;
   &lt;br /&gt;
     '''while''' left + it1 &amp;lt; mid '''and''' mid + it2 &amp;lt; right&lt;br /&gt;
         '''if''' a[left + it1] &amp;lt; a[mid + it2]&lt;br /&gt;
             result[it1 + it2] = a[left + it1]&lt;br /&gt;
             it1 += 1&lt;br /&gt;
         '''else'''&lt;br /&gt;
             result[it1 + it2] = a[mid + it2]&lt;br /&gt;
             it2 += 1&lt;br /&gt;
   &lt;br /&gt;
     '''while''' left + it1 &amp;lt; mid&lt;br /&gt;
         result[it1 + it2] = a[left + it1]&lt;br /&gt;
         it1 += 1&lt;br /&gt;
   &lt;br /&gt;
     '''while''' mid + it2 &amp;lt; right&lt;br /&gt;
         result[it1 + it2] = a[mid + it2]&lt;br /&gt;
         it2 += 1&lt;br /&gt;
   &lt;br /&gt;
     '''for''' i = 0 '''to''' it1 + it2&lt;br /&gt;
         a[left + i] = result[i]&lt;br /&gt;
&lt;br /&gt;
===Рекурсивный алгоритм===&lt;br /&gt;
[[Файл:Merge sort1.png|300px|right|thumb|Пример работы рекурсивного алгоритма сортировки слиянием]]&lt;br /&gt;
Функция сортирует подотрезок массива с индексами в полуинтервале &amp;lt;tex&amp;gt;[left; right)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&amp;lt;code style=&amp;quot;display: inline-block&amp;quot;&amp;gt;&lt;br /&gt;
 '''function''' mergeSortRecursive(a : '''int[n]'''; left, right : '''int'''):&lt;br /&gt;
     '''if''' left + 1 &amp;gt;= right&lt;br /&gt;
         '''return'''&lt;br /&gt;
     mid = (left + right) / 2&lt;br /&gt;
     mergeSortRecursive(a, left, mid)&lt;br /&gt;
     mergeSortRecursive(a, mid, right)&lt;br /&gt;
     merge(a, left, mid, right)&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
===Итеративный алгоритм===&lt;br /&gt;
[[Файл:Merge sort itearative.png|300px|right|thumb|Пример работы итеративного алгоритма сортировки слиянием]]&lt;br /&gt;
При итеративном алгоритме используется на &amp;lt;tex&amp;gt;O(\log n)&amp;lt;/tex&amp;gt; меньше памяти, которая раньше тратилась на рекурсивные вызовы.&lt;br /&gt;
&amp;lt;code style=&amp;quot;display: inline-block&amp;quot;&amp;gt;&lt;br /&gt;
 '''function''' mergeSortIterative(a : '''int[n]'''):&lt;br /&gt;
     '''for''' i = 1 '''to''' n, i *= 2&lt;br /&gt;
         '''for''' j = 0 '''to''' n - i, j += 2 * i&lt;br /&gt;
             merge(a, j, j + i, min(j + 2 * i, n))&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Время работы==&lt;br /&gt;
Чтобы оценить время работы этого алгоритма, составим рекуррентное соотношение. Пускай &amp;lt;tex&amp;gt;T(n)&amp;lt;/tex&amp;gt; {{---}} время сортировки массива длины &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt;, тогда для сортировки слиянием справедливо &amp;lt;tex&amp;gt;T(n)=2T(n/2)+O(n)&amp;lt;/tex&amp;gt; &amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;tex&amp;gt;O(n)&amp;lt;/tex&amp;gt; {{---}} время, необходимое на то, чтобы слить два массива. Распишем это соотношение:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;T(n)=2T(n/2)+O(n)=4T(n/4)+2O(n)=\dots=2^kT(1)+kO(n)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Осталось оценить &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt;. Мы знаем, что &amp;lt;tex&amp;gt;2^k=n&amp;lt;/tex&amp;gt;, а значит &amp;lt;tex&amp;gt;k=\log n&amp;lt;/tex&amp;gt;. Уравнение примет вид &amp;lt;tex&amp;gt;T(n)=nT(1)+ \log n&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;O(n)&amp;lt;/tex&amp;gt;. Так как &amp;lt;tex&amp;gt;T(1)&amp;lt;/tex&amp;gt; {{---}} константа, то &amp;lt;tex&amp;gt;T(n)=O(n)+\log n &amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;O(n)=O(n\log n)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==Сравнение с другими алгоритмами==&lt;br /&gt;
===Достоинства===&lt;br /&gt;
* устойчивая.&lt;br /&gt;
===Недостатки===&lt;br /&gt;
* при любых входных данных время работы {{---}} &amp;lt;tex&amp;gt;O(n\log{n})&amp;lt;/tex&amp;gt;,&lt;br /&gt;
* требуется дополнительно &amp;lt;tex&amp;gt;O(n)&amp;lt;/tex&amp;gt; памяти, но можно модифицировать до &amp;lt;tex&amp;gt;O(1)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==См. также==&lt;br /&gt;
* [[Сортировка кучей]]&lt;br /&gt;
* [[Быстрая сортировка]]&lt;br /&gt;
* [[Timsort]]&lt;br /&gt;
*[[Cортировка слиянием с использованием O(1) дополнительной памяти]]&lt;br /&gt;
&lt;br /&gt;
==Источники информации==&lt;br /&gt;
*[http://ru.wikipedia.org/wiki/Mergesort Википедия {{---}} сортировка слиянием]&lt;br /&gt;
*[http://www.sorting-algorithms.com/merge-sort Визуализатор]&lt;br /&gt;
*[http://ru.wikibooks.org/wiki/%D0%9F%D1%80%D0%B8%D0%BC%D0%B5%D1%80%D1%8B_%D1%80%D0%B5%D0%B0%D0%BB%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D0%B8_%D1%81%D0%BE%D1%80%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B8_%D1%81%D0%BB%D0%B8%D1%8F%D0%BD%D0%B8%D0%B5%D0%BC Викиучебник {{---}} Примеры реализации на различных языках программирования]&lt;br /&gt;
&lt;br /&gt;
[[Категория: Дискретная математика и алгоритмы]]&lt;br /&gt;
[[Категория: Сортировка]]&lt;br /&gt;
[[Категория: Сортировки на сравнениях]]&lt;/div&gt;</summary>
		<author><name>Ильнар</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%A1%D0%BE%D1%80%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B0_%D1%81%D0%BB%D0%B8%D1%8F%D0%BD%D0%B8%D0%B5%D0%BC&amp;diff=46800</id>
		<title>Сортировка слиянием</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%A1%D0%BE%D1%80%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B0_%D1%81%D0%BB%D0%B8%D1%8F%D0%BD%D0%B8%D0%B5%D0%BC&amp;diff=46800"/>
				<updated>2015-05-23T12:24:03Z</updated>
		
		<summary type="html">&lt;p&gt;Ильнар: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''Сортировка слиянием''' (англ. ''Merge sort'') {{---}} алгоритм сортировки, пред­ло­женный Джо­ном фон Ней­ма­ном в 1945 го­ду.&lt;br /&gt;
&lt;br /&gt;
Это устойчивый алгоритм, использующий &amp;lt;tex&amp;gt;O(n)&amp;lt;/tex&amp;gt; дополнительной памяти и работающий за &amp;lt;tex&amp;gt;O(n&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;\log n)&amp;lt;/tex&amp;gt; времени.&lt;br /&gt;
&lt;br /&gt;
==Принцип работы==&lt;br /&gt;
[[Файл:Merging_two_arrays.png|270px|right|thumb|Пример работы процедуры слияния.]]&lt;br /&gt;
Алгоритм использует принцип «разделяй и властвуй»: задача разбивается на подзадачи меньшего размера, которые решаются по отдельности, после чего их решения комбинируются для получения решения исходной задачи. Конкретно процедуру сортировки слиянием можно описать следующим образом:&lt;br /&gt;
&lt;br /&gt;
# Если в рассматриваемом массиве один элемент, то он уже отсортирован {{---}} алгоритм завершает работу.&lt;br /&gt;
# Иначе массив разбивается на две части, которые сортируются рекурсивно.&lt;br /&gt;
# После сортировки двух частей массива к ним применяется процедура слияния, которая по двум отсортированным частям получает исходный отсортированный массив.&lt;br /&gt;
&lt;br /&gt;
===Слияние двух массивов===&lt;br /&gt;
У нас есть два массива &amp;lt;tex&amp;gt;a&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt; (фактически это будут две части одного массива, но для удобства будем писать, что у нас просто два массива). Нам надо получить массив &amp;lt;tex&amp;gt;c&amp;lt;/tex&amp;gt; размером &amp;lt;tex&amp;gt;|a| + |b|&amp;lt;/tex&amp;gt;. Для этого можно применить процедуру слияния. Эта процедура заключается в том, что мы сравниваем элементы массивов (начиная с начала) и меньший из них записываем в финальный. И затем, в массиве у которого оказался меньший элемент, переходим к следующему элементу и сравниваем теперь его. В конце, если один из массивов закончился, мы просто дописываем в финальный другой массив. После мы наш финальный массив записываем заместо двух исходных и получаем отсортированный участок.&lt;br /&gt;
&lt;br /&gt;
Множество отсортированных списков с операцией &amp;lt;tex&amp;gt;\mathrm{merge}&amp;lt;/tex&amp;gt; является [[Моноид|моноидом]], где нейтральным элементом будет &amp;lt;tex&amp;gt;\varnothing&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Ниже приведён псевдокод процедуры слияния, который сливает две части массива &amp;lt;tex&amp;gt;a&amp;lt;/tex&amp;gt; {{---}} &amp;lt;tex&amp;gt;[left; mid)&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;[mid; right)&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 '''function''' merge(a : '''int[n]'''; left, mid, right : '''int'''):&lt;br /&gt;
     it1 = 0&lt;br /&gt;
     it2 = 0&lt;br /&gt;
     result : '''int[right - left]'''&lt;br /&gt;
   &lt;br /&gt;
     '''while''' left + it1 &amp;lt; mid '''and''' mid + it2 &amp;lt; right&lt;br /&gt;
         '''if''' a[left + it1] &amp;lt; a[mid + it2]&lt;br /&gt;
             result[it1 + it2] = a[left + it1]&lt;br /&gt;
             it1 += 1&lt;br /&gt;
         '''else'''&lt;br /&gt;
             result[it1 + it2] = a[mid + it2]&lt;br /&gt;
             it2 += 1&lt;br /&gt;
   &lt;br /&gt;
     '''while''' left + it1 &amp;lt; mid&lt;br /&gt;
         result[it1 + it2] = a[left + it1]&lt;br /&gt;
         it1 += 1&lt;br /&gt;
   &lt;br /&gt;
     '''while''' mid + it2 &amp;lt; right&lt;br /&gt;
         result[it1 + it2] = a[mid + it2]&lt;br /&gt;
         it2 += 1&lt;br /&gt;
   &lt;br /&gt;
     '''for''' i = 0 '''to''' it1 + it2&lt;br /&gt;
         a[left + i] = result[i]&lt;br /&gt;
&lt;br /&gt;
===Рекурсивный алгоритм===&lt;br /&gt;
[[Файл:Merge sort1.png|300px|right|thumb|Пример работы рекурсивного алгоритма сортировки слиянием]]&lt;br /&gt;
Функция сортирует подотрезок массива с индексами в полуинтервале &amp;lt;tex&amp;gt;[left; right)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&amp;lt;code style=&amp;quot;display: inline-block&amp;quot;&amp;gt;&lt;br /&gt;
 '''function''' mergeSortRecursive(a : '''int[n]'''; left, right : '''int'''):&lt;br /&gt;
     '''if''' left + 1 &amp;gt;= right&lt;br /&gt;
         '''return'''&lt;br /&gt;
     mid = (left + right) / 2&lt;br /&gt;
     mergeSortRecursive(a, left, mid)&lt;br /&gt;
     mergeSortRecursive(a, mid, right)&lt;br /&gt;
     merge(a, left, mid, right)&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
===Итеративный алгоритм===&lt;br /&gt;
[[Файл:Merge sort itearative.png|300px|right|thumb|Пример работы итеративного алгоритма сортировки слиянием]]&lt;br /&gt;
При итеративном алгоритме не происходит рекурсивного запуска, что сохранит &amp;lt;tex&amp;gt;O(\log n)&amp;lt;/tex&amp;gt; памяти, которое отдавалось для стека вызовов.&lt;br /&gt;
&amp;lt;code style=&amp;quot;display: inline-block&amp;quot;&amp;gt;&lt;br /&gt;
 '''function''' mergeSortIterative(a : '''int[n]'''):&lt;br /&gt;
     '''for''' i = 1 '''to''' n, i *= 2&lt;br /&gt;
         '''for''' j = 0 '''to''' n - i, j += 2 * i&lt;br /&gt;
             merge(a, j, j + i, min(j + 2 * i, n))&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
==Время работы==&lt;br /&gt;
Чтобы оценить время работы этого алгоритма, составим рекуррентное соотношение. Пускай &amp;lt;tex&amp;gt;T(n)&amp;lt;/tex&amp;gt; {{---}} время сортировки массива длины &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt;, тогда для сортировки слиянием справедливо &amp;lt;tex&amp;gt;T(n)=2T(n/2)+O(n)&amp;lt;/tex&amp;gt; &amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;tex&amp;gt;O(n)&amp;lt;/tex&amp;gt; {{---}} время, необходимое на то, чтобы слить два массива. Распишем это соотношение:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;T(n)=2T(n/2)+O(n)=4T(n/4)+2O(n)=\dots=2^kT(1)+kO(n)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Осталось оценить &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt;. Мы знаем, что &amp;lt;tex&amp;gt;2^k=n&amp;lt;/tex&amp;gt;, а значит &amp;lt;tex&amp;gt;k=\log n&amp;lt;/tex&amp;gt;. Уравнение примет вид &amp;lt;tex&amp;gt;T(n)=nT(1)+ \log n&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;O(n)&amp;lt;/tex&amp;gt;. Так как &amp;lt;tex&amp;gt;T(1)&amp;lt;/tex&amp;gt; {{---}} константа, то &amp;lt;tex&amp;gt;T(n)=O(n)+\log n &amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;O(n)=O(n\log n)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Достоинства:&lt;br /&gt;
* устойчивая.&lt;br /&gt;
Недостатки:&lt;br /&gt;
* при любых входных данных время работы {{---}} &amp;lt;tex&amp;gt;O(n\log{n})&amp;lt;/tex&amp;gt;,&lt;br /&gt;
* требуется дополнительно &amp;lt;tex&amp;gt;O(n)&amp;lt;/tex&amp;gt; памяти.&lt;br /&gt;
&lt;br /&gt;
==См. также==&lt;br /&gt;
* [[Сортировка кучей]]&lt;br /&gt;
* [[Быстрая сортировка]]&lt;br /&gt;
* [[Timsort]]&lt;br /&gt;
*[[Cортировка слиянием с использованием O(1) дополнительной памяти]]&lt;br /&gt;
&lt;br /&gt;
==Источники информации==&lt;br /&gt;
*[http://ru.wikipedia.org/wiki/Mergesort Википедия {{---}} сортировка слиянием]&lt;br /&gt;
*[http://www.sorting-algorithms.com/merge-sort Визуализатор]&lt;br /&gt;
*[http://ru.wikibooks.org/wiki/%D0%9F%D1%80%D0%B8%D0%BC%D0%B5%D1%80%D1%8B_%D1%80%D0%B5%D0%B0%D0%BB%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D0%B8_%D1%81%D0%BE%D1%80%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B8_%D1%81%D0%BB%D0%B8%D1%8F%D0%BD%D0%B8%D0%B5%D0%BC Викиучебник {{---}} Примеры реализации на различных языках программирования]&lt;br /&gt;
&lt;br /&gt;
[[Категория: Дискретная математика и алгоритмы]]&lt;br /&gt;
[[Категория: Сортировка]]&lt;br /&gt;
[[Категория: Сортировки на сравнениях]]&lt;/div&gt;</summary>
		<author><name>Ильнар</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%A1%D0%BE%D1%80%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B0_%D1%81%D0%BB%D0%B8%D1%8F%D0%BD%D0%B8%D0%B5%D0%BC&amp;diff=46799</id>
		<title>Сортировка слиянием</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%A1%D0%BE%D1%80%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B0_%D1%81%D0%BB%D0%B8%D1%8F%D0%BD%D0%B8%D0%B5%D0%BC&amp;diff=46799"/>
				<updated>2015-05-23T12:11:00Z</updated>
		
		<summary type="html">&lt;p&gt;Ильнар: /* См. также */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''Сортировка слиянием''' (англ. ''Merge sort'') {{---}} алгоритм сортировки, пред­ло­женный Джо­ном фон Ней­ма­ном в 1945 го­ду.&lt;br /&gt;
&lt;br /&gt;
Это устойчивый алгоритм, использующий &amp;lt;tex&amp;gt;O(n)&amp;lt;/tex&amp;gt; дополнительной памяти и работающий за &amp;lt;tex&amp;gt;O(n&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;\log n)&amp;lt;/tex&amp;gt; времени.&lt;br /&gt;
&lt;br /&gt;
==Принцип работы==&lt;br /&gt;
[[Файл:Merging_two_arrays.png|270px|right|thumb|Пример работы процедуры слияния.]]&lt;br /&gt;
Алгоритм использует принцип «разделяй и властвуй»: задача разбивается на подзадачи меньшего размера, которые решаются по отдельности, после чего их решения комбинируются для получения решения исходной задачи. Конкретно процедуру сортировки слиянием можно описать следующим образом:&lt;br /&gt;
&lt;br /&gt;
# Если в рассматриваемом массиве один элемент, то он уже отсортирован {{---}} алгоритм завершает работу.&lt;br /&gt;
# Иначе массив разбивается на две части, которые сортируются рекурсивно.&lt;br /&gt;
# После сортировки двух частей массива к ним применяется процедура слияния, которая по двум отсортированным частям получает исходный отсортированный массив.&lt;br /&gt;
&lt;br /&gt;
===Слияние двух массивов===&lt;br /&gt;
У нас есть два массива &amp;lt;tex&amp;gt;a&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt; (фактически это будут две части одного массива, но для удобства будем писать, что у нас просто два массива). Нам надо получить массив &amp;lt;tex&amp;gt;c&amp;lt;/tex&amp;gt; размером &amp;lt;tex&amp;gt;|a| + |b|&amp;lt;/tex&amp;gt;. Для этого можно применить процедуру слияния. Эта процедура заключается в том, что мы сравниваем элементы массивов (начиная с начала) и меньший из них записываем в финальный. И затем, в массиве у которого оказался меньший элемент, переходим к следующему элементу и сравниваем теперь его. В конце, если один из массивов закончился, мы просто дописываем в финальный другой массив. После мы наш финальный массив записываем заместо двух исходных и получаем отсортированный участок.&lt;br /&gt;
&lt;br /&gt;
Множество отсортированных списков с операцией &amp;lt;tex&amp;gt;\mathrm{merge}&amp;lt;/tex&amp;gt; является [[Моноид|моноидом]], &amp;lt;tex&amp;gt;\langle assorted\ list, \mathrm{merge}, \varnothing \rangle &amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;\varnothing&amp;lt;/tex&amp;gt; {{---}} нейтральный элемент.&lt;br /&gt;
&lt;br /&gt;
Ниже приведён псевдокод процедуры слияния, который сливает две части массива &amp;lt;tex&amp;gt;a&amp;lt;/tex&amp;gt; {{---}} &amp;lt;tex&amp;gt;[left; mid)&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;[mid; right)&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 '''function''' merge(a : '''int[n]'''; left, mid, right : '''int'''):&lt;br /&gt;
     it1 = 0&lt;br /&gt;
     it2 = 0&lt;br /&gt;
     result : '''int[right - left]'''&lt;br /&gt;
   &lt;br /&gt;
     '''while''' left + it1 &amp;lt; mid '''and''' mid + it2 &amp;lt; right&lt;br /&gt;
         '''if''' a[left + it1] &amp;lt; a[mid + it2]&lt;br /&gt;
             result[it1 + it2] = a[left + it1]&lt;br /&gt;
             it1 += 1&lt;br /&gt;
         '''else'''&lt;br /&gt;
             result[it1 + it2] = a[mid + it2]&lt;br /&gt;
             it2 += 1&lt;br /&gt;
   &lt;br /&gt;
     '''while''' left + it1 &amp;lt; mid&lt;br /&gt;
         result[it1 + it2] = a[left + it1]&lt;br /&gt;
         it1 += 1&lt;br /&gt;
   &lt;br /&gt;
     '''while''' mid + it2 &amp;lt; right&lt;br /&gt;
         result[it1 + it2] = a[mid + it2]&lt;br /&gt;
         it2 += 1&lt;br /&gt;
   &lt;br /&gt;
     '''for''' i = 0 '''to''' it1 + it2&lt;br /&gt;
         a[left + i] = result[i]&lt;br /&gt;
&lt;br /&gt;
===Рекурсивный алгоритм===&lt;br /&gt;
[[Файл:Merge sort1.png|300px|right|thumb|Пример работы рекурсивного алгоритма сортировки слиянием]]&lt;br /&gt;
Функция сортирует подотрезок массива с индексами в полуинтервале &amp;lt;tex&amp;gt;[left; right)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&amp;lt;code style=&amp;quot;display: inline-block&amp;quot;&amp;gt;&lt;br /&gt;
 '''function''' mergeSortRecursive(a : '''int[n]'''; left, right : '''int'''):&lt;br /&gt;
     '''if''' left + 1 &amp;gt;= right&lt;br /&gt;
         '''return'''&lt;br /&gt;
     mid = (left + right) / 2&lt;br /&gt;
     mergeSortRecursive(a, left, mid)&lt;br /&gt;
     mergeSortRecursive(a, mid, right)&lt;br /&gt;
     merge(a, left, mid, right)&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
===Итеративный алгоритм===&lt;br /&gt;
[[Файл:Merge sort itearative.png|300px|right|thumb|Пример работы итеративного алгоритма сортировки слиянием]]&lt;br /&gt;
При итеративном алгоритме не происходит рекурсивного запуска, что сохранит &amp;lt;tex&amp;gt;O(\log n)&amp;lt;/tex&amp;gt; памяти, которое отдавалось для стека вызовов.&lt;br /&gt;
&amp;lt;code style=&amp;quot;display: inline-block&amp;quot;&amp;gt;&lt;br /&gt;
 '''function''' mergeSortIterative(a : '''int[n]'''):&lt;br /&gt;
     '''for''' i = 1 '''to''' n, i *= 2&lt;br /&gt;
         '''for''' j = 0 '''to''' n - i, j += 2 * i&lt;br /&gt;
             merge(a, j, j + i, min(j + 2 * i, n))&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
==Время работы==&lt;br /&gt;
Чтобы оценить время работы этого алгоритма, составим рекуррентное соотношение. Пускай &amp;lt;tex&amp;gt;T(n)&amp;lt;/tex&amp;gt; {{---}} время сортировки массива длины &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt;, тогда для сортировки слиянием справедливо &amp;lt;tex&amp;gt;T(n)=2T(n/2)+O(n)&amp;lt;/tex&amp;gt; &amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;tex&amp;gt;O(n)&amp;lt;/tex&amp;gt; {{---}} время, необходимое на то, чтобы слить два массива. Распишем это соотношение:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;T(n)=2T(n/2)+O(n)=4T(n/4)+2O(n)=\dots=2^kT(1)+kO(n)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Осталось оценить &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt;. Мы знаем, что &amp;lt;tex&amp;gt;2^k=n&amp;lt;/tex&amp;gt;, а значит &amp;lt;tex&amp;gt;k=\log n&amp;lt;/tex&amp;gt;. Уравнение примет вид &amp;lt;tex&amp;gt;T(n)=nT(1)+ \log n&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;O(n)&amp;lt;/tex&amp;gt;. Так как &amp;lt;tex&amp;gt;T(1)&amp;lt;/tex&amp;gt; {{---}} константа, то &amp;lt;tex&amp;gt;T(n)=O(n)+\log n &amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;O(n)=O(n\log n)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Достоинства:&lt;br /&gt;
* устойчивая.&lt;br /&gt;
Недостатки:&lt;br /&gt;
* при любых входных данных время работы {{---}} &amp;lt;tex&amp;gt;O(n\log{n})&amp;lt;/tex&amp;gt;,&lt;br /&gt;
* требуется дополнительно &amp;lt;tex&amp;gt;O(n)&amp;lt;/tex&amp;gt; памяти.&lt;br /&gt;
&lt;br /&gt;
==См. также==&lt;br /&gt;
* [[Сортировка кучей]]&lt;br /&gt;
* [[Быстрая сортировка]]&lt;br /&gt;
* [[Timsort]]&lt;br /&gt;
*[[Cортировка слиянием с использованием O(1) дополнительной памяти]]&lt;br /&gt;
&lt;br /&gt;
==Источники информации==&lt;br /&gt;
*[http://ru.wikipedia.org/wiki/Mergesort Википедия {{---}} сортировка слиянием]&lt;br /&gt;
*[http://www.sorting-algorithms.com/merge-sort Визуализатор]&lt;br /&gt;
*[http://ru.wikibooks.org/wiki/%D0%9F%D1%80%D0%B8%D0%BC%D0%B5%D1%80%D1%8B_%D1%80%D0%B5%D0%B0%D0%BB%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D0%B8_%D1%81%D0%BE%D1%80%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B8_%D1%81%D0%BB%D0%B8%D1%8F%D0%BD%D0%B8%D0%B5%D0%BC Викиучебник {{---}} Примеры реализации на различных языках программирования]&lt;br /&gt;
&lt;br /&gt;
[[Категория: Дискретная математика и алгоритмы]]&lt;br /&gt;
[[Категория: Сортировка]]&lt;br /&gt;
[[Категория: Сортировки на сравнениях]]&lt;/div&gt;</summary>
		<author><name>Ильнар</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%A1%D0%BE%D1%80%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B0_%D1%81%D0%BB%D0%B8%D1%8F%D0%BD%D0%B8%D0%B5%D0%BC&amp;diff=46798</id>
		<title>Сортировка слиянием</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%A1%D0%BE%D1%80%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B0_%D1%81%D0%BB%D0%B8%D1%8F%D0%BD%D0%B8%D0%B5%D0%BC&amp;diff=46798"/>
				<updated>2015-05-23T12:05:48Z</updated>
		
		<summary type="html">&lt;p&gt;Ильнар: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''Сортировка слиянием''' (англ. ''Merge sort'') {{---}} алгоритм сортировки, пред­ло­женный Джо­ном фон Ней­ма­ном в 1945 го­ду.&lt;br /&gt;
&lt;br /&gt;
Это устойчивый алгоритм, использующий &amp;lt;tex&amp;gt;O(n)&amp;lt;/tex&amp;gt; дополнительной памяти и работающий за &amp;lt;tex&amp;gt;O(n&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;\log n)&amp;lt;/tex&amp;gt; времени.&lt;br /&gt;
&lt;br /&gt;
==Принцип работы==&lt;br /&gt;
[[Файл:Merging_two_arrays.png|270px|right|thumb|Пример работы процедуры слияния.]]&lt;br /&gt;
Алгоритм использует принцип «разделяй и властвуй»: задача разбивается на подзадачи меньшего размера, которые решаются по отдельности, после чего их решения комбинируются для получения решения исходной задачи. Конкретно процедуру сортировки слиянием можно описать следующим образом:&lt;br /&gt;
&lt;br /&gt;
# Если в рассматриваемом массиве один элемент, то он уже отсортирован {{---}} алгоритм завершает работу.&lt;br /&gt;
# Иначе массив разбивается на две части, которые сортируются рекурсивно.&lt;br /&gt;
# После сортировки двух частей массива к ним применяется процедура слияния, которая по двум отсортированным частям получает исходный отсортированный массив.&lt;br /&gt;
&lt;br /&gt;
===Слияние двух массивов===&lt;br /&gt;
У нас есть два массива &amp;lt;tex&amp;gt;a&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt; (фактически это будут две части одного массива, но для удобства будем писать, что у нас просто два массива). Нам надо получить массив &amp;lt;tex&amp;gt;c&amp;lt;/tex&amp;gt; размером &amp;lt;tex&amp;gt;|a| + |b|&amp;lt;/tex&amp;gt;. Для этого можно применить процедуру слияния. Эта процедура заключается в том, что мы сравниваем элементы массивов (начиная с начала) и меньший из них записываем в финальный. И затем, в массиве у которого оказался меньший элемент, переходим к следующему элементу и сравниваем теперь его. В конце, если один из массивов закончился, мы просто дописываем в финальный другой массив. После мы наш финальный массив записываем заместо двух исходных и получаем отсортированный участок.&lt;br /&gt;
&lt;br /&gt;
Множество отсортированных списков с операцией &amp;lt;tex&amp;gt;\mathrm{merge}&amp;lt;/tex&amp;gt; является [[Моноид|моноидом]], &amp;lt;tex&amp;gt;\langle assorted\ list, \mathrm{merge}, \varnothing \rangle &amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;\varnothing&amp;lt;/tex&amp;gt; {{---}} нейтральный элемент.&lt;br /&gt;
&lt;br /&gt;
Ниже приведён псевдокод процедуры слияния, который сливает две части массива &amp;lt;tex&amp;gt;a&amp;lt;/tex&amp;gt; {{---}} &amp;lt;tex&amp;gt;[left; mid)&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;[mid; right)&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 '''function''' merge(a : '''int[n]'''; left, mid, right : '''int'''):&lt;br /&gt;
     it1 = 0&lt;br /&gt;
     it2 = 0&lt;br /&gt;
     result : '''int[right - left]'''&lt;br /&gt;
   &lt;br /&gt;
     '''while''' left + it1 &amp;lt; mid '''and''' mid + it2 &amp;lt; right&lt;br /&gt;
         '''if''' a[left + it1] &amp;lt; a[mid + it2]&lt;br /&gt;
             result[it1 + it2] = a[left + it1]&lt;br /&gt;
             it1 += 1&lt;br /&gt;
         '''else'''&lt;br /&gt;
             result[it1 + it2] = a[mid + it2]&lt;br /&gt;
             it2 += 1&lt;br /&gt;
   &lt;br /&gt;
     '''while''' left + it1 &amp;lt; mid&lt;br /&gt;
         result[it1 + it2] = a[left + it1]&lt;br /&gt;
         it1 += 1&lt;br /&gt;
   &lt;br /&gt;
     '''while''' mid + it2 &amp;lt; right&lt;br /&gt;
         result[it1 + it2] = a[mid + it2]&lt;br /&gt;
         it2 += 1&lt;br /&gt;
   &lt;br /&gt;
     '''for''' i = 0 '''to''' it1 + it2&lt;br /&gt;
         a[left + i] = result[i]&lt;br /&gt;
&lt;br /&gt;
===Рекурсивный алгоритм===&lt;br /&gt;
[[Файл:Merge sort1.png|300px|right|thumb|Пример работы рекурсивного алгоритма сортировки слиянием]]&lt;br /&gt;
Функция сортирует подотрезок массива с индексами в полуинтервале &amp;lt;tex&amp;gt;[left; right)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&amp;lt;code style=&amp;quot;display: inline-block&amp;quot;&amp;gt;&lt;br /&gt;
 '''function''' mergeSortRecursive(a : '''int[n]'''; left, right : '''int'''):&lt;br /&gt;
     '''if''' left + 1 &amp;gt;= right&lt;br /&gt;
         '''return'''&lt;br /&gt;
     mid = (left + right) / 2&lt;br /&gt;
     mergeSortRecursive(a, left, mid)&lt;br /&gt;
     mergeSortRecursive(a, mid, right)&lt;br /&gt;
     merge(a, left, mid, right)&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
===Итеративный алгоритм===&lt;br /&gt;
[[Файл:Merge sort itearative.png|300px|right|thumb|Пример работы итеративного алгоритма сортировки слиянием]]&lt;br /&gt;
При итеративном алгоритме не происходит рекурсивного запуска, что сохранит &amp;lt;tex&amp;gt;O(\log n)&amp;lt;/tex&amp;gt; памяти, которое отдавалось для стека вызовов.&lt;br /&gt;
&amp;lt;code style=&amp;quot;display: inline-block&amp;quot;&amp;gt;&lt;br /&gt;
 '''function''' mergeSortIterative(a : '''int[n]'''):&lt;br /&gt;
     '''for''' i = 1 '''to''' n, i *= 2&lt;br /&gt;
         '''for''' j = 0 '''to''' n - i, j += 2 * i&lt;br /&gt;
             merge(a, j, j + i, min(j + 2 * i, n))&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
==Время работы==&lt;br /&gt;
Чтобы оценить время работы этого алгоритма, составим рекуррентное соотношение. Пускай &amp;lt;tex&amp;gt;T(n)&amp;lt;/tex&amp;gt; {{---}} время сортировки массива длины &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt;, тогда для сортировки слиянием справедливо &amp;lt;tex&amp;gt;T(n)=2T(n/2)+O(n)&amp;lt;/tex&amp;gt; &amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;tex&amp;gt;O(n)&amp;lt;/tex&amp;gt; {{---}} время, необходимое на то, чтобы слить два массива. Распишем это соотношение:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;T(n)=2T(n/2)+O(n)=4T(n/4)+2O(n)=\dots=2^kT(1)+kO(n)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Осталось оценить &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt;. Мы знаем, что &amp;lt;tex&amp;gt;2^k=n&amp;lt;/tex&amp;gt;, а значит &amp;lt;tex&amp;gt;k=\log n&amp;lt;/tex&amp;gt;. Уравнение примет вид &amp;lt;tex&amp;gt;T(n)=nT(1)+ \log n&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;O(n)&amp;lt;/tex&amp;gt;. Так как &amp;lt;tex&amp;gt;T(1)&amp;lt;/tex&amp;gt; {{---}} константа, то &amp;lt;tex&amp;gt;T(n)=O(n)+\log n &amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;O(n)=O(n\log n)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Достоинства:&lt;br /&gt;
* устойчивая.&lt;br /&gt;
Недостатки:&lt;br /&gt;
* при любых входных данных время работы {{---}} &amp;lt;tex&amp;gt;O(n\log{n})&amp;lt;/tex&amp;gt;,&lt;br /&gt;
* требуется дополнительно &amp;lt;tex&amp;gt;O(n)&amp;lt;/tex&amp;gt; памяти.&lt;br /&gt;
&lt;br /&gt;
==См. также==&lt;br /&gt;
* [[Сортировка кучей]]&lt;br /&gt;
* [[Быстрая сортировка]]&lt;br /&gt;
*[[Cортировка слиянием с использованием O(1) дополнительной памяти]]&lt;br /&gt;
&lt;br /&gt;
==Источники информации==&lt;br /&gt;
*[http://ru.wikipedia.org/wiki/Mergesort Википедия {{---}} сортировка слиянием]&lt;br /&gt;
*[http://www.sorting-algorithms.com/merge-sort Визуализатор]&lt;br /&gt;
*[http://ru.wikibooks.org/wiki/%D0%9F%D1%80%D0%B8%D0%BC%D0%B5%D1%80%D1%8B_%D1%80%D0%B5%D0%B0%D0%BB%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D0%B8_%D1%81%D0%BE%D1%80%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B8_%D1%81%D0%BB%D0%B8%D1%8F%D0%BD%D0%B8%D0%B5%D0%BC Викиучебник {{---}} Примеры реализации на различных языках программирования]&lt;br /&gt;
&lt;br /&gt;
[[Категория: Дискретная математика и алгоритмы]]&lt;br /&gt;
[[Категория: Сортировка]]&lt;br /&gt;
[[Категория: Сортировки на сравнениях]]&lt;/div&gt;</summary>
		<author><name>Ильнар</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%A1%D0%BE%D1%80%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B0_%D1%81%D0%BB%D0%B8%D1%8F%D0%BD%D0%B8%D0%B5%D0%BC&amp;diff=46796</id>
		<title>Сортировка слиянием</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%A1%D0%BE%D1%80%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B0_%D1%81%D0%BB%D0%B8%D1%8F%D0%BD%D0%B8%D0%B5%D0%BC&amp;diff=46796"/>
				<updated>2015-05-23T11:06:22Z</updated>
		
		<summary type="html">&lt;p&gt;Ильнар: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''Сортировка слиянием''' (англ. ''Merge sort'') {{---}} алгоритм сортировки, пред­ло­женный Джо­ном фон Ней­ма­ном в 1945 го­ду.&lt;br /&gt;
&lt;br /&gt;
Это устойчивый алгоритм, использующий &amp;lt;tex&amp;gt;O(n)&amp;lt;/tex&amp;gt; дополнительной памяти и работающий за &amp;lt;tex&amp;gt;O(n&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;\log n)&amp;lt;/tex&amp;gt; времени.&lt;br /&gt;
&lt;br /&gt;
==Принцип работы==&lt;br /&gt;
[[Файл:Merging_two_arrays.png|270px|right|thumb|Пример работы процедуры слияния.]]&lt;br /&gt;
Алгоритм использует принцип «разделяй и властвуй»: задача разбивается на подзадачи меньшего размера, которые решаются по отдельности, после чего их решения комбинируются для получения решения исходной задачи. Конкретно процедуру сортировки слиянием можно описать следующим образом:&lt;br /&gt;
&lt;br /&gt;
# Если в рассматриваемом массиве один элемент, то он уже отсортирован {{---}} алгоритм завершает работу.&lt;br /&gt;
# Иначе массив разбивается на две части, которые сортируются рекурсивно.&lt;br /&gt;
# После сортировки двух частей массива к ним применяется процедура слияния, которая по двум отсортированным частям получает исходный отсортированный массив.&lt;br /&gt;
&lt;br /&gt;
Достоинства:&lt;br /&gt;
* устойчивая&lt;br /&gt;
Недостатки:&lt;br /&gt;
* при любых входных данных время работы {{---}} &amp;lt;tex&amp;gt;O(n\log{n})&amp;lt;/tex&amp;gt;&lt;br /&gt;
* требуется дополнительно &amp;lt;tex&amp;gt;O(n)&amp;lt;/tex&amp;gt; памяти&lt;br /&gt;
&lt;br /&gt;
Проблема с одинаковым временем работы решается в [[Timsort]].&lt;br /&gt;
&lt;br /&gt;
===Слияние двух массивов===&lt;br /&gt;
У нас есть два массива &amp;lt;tex&amp;gt;a&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt; (фактически это будут две части одного массива, но для удобства будем писать, что у нас просто два массива). Нам надо получить массив &amp;lt;tex&amp;gt;c&amp;lt;/tex&amp;gt; размером &amp;lt;tex&amp;gt;|a| + |b|&amp;lt;/tex&amp;gt;. Для этого можно применить процедуру слияния. Эта процедура заключается в том, что мы сравниваем элементы массивов (начиная с начала) и меньший из них записываем в финальный. И затем, в массиве у которого оказался меньший элемент, переходим к следующему элементу и сравниваем теперь его. В конце, если один из массивов закончился, мы просто дописываем в финальный другой массив. После мы наш финальный массив записываем заместо двух исходных и получаем отсортированный участок.&lt;br /&gt;
&lt;br /&gt;
Множество отсортированных списков с операцией &amp;lt;tex&amp;gt;merge&amp;lt;/tex&amp;gt; является [[Моноид|моноидом]], &amp;lt;tex&amp;gt;\langle assorted\ list, merge, \varnothing \rangle &amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;\varnothing&amp;lt;/tex&amp;gt; {{---}} нейтральный элемент.&lt;br /&gt;
&lt;br /&gt;
Ниже приведён псевдокод процедуры слияния, который сливает две части массива &amp;lt;tex&amp;gt;a&amp;lt;/tex&amp;gt; {{---}} &amp;lt;tex&amp;gt;[left; mid)&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;[mid; right)&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 '''function''' merge(a : '''int[n]'''; left, mid, right : '''int'''):&lt;br /&gt;
     it1 = 0&lt;br /&gt;
     it2 = 0&lt;br /&gt;
     result : '''int[right - left]'''&lt;br /&gt;
   &lt;br /&gt;
     '''while''' left + it1 &amp;lt; mid '''and''' mid + it2 &amp;lt; right&lt;br /&gt;
         '''if''' a[left + it1] &amp;lt; a[mid + it2]&lt;br /&gt;
             result[it1 + it2] = a[left + it1]&lt;br /&gt;
             it1 += 1&lt;br /&gt;
         '''else'''&lt;br /&gt;
             result[it1 + it2] = a[mid + it2]&lt;br /&gt;
             it2 += 1&lt;br /&gt;
   &lt;br /&gt;
     '''while''' left + it1 &amp;lt; mid&lt;br /&gt;
         result[it1 + it2] = a[left + it1]&lt;br /&gt;
         it1 += 1&lt;br /&gt;
   &lt;br /&gt;
     '''while''' mid + it2 &amp;lt; right&lt;br /&gt;
         result[it1 + it2] = a[mid + it2]&lt;br /&gt;
         it2 += 1&lt;br /&gt;
   &lt;br /&gt;
     '''for''' i = 0 '''to''' it1 + it2&lt;br /&gt;
         a[left + i] = result[i]&lt;br /&gt;
&lt;br /&gt;
===Рекурсивный алгоритм===&lt;br /&gt;
[[Файл:Merge sort1.png|300px|right|thumb|Пример работы рекурсивного алгоритма сортировки слиянием]]&lt;br /&gt;
Функция сортирует подотрезок массива с индексами в полуинтервале &amp;lt;tex&amp;gt;[left; right)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&amp;lt;code style=&amp;quot;display: inline-block&amp;quot;&amp;gt;&lt;br /&gt;
 '''function''' mergeSortRecursive(a : '''int[n]'''; left, right : '''int'''):&lt;br /&gt;
     '''if''' left + 1 &amp;gt;= right&lt;br /&gt;
         '''return'''&lt;br /&gt;
     mid = (left + right) / 2&lt;br /&gt;
     mergeSortRecursive(a, left, mid)&lt;br /&gt;
     mergeSortRecursive(a, mid, right)&lt;br /&gt;
     merge(a, left, mid, right)&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
===Итеративный алгоритм===&lt;br /&gt;
[[Файл:Merge sort itearative.png|300px|right|thumb|Пример работы итеративного алгоритма сортировки слиянием]]&lt;br /&gt;
&amp;lt;code style=&amp;quot;display: inline-block&amp;quot;&amp;gt;&lt;br /&gt;
 '''function''' mergeSortIterative(a : '''int[n]'''):&lt;br /&gt;
     '''for''' i = 1 '''to''' n, i *= 2&lt;br /&gt;
         '''for''' j = 0 '''to''' n - i, j += 2 * i&lt;br /&gt;
             merge(a, j, j + i, min(j + 2 * i, n))&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
==Время работы==&lt;br /&gt;
Чтобы оценить время работы этого алгоритма, составим рекуррентное соотношение. Пускай &amp;lt;tex&amp;gt;T(n)&amp;lt;/tex&amp;gt; {{---}} время сортировки массива длины &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt;, тогда для сортировки слиянием справедливо &amp;lt;tex&amp;gt;T(n)=2T(n/2)+O(n)&amp;lt;/tex&amp;gt; &amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;tex&amp;gt;O(n)&amp;lt;/tex&amp;gt; {{---}} время, необходимое на то, чтобы слить два массива. Распишем это соотношение:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;T(n)=2T(n/2)+O(n)=4T(n/4)+2O(n)=\dots=2^kT(1)+kO(n)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Осталось оценить &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt;. Мы знаем, что &amp;lt;tex&amp;gt;2^k=n&amp;lt;/tex&amp;gt;, а значит &amp;lt;tex&amp;gt;k=\log n&amp;lt;/tex&amp;gt;. Уравнение примет вид &amp;lt;tex&amp;gt;T(n)=nT(1)+ \log n&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;O(n)&amp;lt;/tex&amp;gt;. Так как &amp;lt;tex&amp;gt;T(1)&amp;lt;/tex&amp;gt; {{---}} константа, то &amp;lt;tex&amp;gt;T(n)=O(n)+\log n &amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;O(n)=O(n\log n)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
==См. также==&lt;br /&gt;
* [[Сортировка кучей]]&lt;br /&gt;
* [[Быстрая сортировка]]&lt;br /&gt;
*[[Cортировка слиянием с использованием O(1) дополнительной памяти]]&lt;br /&gt;
&lt;br /&gt;
==Источники информации==&lt;br /&gt;
*[http://ru.wikipedia.org/wiki/Mergesort Википедия {{---}} сортировка слиянием]&lt;br /&gt;
*[http://www.sorting-algorithms.com/merge-sort Визуализатор]&lt;br /&gt;
*[http://ru.wikibooks.org/wiki/%D0%9F%D1%80%D0%B8%D0%BC%D0%B5%D1%80%D1%8B_%D1%80%D0%B5%D0%B0%D0%BB%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D0%B8_%D1%81%D0%BE%D1%80%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B8_%D1%81%D0%BB%D0%B8%D1%8F%D0%BD%D0%B8%D0%B5%D0%BC Викиучебник {{---}} Примеры реализации на различных языках программирования]&lt;br /&gt;
&lt;br /&gt;
[[Категория: Дискретная математика и алгоритмы]]&lt;br /&gt;
[[Категория: Сортировка]]&lt;br /&gt;
[[Категория: Сортировки на сравнениях]]&lt;/div&gt;</summary>
		<author><name>Ильнар</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%A1%D0%BE%D1%80%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B0_%D1%81%D0%BB%D0%B8%D1%8F%D0%BD%D0%B8%D0%B5%D0%BC&amp;diff=46794</id>
		<title>Сортировка слиянием</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%A1%D0%BE%D1%80%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B0_%D1%81%D0%BB%D0%B8%D1%8F%D0%BD%D0%B8%D0%B5%D0%BC&amp;diff=46794"/>
				<updated>2015-05-22T19:44:32Z</updated>
		
		<summary type="html">&lt;p&gt;Ильнар: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''Сортировка слиянием''' (англ. ''Merge sort'') {{---}} алгоритм сортировки, пред­ло­женный Джо­ном фон Ней­ма­ном в 1945 го­ду.&lt;br /&gt;
&lt;br /&gt;
Это устойчивый алгоритм, использующий &amp;lt;tex&amp;gt;O(n)&amp;lt;/tex&amp;gt; дополнительной памяти и работающий за &amp;lt;tex&amp;gt;O(n&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;\log n)&amp;lt;/tex&amp;gt; времени.&lt;br /&gt;
&lt;br /&gt;
==Принцип работы==&lt;br /&gt;
[[Файл:Merging_two_arrays.png|270px|right|thumb|Пример работы процедуры слияния.]]&lt;br /&gt;
Алгоритм использует принцип «разделяй и властвуй»: задача разбивается на подзадачи меньшего размера, которые решаются по отдельности, после чего их решения комбинируются для получения решения исходной задачи. Конкретно процедуру сортировки слиянием можно описать следующим образом:&lt;br /&gt;
&lt;br /&gt;
# Если в рассматриваемом массиве один элемент, то он уже отсортирован {{---}} алгоритм завершает работу.&lt;br /&gt;
# Иначе массив разбивается на две части, которые сортируются рекурсивно.&lt;br /&gt;
# После сортировки двух частей массива к ним применяется процедура слияния, которая по двум отсортированным частям получает исходный отсортированный массив.&lt;br /&gt;
&lt;br /&gt;
===Слияние двух массивов===&lt;br /&gt;
У нас есть два массива &amp;lt;tex&amp;gt;a&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt; (фактически это будут две части одного массива, но для удобства будем писать, что у нас просто два массива). Нам надо получить массив &amp;lt;tex&amp;gt;c&amp;lt;/tex&amp;gt; размером &amp;lt;tex&amp;gt;|a| + |b|&amp;lt;/tex&amp;gt;. Для этого можно применить процедуру слияния. Эта процедура заключается в том, что мы сравниваем элементы массивов (начиная с начала) и меньший из них записываем в финальный. И затем, в массиве у которого оказался меньший элемент, переходим к следующему элементу и сравниваем теперь его. В конце, если один из массивов закончился, мы просто дописываем в финальный другой массив. После мы наш финальный массив записываем заместо двух исходных и получаем отсортированный участок.&lt;br /&gt;
&lt;br /&gt;
Множество отсортированных списков с операцией &amp;lt;tex&amp;gt;merge&amp;lt;/tex&amp;gt; является [[Моноид|моноидом]], &amp;lt;tex&amp;gt;\langle assorted\ list, merge, \varnothing \rangle &amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;\varnothing&amp;lt;/tex&amp;gt; {{---}} нейтральный элемент.&lt;br /&gt;
&lt;br /&gt;
Ниже приведён псевдокод процедуры слияния, который сливает две части массива &amp;lt;tex&amp;gt;a&amp;lt;/tex&amp;gt; {{---}} &amp;lt;tex&amp;gt;[left; mid)&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;[mid; right)&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 '''function''' merge(a : '''int[n]'''; left, mid, right : '''int'''):&lt;br /&gt;
     it1 = 0&lt;br /&gt;
     it2 = 0&lt;br /&gt;
     result : '''int[right - left]'''&lt;br /&gt;
   &lt;br /&gt;
     '''while''' left + it1 &amp;lt; mid '''and''' mid + it2 &amp;lt; right&lt;br /&gt;
         '''if''' a[left + it1] &amp;lt; a[mid + it2]&lt;br /&gt;
             result[it1 + it2] = a[left + it1]&lt;br /&gt;
             it1 += 1&lt;br /&gt;
         '''else'''&lt;br /&gt;
             result[it1 + it2] = a[mid + it2]&lt;br /&gt;
             it2 += 1&lt;br /&gt;
   &lt;br /&gt;
     '''while''' left + it1 &amp;lt; mid&lt;br /&gt;
         result[it1 + it2] = a[left + it1]&lt;br /&gt;
         it1 += 1&lt;br /&gt;
   &lt;br /&gt;
     '''while''' mid + it2 &amp;lt; right&lt;br /&gt;
         result[it1 + it2] = a[mid + it2]&lt;br /&gt;
         it2 += 1&lt;br /&gt;
   &lt;br /&gt;
     '''for''' i = 0 '''to''' it1 + it2&lt;br /&gt;
         a[left + i] = result[i]&lt;br /&gt;
&lt;br /&gt;
===Рекурсивный алгоритм===&lt;br /&gt;
[[Файл:Merge sort1.png|300px|right|thumb|Пример работы рекурсивного алгоритма сортировки слиянием]]&lt;br /&gt;
Функция сортирует подотрезок массива с индексами в полуинтервале &amp;lt;tex&amp;gt;[left; right)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&amp;lt;code style=&amp;quot;display: inline-block&amp;quot;&amp;gt;&lt;br /&gt;
 '''function''' mergeSortRecursive(a : '''int[n]'''; left, right : '''int'''):&lt;br /&gt;
     '''if''' left + 1 &amp;gt;= right&lt;br /&gt;
         '''return'''&lt;br /&gt;
     mid = (left + right) / 2&lt;br /&gt;
     mergeSortRecursive(a, left, mid)&lt;br /&gt;
     mergeSortRecursive(a, mid, right)&lt;br /&gt;
     merge(a, left, mid, right)&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
===Итеративный алгоритм===&lt;br /&gt;
[[Файл:Merge sort itearative.png|300px|right|thumb|Пример работы итеративного алгоритма сортировки слиянием]]&lt;br /&gt;
&amp;lt;code style=&amp;quot;display: inline-block&amp;quot;&amp;gt;&lt;br /&gt;
 '''function''' mergeSortIterative(a : '''int[n]'''):&lt;br /&gt;
     '''for''' i = 1 '''to''' n, i *= 2&lt;br /&gt;
         '''for''' j = 0 '''to''' n - i, j += 2 * i&lt;br /&gt;
             merge(a, j, j + i, min(j + 2 * i, n))&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
==Время работы==&lt;br /&gt;
Чтобы оценить время работы этого алгоритма, составим рекуррентное соотношение. Пускай &amp;lt;tex&amp;gt;T(n)&amp;lt;/tex&amp;gt; {{---}} время сортировки массива длины &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt;, тогда для сортировки слиянием справедливо &amp;lt;tex&amp;gt;T(n)=2T(n/2)+O(n)&amp;lt;/tex&amp;gt; &amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;tex&amp;gt;O(n)&amp;lt;/tex&amp;gt; {{---}} время, необходимое на то, чтобы слить два массива. Распишем это соотношение:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;T(n)=2T(n/2)+O(n)=4T(n/4)+2O(n)=\dots=2^kT(1)+kO(n)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Осталось оценить &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt;. Мы знаем, что &amp;lt;tex&amp;gt;2^k=n&amp;lt;/tex&amp;gt;, а значит &amp;lt;tex&amp;gt;k=\log n&amp;lt;/tex&amp;gt;. Уравнение примет вид &amp;lt;tex&amp;gt;T(n)=nT(1)+ \log n&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;O(n)&amp;lt;/tex&amp;gt;. Так как &amp;lt;tex&amp;gt;T(1)&amp;lt;/tex&amp;gt; {{---}} константа, то &amp;lt;tex&amp;gt;T(n)=O(n)+\log n &amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;O(n)=O(n\log n)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==См. также==&lt;br /&gt;
* [[Сортировка кучей]]&lt;br /&gt;
* [[Быстрая сортировка]]&lt;br /&gt;
*[[Cортировка слиянием с использованием O(1) дополнительной памяти]]&lt;br /&gt;
&lt;br /&gt;
==Источники информации==&lt;br /&gt;
*[http://ru.wikipedia.org/wiki/Mergesort Википедия {{---}} сортировка слиянием]&lt;br /&gt;
*[http://www.sorting-algorithms.com/merge-sort Визуализатор]&lt;br /&gt;
*[http://ru.wikibooks.org/wiki/%D0%9F%D1%80%D0%B8%D0%BC%D0%B5%D1%80%D1%8B_%D1%80%D0%B5%D0%B0%D0%BB%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D0%B8_%D1%81%D0%BE%D1%80%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B8_%D1%81%D0%BB%D0%B8%D1%8F%D0%BD%D0%B8%D0%B5%D0%BC Викиучебник {{---}} Примеры реализации на различных языках программирования]&lt;br /&gt;
&lt;br /&gt;
[[Категория: Дискретная математика и алгоритмы]]&lt;br /&gt;
[[Категория: Сортировка]]&lt;br /&gt;
[[Категория: Сортировки на сравнениях]]&lt;/div&gt;</summary>
		<author><name>Ильнар</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:Merge_sort_itearative.png&amp;diff=46789</id>
		<title>Файл:Merge sort itearative.png</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:Merge_sort_itearative.png&amp;diff=46789"/>
				<updated>2015-05-22T16:51:47Z</updated>
		
		<summary type="html">&lt;p&gt;Ильнар: загружена новая версия «Файл:Merge sort itearative.png»&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Iterative merge sort ex.&lt;/div&gt;</summary>
		<author><name>Ильнар</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:Merge_sort_itearative.png&amp;diff=46788</id>
		<title>Файл:Merge sort itearative.png</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:Merge_sort_itearative.png&amp;diff=46788"/>
				<updated>2015-05-22T16:49:57Z</updated>
		
		<summary type="html">&lt;p&gt;Ильнар: загружена новая версия «Файл:Merge sort itearative.png»&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Iterative merge sort ex.&lt;/div&gt;</summary>
		<author><name>Ильнар</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:Merge_sort_itearative.png&amp;diff=46787</id>
		<title>Файл:Merge sort itearative.png</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:Merge_sort_itearative.png&amp;diff=46787"/>
				<updated>2015-05-22T16:32:03Z</updated>
		
		<summary type="html">&lt;p&gt;Ильнар: Iterative merge sort ex.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Iterative merge sort ex.&lt;/div&gt;</summary>
		<author><name>Ильнар</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%A1%D0%BE%D1%80%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B0_%D1%81%D0%BB%D0%B8%D1%8F%D0%BD%D0%B8%D0%B5%D0%BC&amp;diff=46536</id>
		<title>Сортировка слиянием</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%A1%D0%BE%D1%80%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B0_%D1%81%D0%BB%D0%B8%D1%8F%D0%BD%D0%B8%D0%B5%D0%BC&amp;diff=46536"/>
				<updated>2015-05-15T19:07:35Z</updated>
		
		<summary type="html">&lt;p&gt;Ильнар: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''Сортировка слиянием''' (англ. ''Merge sort'') {{---}} алгоритм сортировки, пред­ло­женный Джо­ном фон Ней­ма­ном в 1945 го­ду.&lt;br /&gt;
&lt;br /&gt;
Это устойчивый алгоритм, использующий &amp;lt;tex&amp;gt;O(n)&amp;lt;/tex&amp;gt; дополнительной памяти и работающий за &amp;lt;tex&amp;gt;O(n&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;\log n)&amp;lt;/tex&amp;gt; времени.&lt;br /&gt;
&lt;br /&gt;
==Принцип работы==&lt;br /&gt;
[[Файл:Merging_two_arrays.png|270px|right|thumb|Пример работы процедуры слияния.]]&lt;br /&gt;
Алгоритм использует принцип «разделяй и властвуй»: задача разбивается на подзадачи меньшего размера, которые решаются по отдельности, после чего их решения комбинируются для получения решения исходной задачи. Конкретно процедуру сортировки слиянием можно описать следующим образом:&lt;br /&gt;
&lt;br /&gt;
# Если в рассматриваемом массиве один элемент, то он уже отсортирован {{---}} алгоритм завершает работу.&lt;br /&gt;
# Иначе массив разбивается на две части, которые сортируются рекурсивно.&lt;br /&gt;
# После сортировки двух частей массива к ним применяется процедура слияния, которая по двум отсортированным частям получает исходный отсортированный массив.&lt;br /&gt;
&lt;br /&gt;
===Слияние двух массивов===&lt;br /&gt;
У нас есть два массива &amp;lt;tex&amp;gt;a&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt; (фактически это будут две части одного массива, но для удобства будем писать, что у нас просто два массива). Нам надо получить массив &amp;lt;tex&amp;gt;c&amp;lt;/tex&amp;gt; размером &amp;lt;tex&amp;gt;|a| + |b|&amp;lt;/tex&amp;gt;. Для этого можно применить процедуру слияния. Эта процедура заключается в том, что мы сравниваем элементы массивов (начиная с начала) и меньший из них записываем в финальный. И затем, в массиве у которого оказался меньший элемент, переходим к следующему элементу и сравниваем теперь его. В конце, если один из массивов закончился, мы просто дописываем в финальный другой массив. После мы наш финальный массив записываем заместо двух исходных и получаем отсортированный участок.&lt;br /&gt;
&lt;br /&gt;
Множество отсортированных списков с операцией &amp;lt;tex&amp;gt;merge&amp;lt;/tex&amp;gt; является [[Моноид|моноидом]], &amp;lt;tex&amp;gt;\langle assorted\ list, merge, \varnothing \rangle &amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;\varnothing&amp;lt;/tex&amp;gt; {{---}} нейтральный элемент.&lt;br /&gt;
&lt;br /&gt;
Ниже приведён псевдокод процедуры слияния, который сливает две части массива &amp;lt;tex&amp;gt;a&amp;lt;/tex&amp;gt; {{---}} &amp;lt;tex&amp;gt;[left; mid)&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;[mid; right)&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 '''function''' merge(a : '''int[n]'''; left, mid, right : '''int'''):&lt;br /&gt;
     it1 = 0&lt;br /&gt;
     it2 = 0&lt;br /&gt;
     result : '''int[right - left]'''&lt;br /&gt;
   &lt;br /&gt;
     '''while''' left + it1 &amp;lt; mid '''and''' mid + it2 &amp;lt; right&lt;br /&gt;
         '''if''' a[left + it1] &amp;lt; a[mid + it2]&lt;br /&gt;
             result[it1 + it2] = a[left + it1]&lt;br /&gt;
             it1 += 1&lt;br /&gt;
         '''else'''&lt;br /&gt;
             result[it1 + it2] = a[mid + it2]&lt;br /&gt;
             it2 += 1&lt;br /&gt;
   &lt;br /&gt;
     '''while''' left + it1 &amp;lt; mid&lt;br /&gt;
         result[it1 + it2] = a[left + it1]&lt;br /&gt;
         it1 += 1&lt;br /&gt;
   &lt;br /&gt;
     '''while''' mid + it2 &amp;lt; right&lt;br /&gt;
         result[it1 + it2] = a[mid + it2]&lt;br /&gt;
         it2 += 1&lt;br /&gt;
   &lt;br /&gt;
     '''for''' i = 0 '''to''' it1 + it2&lt;br /&gt;
         a[left + i] = result[i]&lt;br /&gt;
&lt;br /&gt;
===Рекурсивный алгоритм===&lt;br /&gt;
[[Файл:Merge sort1.png|300px|right|thumb|Пример работы рекурсивного алгоритма сортировки слиянием]]&lt;br /&gt;
Функция сортирует подотрезок массива с индексами в полуинтервале &amp;lt;tex&amp;gt;[left; right)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&amp;lt;code style=&amp;quot;display: inline-block&amp;quot;&amp;gt;&lt;br /&gt;
 '''function''' mergeSortRecursive(a : '''int[n]'''; left, right : '''int'''):&lt;br /&gt;
     '''if''' left + 1 &amp;gt;= right&lt;br /&gt;
         '''return'''&lt;br /&gt;
     mid = (left + right) / 2&lt;br /&gt;
     mergeSortRecursive(a, left, mid)&lt;br /&gt;
     mergeSortRecursive(a, mid, right)&lt;br /&gt;
     merge(a, left, mid, right)&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
===Итеративный алгоритм===&lt;br /&gt;
Функция сортирует все элементы массива. На &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt; итерации мы делаем &amp;lt;tex&amp;gt;merge&amp;lt;/tex&amp;gt; двух соседних групп длиной &amp;lt;tex&amp;gt;2^i&amp;lt;/tex&amp;gt;. &lt;br /&gt;
&amp;lt;code style=&amp;quot;display: inline-block&amp;quot;&amp;gt;&lt;br /&gt;
 '''function''' mergeSortIterative(a : '''int[n]'''):&lt;br /&gt;
     '''for''' i = 1 '''to''' n, i *= 2&lt;br /&gt;
         '''for''' j = 0 '''to''' n - i, j += 2 * i&lt;br /&gt;
             merge(a, j, j + i, min(j + 2 * i, n))&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
==Время работы==&lt;br /&gt;
Чтобы оценить время работы этого алгоритма, составим рекуррентное соотношение. Пускай &amp;lt;tex&amp;gt;T(n)&amp;lt;/tex&amp;gt; {{---}} время сортировки массива длины &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt;, тогда для сортировки слиянием справедливо &amp;lt;tex&amp;gt;T(n)=2T(n/2)+O(n)&amp;lt;/tex&amp;gt; &amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;tex&amp;gt;O(n)&amp;lt;/tex&amp;gt; {{---}} время, необходимое на то, чтобы слить два массива. Распишем это соотношение:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;T(n)=2T(n/2)+O(n)=4T(n/4)+2O(n)=\dots=2^kT(1)+kO(n)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Осталось оценить &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt;. Мы знаем, что &amp;lt;tex&amp;gt;2^k=n&amp;lt;/tex&amp;gt;, а значит &amp;lt;tex&amp;gt;k=\log n&amp;lt;/tex&amp;gt;. Уравнение примет вид &amp;lt;tex&amp;gt;T(n)=nT(1)+ \log n&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;O(n)&amp;lt;/tex&amp;gt;. Так как &amp;lt;tex&amp;gt;T(1)&amp;lt;/tex&amp;gt; {{---}} константа, то &amp;lt;tex&amp;gt;T(n)=O(n)+\log n &amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;O(n)=O(n\log n)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==См. также==&lt;br /&gt;
* [[Сортировка кучей]]&lt;br /&gt;
* [[Быстрая сортировка]]&lt;br /&gt;
*[[Cортировка слиянием с использованием O(1) дополнительной памяти]]&lt;br /&gt;
&lt;br /&gt;
==Источники информации==&lt;br /&gt;
*[http://ru.wikipedia.org/wiki/Mergesort Википедия {{---}} сортировка слиянием]&lt;br /&gt;
*[http://www.sorting-algorithms.com/merge-sort Визуализатор]&lt;br /&gt;
*[http://ru.wikibooks.org/wiki/%D0%9F%D1%80%D0%B8%D0%BC%D0%B5%D1%80%D1%8B_%D1%80%D0%B5%D0%B0%D0%BB%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D0%B8_%D1%81%D0%BE%D1%80%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B8_%D1%81%D0%BB%D0%B8%D1%8F%D0%BD%D0%B8%D0%B5%D0%BC Викиучебник {{---}} Примеры реализации на различных языках программирования]&lt;br /&gt;
&lt;br /&gt;
[[Категория: Дискретная математика и алгоритмы]]&lt;br /&gt;
[[Категория: Сортировка]]&lt;br /&gt;
[[Категория: Сортировки на сравнениях]]&lt;/div&gt;</summary>
		<author><name>Ильнар</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%A1%D0%BE%D1%80%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B0_%D1%81%D0%BB%D0%B8%D1%8F%D0%BD%D0%B8%D0%B5%D0%BC&amp;diff=46451</id>
		<title>Сортировка слиянием</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%A1%D0%BE%D1%80%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B0_%D1%81%D0%BB%D0%B8%D1%8F%D0%BD%D0%B8%D0%B5%D0%BC&amp;diff=46451"/>
				<updated>2015-05-14T10:12:16Z</updated>
		
		<summary type="html">&lt;p&gt;Ильнар: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''Сортировка слиянием''' (англ. ''Merge sort'') {{---}} алгоритм сортировки, пред­ло­женный Джо­ном фон Ней­ма­ном в 1945 го­ду.&lt;br /&gt;
&lt;br /&gt;
Это устойчивый алгоритм, использующий &amp;lt;tex&amp;gt;O(n)&amp;lt;/tex&amp;gt; дополнительной памяти и работающий за &amp;lt;tex&amp;gt;O(n&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;\log n)&amp;lt;/tex&amp;gt; времени.&lt;br /&gt;
&lt;br /&gt;
==Принцип работы==&lt;br /&gt;
[[Файл:Merging_two_arrays.png|270px|right|thumb|Пример работы процедуры слияния.]]&lt;br /&gt;
Алгоритм использует принцип «разделяй и властвуй»: задача разбивается на подзадачи меньшего размера, которые решаются по отдельности, после чего их решения комбинируются для получения решения исходной задачи. Конкретно процедуру сортировки слиянием можно описать следующим образом:&lt;br /&gt;
&lt;br /&gt;
# Если в рассматриваемом массиве один элемент, то он уже отсортирован {{---}} алгоритм завершает работу.&lt;br /&gt;
# Иначе массив разбивается на две части, которые сортируются рекурсивно.&lt;br /&gt;
# После сортировки двух частей массива к ним применяется процедура слияния, которая по двум отсортированным частям получает исходный отсортированный массив.&lt;br /&gt;
&lt;br /&gt;
===Слияние двух массивов===&lt;br /&gt;
У нас есть два массива &amp;lt;tex&amp;gt;a&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt; (фактически это будут две части одного массива, но для удобства будем писать, что у нас просто два массива). Нам надо получить массив &amp;lt;tex&amp;gt;c&amp;lt;/tex&amp;gt; размером &amp;lt;tex&amp;gt;|a| + |b|&amp;lt;/tex&amp;gt;. Для этого можно применить процедуру слияния. Эта процедура заключается в том, что мы сравниваем элементы массивов (начиная с начала) и меньший из них записываем в финальный. И затем, в массиве у которого оказался меньший элемент, переходим к следующему элементу и сравниваем теперь его. В конце, если один из массивов закончился, мы просто дописываем в финальный другой массив. После мы наш финальный массив записываем заместо двух исходных и получаем отсортированный участок.&lt;br /&gt;
&lt;br /&gt;
Множество отсортированных списков с операцией &amp;lt;tex&amp;gt;merge&amp;lt;/tex&amp;gt; является [[Моноид|моноидом]], &amp;lt;tex&amp;gt;\langle assorted\ list, merge, \varnothing \rangle &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Ниже приведён псевдокод процедуры слияния, который сливает две части массива &amp;lt;tex&amp;gt;a&amp;lt;/tex&amp;gt; {{---}} &amp;lt;tex&amp;gt;[left; mid)&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;[mid; right)&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 '''function''' merge(a : '''int[n]'''; left, mid, right : '''int'''):&lt;br /&gt;
     it1 = 0&lt;br /&gt;
     it2 = 0&lt;br /&gt;
     result : '''int[right - left]'''&lt;br /&gt;
   &lt;br /&gt;
     '''while''' left + it1 &amp;lt; mid '''and''' mid + it2 &amp;lt; right&lt;br /&gt;
         '''if''' a[left + it1] &amp;lt; a[mid + it2]&lt;br /&gt;
             result[it1 + it2] = a[left + it1]&lt;br /&gt;
             it1 += 1&lt;br /&gt;
         '''else'''&lt;br /&gt;
             result[it1 + it2] = a[mid + it2]&lt;br /&gt;
             it2 += 1&lt;br /&gt;
   &lt;br /&gt;
     '''while''' left + it1 &amp;lt; mid&lt;br /&gt;
         result[it1 + it2] = a[left + it1]&lt;br /&gt;
         it1 += 1&lt;br /&gt;
   &lt;br /&gt;
     '''while''' mid + it2 &amp;lt; right&lt;br /&gt;
         result[it1 + it2] = a[mid + it2]&lt;br /&gt;
         it2 += 1&lt;br /&gt;
   &lt;br /&gt;
     '''for''' i = 0 '''to''' it1 + it2&lt;br /&gt;
         a[left + i] = result[i]&lt;br /&gt;
&lt;br /&gt;
===Рекурсивный алгоритм===&lt;br /&gt;
[[Файл:Merge sort1.png|300px|right|thumb|Пример работы рекурсивного алгоритма сортировки слиянием]]&lt;br /&gt;
Функция сортирует подотрезок массива с индексами в полуинтервале &amp;lt;tex&amp;gt;[left; right)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&amp;lt;code style=&amp;quot;display: inline-block&amp;quot;&amp;gt;&lt;br /&gt;
 '''function''' mergeSortRecursive(a : '''int[n]'''; left, right : '''int'''):&lt;br /&gt;
     '''if''' left + 1 &amp;gt;= right&lt;br /&gt;
         '''return'''&lt;br /&gt;
     mid = (left + right) / 2&lt;br /&gt;
     mergeSortRecursive(a, left, mid)&lt;br /&gt;
     mergeSortRecursive(a, mid, right)&lt;br /&gt;
     merge(a, left, mid, right)&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
===Итеративный алгоритм===&lt;br /&gt;
&amp;lt;code style=&amp;quot;display: inline-block&amp;quot;&amp;gt;&lt;br /&gt;
 '''function''' mergeSortIterative(a : '''int[n]'''):&lt;br /&gt;
     '''for''' i = 1 '''to''' n, i *= 2&lt;br /&gt;
         '''for''' j = 0 '''to''' n - i, j += 2 * i&lt;br /&gt;
             merge(a, j, j + i, min(j + 2 * i, n))&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
==Время работы==&lt;br /&gt;
Чтобы оценить время работы этого алгоритма, составим рекуррентное соотношение. Пускай &amp;lt;tex&amp;gt;T(n)&amp;lt;/tex&amp;gt; {{---}} время сортировки массива длины &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt;, тогда для сортировки слиянием справедливо &amp;lt;tex&amp;gt;T(n)=2T(n/2)+O(n)&amp;lt;/tex&amp;gt; &amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;tex&amp;gt;O(n)&amp;lt;/tex&amp;gt; {{---}} время, необходимое на то, чтобы слить два массива. Распишем это соотношение:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;T(n)=2T(n/2)+O(n)=4T(n/4)+2O(n)=\dots=2^kT(1)+kO(n)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Осталось оценить &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt;. Мы знаем, что &amp;lt;tex&amp;gt;2^k=n&amp;lt;/tex&amp;gt;, а значит &amp;lt;tex&amp;gt;k=\log n&amp;lt;/tex&amp;gt;. Уравнение примет вид &amp;lt;tex&amp;gt;T(n)=nT(1)+ \log n&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;O(n)&amp;lt;/tex&amp;gt;. Так как &amp;lt;tex&amp;gt;T(1)&amp;lt;/tex&amp;gt; {{---}} константа, то &amp;lt;tex&amp;gt;T(n)=O(n)+\log n &amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;O(n)=O(n\log n)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==См. также==&lt;br /&gt;
* [[Сортировка кучей]]&lt;br /&gt;
* [[Быстрая сортировка]]&lt;br /&gt;
*[[Cортировка слиянием с использованием O(1) дополнительной памяти]]&lt;br /&gt;
&lt;br /&gt;
==Ссылки==&lt;br /&gt;
*[http://ru.wikipedia.org/wiki/Mergesort Википедия {{---}} сортировка слиянием]&lt;br /&gt;
*[http://www.sorting-algorithms.com/merge-sort Визуализатор]&lt;br /&gt;
*[http://ru.wikibooks.org/wiki/%D0%9F%D1%80%D0%B8%D0%BC%D0%B5%D1%80%D1%8B_%D1%80%D0%B5%D0%B0%D0%BB%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D0%B8_%D1%81%D0%BE%D1%80%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B8_%D1%81%D0%BB%D0%B8%D1%8F%D0%BD%D0%B8%D0%B5%D0%BC Викиучебник {{---}} Примеры реализации на различных языках программирования]&lt;br /&gt;
&lt;br /&gt;
[[Категория: Дискретная математика и алгоритмы]]&lt;br /&gt;
[[Категория: Сортировка]]&lt;br /&gt;
[[Категория: Сортировки на сравнениях]]&lt;/div&gt;</summary>
		<author><name>Ильнар</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%A1%D0%BE%D1%80%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B0_%D1%81%D0%BB%D0%B8%D1%8F%D0%BD%D0%B8%D0%B5%D0%BC&amp;diff=46150</id>
		<title>Сортировка слиянием</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%A1%D0%BE%D1%80%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B0_%D1%81%D0%BB%D0%B8%D1%8F%D0%BD%D0%B8%D0%B5%D0%BC&amp;diff=46150"/>
				<updated>2015-05-09T11:31:49Z</updated>
		
		<summary type="html">&lt;p&gt;Ильнар: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''Сортировка слиянием''' (англ. ''Merge sort'') {{---}} алгоритм сортировки, пред­ло­женный Джо­ном фон Ней­ма­ном в 1945 го­ду.&lt;br /&gt;
&lt;br /&gt;
Это устойчивый алгоритм, использующий &amp;lt;tex&amp;gt;O(n)&amp;lt;/tex&amp;gt; дополнительной памяти и работающий за &amp;lt;tex&amp;gt;O(n&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;\log n)&amp;lt;/tex&amp;gt; времени.&lt;br /&gt;
&lt;br /&gt;
==Принцип работы==&lt;br /&gt;
[[Файл:Merging_two_arrays.png|270px|right|thumb|Пример работы процедуры слияния.]]&lt;br /&gt;
Алгоритм использует принцип «разделяй и властвуй»: задача разбивается на подзадачи меньшего размера, которые решаются по отдельности, после чего их решения комбинируются для получения решения исходной задачи. Конкретно процедуру сортировки слиянием можно описать следующим образом:&lt;br /&gt;
&lt;br /&gt;
# Если в рассматриваемом массиве один элемент, то он уже отсортирован {{---}} алгоритм завершает работу.&lt;br /&gt;
# Иначе массив разбивается на две части, которые сортируются рекурсивно.&lt;br /&gt;
# После сортировки двух частей массива к ним применяется процедура слияния, которая по двум отсортированным частям получает исходный отсортированный массив.&lt;br /&gt;
&lt;br /&gt;
===Слияние двух массивов===&lt;br /&gt;
У нас есть два массива &amp;lt;tex&amp;gt;a&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt; (фактически это будут две части одного массива, но для удобства будем писать, что у нас просто два массива). Нам надо получить массив &amp;lt;tex&amp;gt;c&amp;lt;/tex&amp;gt; размером &amp;lt;tex&amp;gt;|a| + |b|&amp;lt;/tex&amp;gt;. Для этого можно применить процедуру слияния. Эта процедура заключается в том, что мы сравниваем элементы массивов (начиная с начала) и меньший из них записываем в финальный. И затем, в массиве у которого оказался меньший элемент, переходим к следующему элементу и сравниваем теперь его. В конце, если один из массивов закончился, мы просто дописываем в финальный другой массив. После мы наш финальный массив записываем заместо двух исходных и получаем отсортированный участок.&lt;br /&gt;
&lt;br /&gt;
Два отсортированных списка с операцией &amp;lt;tex&amp;gt;merge&amp;lt;/tex&amp;gt; являются моноидом.&lt;br /&gt;
&lt;br /&gt;
Ниже приведён псевдокод процедуры слияния, который сливает две части массива &amp;lt;tex&amp;gt;a&amp;lt;/tex&amp;gt; {{---}} &amp;lt;tex&amp;gt;[left; mid)&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;[mid; right)&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 '''function''' merge(a : '''int[n]'''; left, mid, right : '''int'''):&lt;br /&gt;
     it1 = 0&lt;br /&gt;
     it2 = 0&lt;br /&gt;
     result : '''int[right - left]'''&lt;br /&gt;
   &lt;br /&gt;
     '''while''' left + it1 &amp;lt; mid '''and''' mid + it2 &amp;lt; right&lt;br /&gt;
         '''if''' a[left + it1] &amp;lt; a[mid + it2]&lt;br /&gt;
             result[it1 + it2] = a[left + it1]&lt;br /&gt;
             it1 += 1&lt;br /&gt;
         '''else'''&lt;br /&gt;
             result[it1 + it2] = a[mid + it2]&lt;br /&gt;
             it2 += 1&lt;br /&gt;
   &lt;br /&gt;
     '''while''' left + it1 &amp;lt; mid&lt;br /&gt;
         result[it1 + it2] = a[left + it1]&lt;br /&gt;
         it1 += 1&lt;br /&gt;
   &lt;br /&gt;
     '''while''' mid + it2 &amp;lt; right&lt;br /&gt;
         result[it1 + it2] = a[mid + it2]&lt;br /&gt;
         it2 += 1&lt;br /&gt;
   &lt;br /&gt;
     '''for''' i = 0 '''to''' it1 + it2&lt;br /&gt;
         a[left + i] = result[i]&lt;br /&gt;
&lt;br /&gt;
===Рекурсивный алгоритм===&lt;br /&gt;
[[Файл:Merge sort1.png|300px|right|thumb|Пример работы рекурсивного алгоритма сортировки слиянием]]&lt;br /&gt;
Функция сортирует подотрезок массива с индексами в полуинтервале &amp;lt;tex&amp;gt;[left; right)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&amp;lt;code style=&amp;quot;display: inline-block&amp;quot;&amp;gt;&lt;br /&gt;
 '''function''' mergeSortRecursive(a : '''int[n]'''; left, right : '''int'''):&lt;br /&gt;
     '''if''' left + 1 &amp;gt;= right&lt;br /&gt;
         '''return'''&lt;br /&gt;
     mid = (left + right) / 2&lt;br /&gt;
     mergeSortRecursive(a, left, mid)&lt;br /&gt;
     mergeSortRecursive(a, mid, right)&lt;br /&gt;
     merge(a, left, mid, right)&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
===Итеративный алгоритм===&lt;br /&gt;
&amp;lt;code style=&amp;quot;display: inline-block&amp;quot;&amp;gt;&lt;br /&gt;
 '''function''' mergeSortIterative(a : '''int[n]'''):&lt;br /&gt;
     '''for''' i = 1 '''to''' n, i *= 2&lt;br /&gt;
         '''for''' j = 0 '''to''' n - i, j += 2 * i&lt;br /&gt;
             merge(a, j, j + i, min(j + 2 * i, n))&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
==Время работы==&lt;br /&gt;
Чтобы оценить время работы этого алгоритма, составим рекуррентное соотношение. Пускай &amp;lt;tex&amp;gt;T(n)&amp;lt;/tex&amp;gt; {{---}} время сортировки массива длины &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt;, тогда для сортировки слиянием справедливо &amp;lt;tex&amp;gt;T(n)=2T(n/2)+O(n)&amp;lt;/tex&amp;gt; &amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;tex&amp;gt;O(n)&amp;lt;/tex&amp;gt; {{---}} время, необходимое на то, чтобы слить два массива. Распишем это соотношение:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;T(n)=2T(n/2)+O(n)=4T(n/4)+2O(n)=\dots=2^kT(1)+kO(n)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Осталось оценить &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt;. Мы знаем, что &amp;lt;tex&amp;gt;2^k=n&amp;lt;/tex&amp;gt;, а значит &amp;lt;tex&amp;gt;k=\log n&amp;lt;/tex&amp;gt;. Уравнение примет вид &amp;lt;tex&amp;gt;T(n)=nT(1)+ \log n&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;O(n)&amp;lt;/tex&amp;gt;. Так как &amp;lt;tex&amp;gt;T(1)&amp;lt;/tex&amp;gt; {{---}} константа, то &amp;lt;tex&amp;gt;T(n)=O(n)+\log n &amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;O(n)=O(n\log n)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==См. также==&lt;br /&gt;
* [[Сортировка кучей]]&lt;br /&gt;
* [[Быстрая сортировка]]&lt;br /&gt;
*[[Cортировка слиянием с использованием O(1) дополнительной памяти]]&lt;br /&gt;
&lt;br /&gt;
==Ссылки==&lt;br /&gt;
*[http://ru.wikipedia.org/wiki/Mergesort Википедия {{---}} сортировка слиянием]&lt;br /&gt;
*[http://www.sorting-algorithms.com/merge-sort Визуализатор]&lt;br /&gt;
*[http://ru.wikibooks.org/wiki/%D0%9F%D1%80%D0%B8%D0%BC%D0%B5%D1%80%D1%8B_%D1%80%D0%B5%D0%B0%D0%BB%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D0%B8_%D1%81%D0%BE%D1%80%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B8_%D1%81%D0%BB%D0%B8%D1%8F%D0%BD%D0%B8%D0%B5%D0%BC Викиучебник {{---}} Примеры реализации на различных языках программирования]&lt;br /&gt;
&lt;br /&gt;
[[Категория: Дискретная математика и алгоритмы]]&lt;br /&gt;
[[Категория: Сортировка]]&lt;br /&gt;
[[Категория: Сортировки на сравнениях]]&lt;/div&gt;</summary>
		<author><name>Ильнар</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%A1%D0%BE%D1%80%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B0_%D1%81%D0%BB%D0%B8%D1%8F%D0%BD%D0%B8%D0%B5%D0%BC&amp;diff=46149</id>
		<title>Сортировка слиянием</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%A1%D0%BE%D1%80%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B0_%D1%81%D0%BB%D0%B8%D1%8F%D0%BD%D0%B8%D0%B5%D0%BC&amp;diff=46149"/>
				<updated>2015-05-09T11:25:53Z</updated>
		
		<summary type="html">&lt;p&gt;Ильнар: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''Сортировка слиянием''' (англ. ''Merge sort'') {{---}} алгоритм сортировки, пред­ло­женный Джо­ном фон Ней­ма­ном в 1945 го­ду.&lt;br /&gt;
&lt;br /&gt;
Это устойчивый алгоритм, использующий &amp;lt;tex&amp;gt;O(n)&amp;lt;/tex&amp;gt; дополнительной памяти и работающий за &amp;lt;tex&amp;gt;O(n&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;\log n)&amp;lt;/tex&amp;gt; времени.&lt;br /&gt;
&lt;br /&gt;
==Принцип работы==&lt;br /&gt;
[[Файл:Merging_two_arrays.png|270px|right|thumb|Пример работы процедуры слияния.]]&lt;br /&gt;
Алгоритм использует принцип «разделяй и властвуй»: задача разбивается на подзадачи меньшего размера, которые решаются по отдельности, после чего их решения комбинируются для получения решения исходной задачи. Конкретно процедуру сортировки слиянием можно описать следующим образом:&lt;br /&gt;
&lt;br /&gt;
# Если в рассматриваемом массиве один элемент, то он уже отсортирован {{---}} алгоритм завершает работу.&lt;br /&gt;
# Иначе массив разбивается на две части, которые сортируются рекурсивно.&lt;br /&gt;
# После сортировки двух частей массива к ним применяется процедура слияния, которая по двум отсортированным частям получает исходный отсортированный массив.&lt;br /&gt;
&lt;br /&gt;
===Слияние двух массивов===&lt;br /&gt;
У нас есть два массива &amp;lt;tex&amp;gt;a&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt; (фактически это будут две части одного массива, но для удобства будем писать, что у нас просто два массива). Нам надо получить массив &amp;lt;tex&amp;gt;c&amp;lt;/tex&amp;gt; размером &amp;lt;tex&amp;gt;|a| + |b|&amp;lt;/tex&amp;gt;. Для этого можно применить процедуру слияния. Эта процедура заключается в том, что мы сравниваем элементы массивов (начиная с начала) и меньший из них записываем в финальный. И затем, в массиве у которого оказался меньший элемент, переходим к следующему элементу и сравниваем теперь его. В конце, если один из массивов закончился, мы просто дописываем в финальный другой массив. После мы наш финальный массив записываем заместо двух исходных и получаем отсортированный участок.&lt;br /&gt;
&lt;br /&gt;
Два отсортированных списка с операцией &amp;lt;tex&amp;gt;merge&amp;lt;/tex&amp;gt; являются моноидом.&lt;br /&gt;
&lt;br /&gt;
Ниже приведён псевдокод процедуры слияния, который сливает две части массива &amp;lt;tex&amp;gt;a&amp;lt;/tex&amp;gt; {{---}} &amp;lt;tex&amp;gt;[left; mid)&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;[mid; right)&amp;lt;/tex&amp;gt;&lt;br /&gt;
&amp;lt;code style=&amp;quot;display: inline-block&amp;quot;&amp;gt;&lt;br /&gt;
 '''function''' merge(a : '''int[n]'''; left, mid, right : '''int'''):&lt;br /&gt;
     it1 = 0&lt;br /&gt;
     it2 = 0&lt;br /&gt;
     result : '''int[right - left]'''&lt;br /&gt;
   &lt;br /&gt;
     '''while''' left + it1 &amp;lt; mid '''and''' mid + it2 &amp;lt; right&lt;br /&gt;
         '''if''' a[left + it1] &amp;lt; a[mid + it2]&lt;br /&gt;
             result[it1 + it2] = a[left + it1]&lt;br /&gt;
             it1 += 1&lt;br /&gt;
         '''else'''&lt;br /&gt;
             result[it1 + it2] = a[mid + it2]&lt;br /&gt;
             it2 += 1&lt;br /&gt;
   &lt;br /&gt;
     '''while''' left + it1 &amp;lt; mid&lt;br /&gt;
         result[it1 + it2] = a[left + it1]&lt;br /&gt;
         it1 += 1&lt;br /&gt;
   &lt;br /&gt;
     '''while''' mid + it2 &amp;lt; right&lt;br /&gt;
         result[it1 + it2] = a[mid + it2]&lt;br /&gt;
         it2 += 1&lt;br /&gt;
   &lt;br /&gt;
     '''for''' i = 0 '''to''' it1 + it2&lt;br /&gt;
         a[left + i] = result[i]&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
===Рекурсивный алгоритм===&lt;br /&gt;
Функция сортирует подотрезок массива с индексами в полуинтервале &amp;lt;tex&amp;gt;[left; right)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
[[Файл:Merge sort1.png|300px|right|thumb|Пример работы рекурсивного алгоритма сортировки слиянием]]&lt;br /&gt;
&amp;lt;code style=&amp;quot;display: inline-block&amp;quot;&amp;gt;&lt;br /&gt;
 '''function''' mergeSortRecursive(a : '''int[n]'''; left, right : '''int'''):&lt;br /&gt;
     '''if''' left + 1 &amp;gt;= right&lt;br /&gt;
         '''return'''&lt;br /&gt;
     mid = (left + right) / 2&lt;br /&gt;
     mergeSortRecursive(a, left, mid)&lt;br /&gt;
     mergeSortRecursive(a, mid, right)&lt;br /&gt;
     merge(a, left, mid, right)&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
===Итеративный алгоритм===&lt;br /&gt;
&amp;lt;code style=&amp;quot;display: inline-block&amp;quot;&amp;gt;&lt;br /&gt;
 '''function''' mergeSortIterative(a : '''int[n]'''):&lt;br /&gt;
     '''for''' i = 1 '''to''' n, i *= 2&lt;br /&gt;
         '''for''' j = 0 '''to''' n - i, j += 2 * i&lt;br /&gt;
             merge(a, j, j + i, min(j + 2 * i, n))&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
==Время работы==&lt;br /&gt;
Чтобы оценить время работы этого алгоритма, составим рекуррентное соотношение. Пускай &amp;lt;tex&amp;gt;T(n)&amp;lt;/tex&amp;gt; {{---}} время сортировки массива длины &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt;, тогда для сортировки слиянием справедливо &amp;lt;tex&amp;gt;T(n)=2T(n/2)+O(n)&amp;lt;/tex&amp;gt; &amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;tex&amp;gt;O(n)&amp;lt;/tex&amp;gt; {{---}} время, необходимое на то, чтобы слить два массива. Распишем это соотношение:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;T(n)=2T(n/2)+O(n)=4T(n/4)+2O(n)=\dots=2^kT(1)+kO(n)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Осталось оценить &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt;. Мы знаем, что &amp;lt;tex&amp;gt;2^k=n&amp;lt;/tex&amp;gt;, а значит &amp;lt;tex&amp;gt;k=\log n&amp;lt;/tex&amp;gt;. Уравнение примет вид &amp;lt;tex&amp;gt;T(n)=nT(1)+ \log n&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;O(n)&amp;lt;/tex&amp;gt;. Так как &amp;lt;tex&amp;gt;T(1)&amp;lt;/tex&amp;gt; {{---}} константа, то &amp;lt;tex&amp;gt;T(n)=O(n)+\log n &amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;O(n)=O(n\log n)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==См. также==&lt;br /&gt;
* [[Сортировка кучей]]&lt;br /&gt;
* [[Быстрая сортировка]]&lt;br /&gt;
*[[Cортировка слиянием с использованием O(1) дополнительной памяти]]&lt;br /&gt;
&lt;br /&gt;
===Ссылки===&lt;br /&gt;
*[http://ru.wikipedia.org/wiki/Mergesort Википедия {{---}} сортировка слиянием]&lt;br /&gt;
*[http://www.sorting-algorithms.com/merge-sort Визуализатор]&lt;br /&gt;
*[http://ru.wikibooks.org/wiki/%D0%9F%D1%80%D0%B8%D0%BC%D0%B5%D1%80%D1%8B_%D1%80%D0%B5%D0%B0%D0%BB%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D0%B8_%D1%81%D0%BE%D1%80%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B8_%D1%81%D0%BB%D0%B8%D1%8F%D0%BD%D0%B8%D0%B5%D0%BC Викиучебник {{---}} Примеры реализации на различных языках программирования]&lt;br /&gt;
&lt;br /&gt;
[[Категория: Дискретная математика и алгоритмы]]&lt;br /&gt;
[[Категория: Сортировка]]&lt;br /&gt;
[[Категория: Сортировки на сравнениях]]&lt;/div&gt;</summary>
		<author><name>Ильнар</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%A1%D0%BE%D1%80%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B0_%D1%81%D0%BB%D0%B8%D1%8F%D0%BD%D0%B8%D0%B5%D0%BC&amp;diff=46144</id>
		<title>Сортировка слиянием</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%A1%D0%BE%D1%80%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B0_%D1%81%D0%BB%D0%B8%D1%8F%D0%BD%D0%B8%D0%B5%D0%BC&amp;diff=46144"/>
				<updated>2015-05-09T10:07:51Z</updated>
		
		<summary type="html">&lt;p&gt;Ильнар: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''Сортировка слиянием''' (англ. ''Merge sort'') {{---}} алгоритм сортировки, пред­ло­женный Джо­ном фон Ней­ма­ном в 1945 го­ду.&lt;br /&gt;
&lt;br /&gt;
Это устойчивый алгоритм, использующий &amp;lt;tex&amp;gt;O(n)&amp;lt;/tex&amp;gt; дополнительной памяти и &amp;lt;tex&amp;gt;O(n&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;\log n)&amp;lt;/tex&amp;gt; времени.&lt;br /&gt;
&lt;br /&gt;
==Принцип работы==&lt;br /&gt;
[[Файл:Merging_two_arrays.png|270px|right|thumb|Пример работы процедуры слияния.]]&lt;br /&gt;
Алгоритм использует принцип «разделяй и властвуй»: задача разбивается на подзадачи меньшего размера, которые решаются по отдельности, после чего их решения комбинируются для получения решения исходной задачи. Конкретно процедуру сортировки слиянием можно описать следующим образом:&lt;br /&gt;
&lt;br /&gt;
# Если в рассматриваемом массиве один элемент, то он уже отсортирован {{---}} алгоритм завершает работу.&lt;br /&gt;
# Иначе массив разбивается на две части, которые сортируются рекурсивно.&lt;br /&gt;
# После сортировки двух частей массива к ним применяется процедура слияния, которая по двум отсортированным частям получает исходный отсортированный массив.&lt;br /&gt;
&lt;br /&gt;
===Слияние двух массивов===&lt;br /&gt;
У нас есть два массива &amp;lt;tex&amp;gt;A&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;B&amp;lt;/tex&amp;gt; (фактически это будут две части одного массива, но для удобства будем писать, что у нас просто два массива). Нам надо получить массив &amp;lt;tex&amp;gt;C&amp;lt;/tex&amp;gt; размером &amp;lt;tex&amp;gt;|A| + |B|&amp;lt;/tex&amp;gt;. Для этого можно применить процедуру слияния. Эта процедура заключается в том, что мы сравниваем элементы массивов (начиная с начала) и меньший из них записываем в финальный. И затем, в массиве у которого оказался меньший элемент, переходим к следующему элементу и сравниваем теперь его. В конце, если один из массивов закончился, мы просто дописываем в финальный другой массив. После мы наш финальный массив записываем заместо двух исходных и получаем отсортированный участок.&lt;br /&gt;
&lt;br /&gt;
Два отсортированных списка с операцией &amp;lt;tex&amp;gt;merge&amp;lt;/tex&amp;gt; являются моноидом.&lt;br /&gt;
&lt;br /&gt;
Ниже приведён псевдокод процедуры слияния, который сливает две части массива &amp;lt;tex&amp;gt;A&amp;lt;/tex&amp;gt; {{---}} &amp;lt;tex&amp;gt;[left; mid)&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;[mid; right)&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 '''function''' merge(a : '''int[n]'''; left, mid, right : '''int'''):&lt;br /&gt;
     it1 = 0&lt;br /&gt;
     it2 = 0&lt;br /&gt;
     result : '''int[right - left]'''&lt;br /&gt;
   &lt;br /&gt;
     '''while''' left + it1 &amp;lt; mid '''and''' mid + it2 &amp;lt; right&lt;br /&gt;
         '''if''' a[left + it1] &amp;lt; a[mid + it2]&lt;br /&gt;
             result[it1 + it2] = a[left + it1]&lt;br /&gt;
             it1 += 1&lt;br /&gt;
         '''else'''&lt;br /&gt;
             result[it1 + it2] = a[mid + it2]&lt;br /&gt;
             it2 += 1&lt;br /&gt;
   &lt;br /&gt;
     '''while''' left + it1 &amp;lt; mid&lt;br /&gt;
         result[it1 + it2] = a[left + it1]&lt;br /&gt;
         it1 += 1&lt;br /&gt;
   &lt;br /&gt;
     '''while''' mid + it2 &amp;lt; right&lt;br /&gt;
         result[it1 + it2] = a[mid + it2]&lt;br /&gt;
         it2 += 1&lt;br /&gt;
   &lt;br /&gt;
     '''for''' i = 0 '''to''' it1 + it2&lt;br /&gt;
         a[left + i] = result[i]&lt;br /&gt;
&lt;br /&gt;
===Рекурсивный алгоритм===&lt;br /&gt;
Функция сортирует подотрезок массива с индексами в полуинтервале &amp;lt;tex&amp;gt;[left; right)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
 '''function''' mergeSortRecursive(a : '''int[n]'''; left, right : '''int'''):&lt;br /&gt;
     '''if''' left + 1 &amp;gt;= right&lt;br /&gt;
         '''return'''&lt;br /&gt;
     mid = (left + right) / 2&lt;br /&gt;
     mergeSortRecursive(a, left, mid)&lt;br /&gt;
     mergeSortRecursive(a, mid, right)&lt;br /&gt;
     merge(a, left, mid, right)&lt;br /&gt;
&lt;br /&gt;
[[Файл:Merge sort1.png|300px|Пример работы рекурсивного алгоритма сортировки слиянием]]&lt;br /&gt;
&lt;br /&gt;
===Итеративный алгоритм===&lt;br /&gt;
Функция сортирует подотрезок массива с индексами в полуинтервале &amp;lt;tex&amp;gt;[left; right)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
 '''function''' mergeSortIterative(a : '''int[n]'''; left, right : '''int'''):&lt;br /&gt;
     '''for''' i = 1 '''to''' n, i *= 2&lt;br /&gt;
         '''for''' j = left '''to''' right - i, j += 2 * i&lt;br /&gt;
             merge(a, j, j + i, min(j + 2 * i, right))&lt;br /&gt;
 &lt;br /&gt;
==Время работы==&lt;br /&gt;
Чтобы оценить время работы этого алгоритма, составим рекуррентное соотношение. Пускай &amp;lt;tex&amp;gt;T(n)&amp;lt;/tex&amp;gt; {{---}} время сортировки массива длины &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt;, тогда для сортировки слиянием справедливо &amp;lt;tex&amp;gt;T(n)=2T(n/2)+O(n)&amp;lt;/tex&amp;gt; &amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;tex&amp;gt;O(n)&amp;lt;/tex&amp;gt; {{---}} время, необходимое на то, чтобы слить два массива. Распишем это соотношение:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;T(n)=2T(n/2)+O(n)=4T(n/4)+2O(n)=\dots=2^kT(1)+kO(n)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Осталось оценить &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt;. Мы знаем, что &amp;lt;tex&amp;gt;2^k=n&amp;lt;/tex&amp;gt;, а значит &amp;lt;tex&amp;gt;k=\log n&amp;lt;/tex&amp;gt;. Уравнение примет вид &amp;lt;tex&amp;gt;T(n)=nT(1)+ \log n&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;O(n)&amp;lt;/tex&amp;gt;. Так как &amp;lt;tex&amp;gt;T(1)&amp;lt;/tex&amp;gt; {{---}} константа, то &amp;lt;tex&amp;gt;T(n)=O(n)+\log n &amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;O(n)=O(n\log n)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==Источники информации==&lt;br /&gt;
*[http://ru.wikipedia.org/wiki/Mergesort Википедия {{---}} сортировка слиянием]&lt;br /&gt;
&lt;br /&gt;
==См. также==&lt;br /&gt;
* [[Сортировка кучей]]&lt;br /&gt;
* [[Быстрая сортировка]]&lt;br /&gt;
*[[Cортировка слиянием с использованием O(1) дополнительной памяти]]&lt;br /&gt;
*[http://www.sorting-algorithms.com/merge-sort Визуализатор]&lt;br /&gt;
*[http://ru.wikibooks.org/wiki/%D0%9F%D1%80%D0%B8%D0%BC%D0%B5%D1%80%D1%8B_%D1%80%D0%B5%D0%B0%D0%BB%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D0%B8_%D1%81%D0%BE%D1%80%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B8_%D1%81%D0%BB%D0%B8%D1%8F%D0%BD%D0%B8%D0%B5%D0%BC Викиучебник {{---}} Примеры реализации на различных языках программирования]&lt;br /&gt;
&lt;br /&gt;
[[Категория: Дискретная математика и алгоритмы]]&lt;br /&gt;
[[Категория: Сортировка]]&lt;br /&gt;
[[Категория: Сортировки на сравнениях]]&lt;/div&gt;</summary>
		<author><name>Ильнар</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%A1%D0%BE%D1%80%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B0_%D1%81%D0%BB%D0%B8%D1%8F%D0%BD%D0%B8%D0%B5%D0%BC&amp;diff=46142</id>
		<title>Сортировка слиянием</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%A1%D0%BE%D1%80%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B0_%D1%81%D0%BB%D0%B8%D1%8F%D0%BD%D0%B8%D0%B5%D0%BC&amp;diff=46142"/>
				<updated>2015-05-09T10:04:18Z</updated>
		
		<summary type="html">&lt;p&gt;Ильнар: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''Сортировка слиянием''' (англ. ''Merge sort'') {{---}} алгоритм сортировки, пред­ло­женный Джо­ном фон Ней­ма­ном в 1945 го­ду.&lt;br /&gt;
&lt;br /&gt;
Это устойчивый алгоритм, использующий &amp;lt;tex&amp;gt;O(n)&amp;lt;/tex&amp;gt; дополнительной памяти и &amp;lt;tex&amp;gt;O(n&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;\log n)&amp;lt;/tex&amp;gt; времени.&lt;br /&gt;
&lt;br /&gt;
==Принцип работы==&lt;br /&gt;
[[Файл:Merging_two_arrays.png|270px|right|thumb|Пример работы процедуры слияния.]]&lt;br /&gt;
Алгоритм использует принцип «разделяй и властвуй»: задача разбивается на подзадачи меньшего размера, которые решаются по отдельности, после чего их решения комбинируются для получения решения исходной задачи. Конкретно процедуру сортировки слиянием можно описать следующим образом:&lt;br /&gt;
&lt;br /&gt;
# Если в рассматриваемом массиве один элемент, то он уже отсортирован {{---}} алгоритм завершает работу.&lt;br /&gt;
# Иначе массив разбивается на две части, которые сортируются рекурсивно.&lt;br /&gt;
# После сортировки двух частей массива к ним применяется процедура слияния, которая по двум отсортированным частям получает исходный отсортированный массив.&lt;br /&gt;
&lt;br /&gt;
===Слияние двух массивов===&lt;br /&gt;
У нас есть два массива &amp;lt;tex&amp;gt;A&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;B&amp;lt;/tex&amp;gt; (фактически это будут две части одного массива, но для удобства будем писать, что у нас просто два массива). Нам надо получить массив &amp;lt;tex&amp;gt;C&amp;lt;/tex&amp;gt; размером &amp;lt;tex&amp;gt;|A| + |B|&amp;lt;/tex&amp;gt;. Для этого можно применить процедуру слияния. Эта процедура заключается в том, что мы сравниваем элементы массивов (начиная с начала) и меньший из них записываем в финальный. И затем, в массиве у которого оказался меньший элемент, переходим к следующему элементу и сравниваем теперь его. В конце, если один из массивов закончился, мы просто дописываем в финальный другой массив. После мы наш финальный массив записываем заместо двух исходных и получаем отсортированный участок.&lt;br /&gt;
&lt;br /&gt;
Два отсортированных списка с операцией &amp;lt;tex&amp;gt;merge&amp;lt;/tex&amp;gt; являются моноидом.&lt;br /&gt;
&lt;br /&gt;
Ниже приведён псевдокод процедуры слияния, который сливает две части массива &amp;lt;tex&amp;gt;A&amp;lt;/tex&amp;gt; {{---}} &amp;lt;tex&amp;gt;[left; mid)&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;[mid; right)&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 '''function''' merge(a : '''int[N]'''; left, mid, right : '''int'''):&lt;br /&gt;
     it1 = 0&lt;br /&gt;
     it2 = 0&lt;br /&gt;
     result : '''int[right - left]'''&lt;br /&gt;
   &lt;br /&gt;
     '''while''' left + it1 &amp;lt; mid '''and''' mid + it2 &amp;lt; right&lt;br /&gt;
         '''if''' a[left + it1] &amp;lt; a[mid + it2]&lt;br /&gt;
             result[it1 + it2] = a[left + it1]&lt;br /&gt;
             it1 += 1&lt;br /&gt;
         '''else'''&lt;br /&gt;
             result[it1 + it2] = a[mid + it2]&lt;br /&gt;
             it2 += 1&lt;br /&gt;
   &lt;br /&gt;
     '''while''' left + it1 &amp;lt; mid&lt;br /&gt;
         result[it1 + it2] = a[left + it1]&lt;br /&gt;
         it1 += 1&lt;br /&gt;
   &lt;br /&gt;
     '''while''' mid + it2 &amp;lt; right&lt;br /&gt;
         result[it1 + it2] = a[mid + it2]&lt;br /&gt;
         it2 += 1&lt;br /&gt;
   &lt;br /&gt;
     '''for''' i = 0 '''to''' it1 + it2&lt;br /&gt;
         a[left + i] = result[i]&lt;br /&gt;
&lt;br /&gt;
===Рекурсивный алгоритм===&lt;br /&gt;
Функция сортирует подотрезок массива с индексами в полуинтервале &amp;lt;tex&amp;gt;[left; right)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
 '''function''' mergeSortRecursive(a : '''int[N]'''; left, right : '''int'''):&lt;br /&gt;
     '''if''' left + 1 &amp;gt;= right&lt;br /&gt;
         '''return'''&lt;br /&gt;
     mid = (left + right) / 2&lt;br /&gt;
     mergeSortRecursive(a, left, mid)&lt;br /&gt;
     mergeSortRecursive(a, mid, right)&lt;br /&gt;
     merge(a, left, mid, right)&lt;br /&gt;
&lt;br /&gt;
[[Файл:Merge sort1.png|300px|Пример работы рекурсивного алгоритма сортировки слиянием]]&lt;br /&gt;
&lt;br /&gt;
===Итеративный алгоритм===&lt;br /&gt;
Функция сортирует подотрезок массива с индексами в полуинтервале &amp;lt;tex&amp;gt;[left; right)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
 '''function''' mergeSortIterative(a : '''int[N]'''; left, right : '''int'''):&lt;br /&gt;
     '''for''' i = 1 '''to''' N, i *= 2&lt;br /&gt;
         '''for''' j = left '''to''' right - i, j += 2 * i&lt;br /&gt;
             merge(a, j, j + i, min(j + 2 * i, right))&lt;br /&gt;
 &lt;br /&gt;
==Время работы==&lt;br /&gt;
Чтобы оценить время работы этого алгоритма, составим рекуррентное соотношение. Пускай &amp;lt;tex&amp;gt;T(n)&amp;lt;/tex&amp;gt; {{---}} время сортировки массива длины &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt;, тогда для сортировки слиянием справедливо &amp;lt;tex&amp;gt;T(n)=2T(n/2)+O(n)&amp;lt;/tex&amp;gt; &amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;tex&amp;gt;O(n)&amp;lt;/tex&amp;gt; {{---}} время, необходимое на то, чтобы слить два массива. Распишем это соотношение:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;T(n)=2T(n/2)+O(n)=4T(n/4)+2O(n)=\dots=2^kT(1)+kO(n)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Осталось оценить &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt;. Мы знаем, что &amp;lt;tex&amp;gt;2^k=n&amp;lt;/tex&amp;gt;, а значит &amp;lt;tex&amp;gt;k=\log n&amp;lt;/tex&amp;gt;. Уравнение примет вид &amp;lt;tex&amp;gt;T(n)=nT(1)+ \log n&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;O(n)&amp;lt;/tex&amp;gt;. Так как &amp;lt;tex&amp;gt;T(1)&amp;lt;/tex&amp;gt; {{---}} константа, то &amp;lt;tex&amp;gt;T(n)=O(n)+\log n &amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;O(n)=O(n\log n)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==Источники информации==&lt;br /&gt;
*[http://ru.wikipedia.org/wiki/Mergesort Википедия {{---}} сортировка слиянием]&lt;br /&gt;
&lt;br /&gt;
==См. также==&lt;br /&gt;
* [[Сортировка кучей]]&lt;br /&gt;
* [[Быстрая сортировка]]&lt;br /&gt;
*[[Cортировка слиянием с использованием O(1) дополнительной памяти]]&lt;br /&gt;
*[http://www.sorting-algorithms.com/merge-sort Визуализатор]&lt;br /&gt;
*[http://ru.wikibooks.org/wiki/%D0%9F%D1%80%D0%B8%D0%BC%D0%B5%D1%80%D1%8B_%D1%80%D0%B5%D0%B0%D0%BB%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D0%B8_%D1%81%D0%BE%D1%80%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B8_%D1%81%D0%BB%D0%B8%D1%8F%D0%BD%D0%B8%D0%B5%D0%BC Викиучебник {{---}} Примеры реализации на различных языках программирования]&lt;br /&gt;
&lt;br /&gt;
[[Категория: Дискретная математика и алгоритмы]]&lt;br /&gt;
[[Категория: Сортировка]]&lt;br /&gt;
[[Категория: Сортировки на сравнениях]]&lt;/div&gt;</summary>
		<author><name>Ильнар</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%A1%D0%BE%D1%80%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B0_%D1%81%D0%BB%D0%B8%D1%8F%D0%BD%D0%B8%D0%B5%D0%BC&amp;diff=46138</id>
		<title>Сортировка слиянием</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%A1%D0%BE%D1%80%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B0_%D1%81%D0%BB%D0%B8%D1%8F%D0%BD%D0%B8%D0%B5%D0%BC&amp;diff=46138"/>
				<updated>2015-05-09T09:56:01Z</updated>
		
		<summary type="html">&lt;p&gt;Ильнар: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''Сортировка слиянием''' (англ. ''Merge sort'') {{---}} алгоритм сортировки, пред­ло­женный Джо­ном фон Ней­ма­ном в 1945 го­ду.&lt;br /&gt;
&lt;br /&gt;
Это устойчивый алгоритм, использующий &amp;lt;tex&amp;gt;O(n)&amp;lt;/tex&amp;gt; дополнительной памяти и &amp;lt;tex&amp;gt;O(n&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;\log n)&amp;lt;/tex&amp;gt; времени.&lt;br /&gt;
&lt;br /&gt;
==Принцип работы==&lt;br /&gt;
[[Файл:Merging_two_arrays.png|270px|right|thumb|Пример работы процедуры слияния.]]&lt;br /&gt;
Алгоритм использует принцип «разделяй и властвуй»: задача разбивается на подзадачи меньшего размера, которые решаются по отдельности, после чего их решения комбинируются для получения решения исходной задачи. Конкретно процедуру сортировки слиянием можно описать следующим образом:&lt;br /&gt;
&lt;br /&gt;
# Если в рассматриваемом массиве один элемент, то он уже отсортирован {{---}} алгоритм завершает работу.&lt;br /&gt;
# Иначе массив разбивается на две части, которые сортируются рекурсивно.&lt;br /&gt;
# После сортировки двух частей массива к ним применяется процедура слияния, которая по двум отсортированным частям получает исходный отсортированный массив.&lt;br /&gt;
&lt;br /&gt;
===Слияние двух массивов===&lt;br /&gt;
У нас есть два массива &amp;lt;tex&amp;gt;A&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;B&amp;lt;/tex&amp;gt; (фактически это будут две части одного массива, но для удобства будем писать, что у нас просто два массива). Нам надо получить массив &amp;lt;tex&amp;gt;C&amp;lt;/tex&amp;gt; размером &amp;lt;tex&amp;gt;|A| + |B|&amp;lt;/tex&amp;gt;. Для этого можно применить процедуру слияния. Эта процедура заключается в том, что мы сравниваем элементы массивов (начиная с начала) и меньший из них записываем в финальный. И затем, в массиве у которого оказался меньший элемент, переходим к следующему элементу и сравниваем теперь его. В конце, если один из массивов закончился, мы просто дописываем в финальный другой массив. После мы наш финальный массив записываем заместо двух исходных и получаем отсортированный участок.&lt;br /&gt;
&lt;br /&gt;
Ниже приведён псевдокод процедуры слияния, который сливает две части массива &amp;lt;tex&amp;gt;A&amp;lt;/tex&amp;gt; {{---}} &amp;lt;tex&amp;gt;[left; mid)&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;[mid; right)&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 merge(a : '''int[N]'''; left, mid, right : '''int'''):&lt;br /&gt;
     it1 = 0&lt;br /&gt;
     it2 = 0&lt;br /&gt;
     result : '''int[right - left]'''&lt;br /&gt;
   &lt;br /&gt;
     '''while''' left + it1 &amp;lt; mid '''and''' mid + it2 &amp;lt; right&lt;br /&gt;
         '''if''' a[left + it1] &amp;lt; a[mid + it2]&lt;br /&gt;
             result[it1 + it2] = a[left + it1]&lt;br /&gt;
             it1 += 1&lt;br /&gt;
         '''else'''&lt;br /&gt;
             result[it1 + it2] = a[mid + it2]&lt;br /&gt;
             it2 += 1&lt;br /&gt;
   &lt;br /&gt;
     '''while''' left + it1 &amp;lt; mid&lt;br /&gt;
         result[it1 + it2] = a[left + it1]&lt;br /&gt;
         it1 += 1&lt;br /&gt;
   &lt;br /&gt;
     '''while''' mid + it2 &amp;lt; right&lt;br /&gt;
         result[it1 + it2] = a[mid + it2]&lt;br /&gt;
         it2 += 1&lt;br /&gt;
   &lt;br /&gt;
     '''for''' i = 0 '''to''' it1 + it2&lt;br /&gt;
         a[left + i] = result[i]&lt;br /&gt;
&lt;br /&gt;
===Рекурсивный алгоритм===&lt;br /&gt;
Функция сортирует подотрезок массива с индексами в полуинтервале &amp;lt;tex&amp;gt;[left; right)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
[[Файл:Merge sort1.png|300px|thumb|Пример работы рекурсивного алгоритма сортировки слиянием]]&lt;br /&gt;
&lt;br /&gt;
 mergeSortRecursive(a : '''int[N]'''; left, right : '''int'''):&lt;br /&gt;
     '''if''' left + 1 &amp;gt;= right&lt;br /&gt;
         '''return'''&lt;br /&gt;
     mid = (left + right) / 2&lt;br /&gt;
     mergeSortRecursive(a, left, mid)&lt;br /&gt;
     mergeSortRecursive(a, mid, right)&lt;br /&gt;
     merge(a, left, mid, right)&lt;br /&gt;
&lt;br /&gt;
===Итеративный алгоритм===&lt;br /&gt;
Функция сортирует подотрезок массива с индексами в полуинтервале &amp;lt;tex&amp;gt;[left; right)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
 mergeSortIterative(a : '''int[N]'''; left, right : '''int'''):&lt;br /&gt;
     '''for''' i = 1 '''to''' N, i *= 2&lt;br /&gt;
         '''for''' j = left '''to''' right - i, j += 2 * i&lt;br /&gt;
             merge(a, j, j + i, min(j + 2 * i, right))&lt;br /&gt;
 &lt;br /&gt;
==Время работы==&lt;br /&gt;
Чтобы оценить время работы этого алгоритма, составим рекуррентное соотношение. Пускай &amp;lt;tex&amp;gt;T(n)&amp;lt;/tex&amp;gt; {{---}} время сортировки массива длины &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt;, тогда для сортировки слиянием справедливо &amp;lt;tex&amp;gt;T(n)=2T(n/2)+O(n)&amp;lt;/tex&amp;gt; &amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;tex&amp;gt;O(n)&amp;lt;/tex&amp;gt; {{---}} время, необходимое на то, чтобы слить два массива. Распишем это соотношение:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;T(n)=2T(n/2)+O(n)=4T(n/4)+2O(n)=\dots=2^kT(1)+kO(n)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Осталось оценить &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt;. Мы знаем, что &amp;lt;tex&amp;gt;2^k=n&amp;lt;/tex&amp;gt;, а значит &amp;lt;tex&amp;gt;k=\log n&amp;lt;/tex&amp;gt;. Уравнение примет вид &amp;lt;tex&amp;gt;T(n)=nT(1)+ \log n&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;O(n)&amp;lt;/tex&amp;gt;. Так как &amp;lt;tex&amp;gt;T(1)&amp;lt;/tex&amp;gt; {{---}} константа, то &amp;lt;tex&amp;gt;T(n)=O(n)+\log n &amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;O(n)=O(n\log n)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==Источники информации==&lt;br /&gt;
*[http://ru.wikipedia.org/wiki/Mergesort Википедия {{---}} сортировка слиянием]&lt;br /&gt;
&lt;br /&gt;
==См. также==&lt;br /&gt;
* [[Сортировка кучей]]&lt;br /&gt;
* [[Быстрая сортировка]]&lt;br /&gt;
*[[Cортировка слиянием с использованием O(1) дополнительной памяти]]&lt;br /&gt;
*[http://www.sorting-algorithms.com/merge-sort Визуализатор]&lt;br /&gt;
*[http://ru.wikibooks.org/wiki/%D0%9F%D1%80%D0%B8%D0%BC%D0%B5%D1%80%D1%8B_%D1%80%D0%B5%D0%B0%D0%BB%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D0%B8_%D1%81%D0%BE%D1%80%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B8_%D1%81%D0%BB%D0%B8%D1%8F%D0%BD%D0%B8%D0%B5%D0%BC Викиучебник {{---}} Примеры реализации на различных языках программирования]&lt;br /&gt;
&lt;br /&gt;
[[Категория: Дискретная математика и алгоритмы]]&lt;br /&gt;
[[Категория: Сортировка]]&lt;br /&gt;
[[Категория: Сортировки на сравнениях]]&lt;/div&gt;</summary>
		<author><name>Ильнар</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%A1%D0%BE%D1%80%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B0_%D1%81%D0%BB%D0%B8%D1%8F%D0%BD%D0%B8%D0%B5%D0%BC&amp;diff=46137</id>
		<title>Сортировка слиянием</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%A1%D0%BE%D1%80%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B0_%D1%81%D0%BB%D0%B8%D1%8F%D0%BD%D0%B8%D0%B5%D0%BC&amp;diff=46137"/>
				<updated>2015-05-09T09:54:50Z</updated>
		
		<summary type="html">&lt;p&gt;Ильнар: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''Сортировка слиянием''' (англ. ''Merge sort'') {{---}} алгоритм сортировки, пред­ло­женный Джо­ном фон Ней­ма­ном в 1945 го­ду.&lt;br /&gt;
&lt;br /&gt;
Это устойчивый алгоритм, использующий &amp;lt;tex&amp;gt;O(n)&amp;lt;/tex&amp;gt; дополнительной памяти и &amp;lt;tex&amp;gt;O(n&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;\log n)&amp;lt;/tex&amp;gt; времени.&lt;br /&gt;
&lt;br /&gt;
==Принцип работы==&lt;br /&gt;
[[Файл:Merging_two_arrays.png|270px|right|thumb|Пример работы процедуры слияния.]]&lt;br /&gt;
Алгоритм использует принцип «разделяй и властвуй»: задача разбивается на подзадачи меньшего размера, которые решаются по отдельности, после чего их решения комбинируются для получения решения исходной задачи. Конкретно процедуру сортировки слиянием можно описать следующим образом:&lt;br /&gt;
&lt;br /&gt;
# Если в рассматриваемом массиве один элемент, то он уже отсортирован {{---}} алгоритм завершает работу.&lt;br /&gt;
# Иначе массив разбивается на две части, которые сортируются рекурсивно.&lt;br /&gt;
# После сортировки двух частей массива к ним применяется процедура слияния, которая по двум отсортированным частям получает исходный отсортированный массив.&lt;br /&gt;
&lt;br /&gt;
===Слияние двух массивов===&lt;br /&gt;
У нас есть два массива &amp;lt;tex&amp;gt;A&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;B&amp;lt;/tex&amp;gt; (фактически это будут две части одного массива, но для удобства будем писать, что у нас просто два массива). Нам надо получить массив &amp;lt;tex&amp;gt;C&amp;lt;/tex&amp;gt; размером &amp;lt;tex&amp;gt;|A| + |B|&amp;lt;/tex&amp;gt;. Для этого можно применить процедуру слияния. Эта процедура заключается в том, что мы сравниваем элементы массивов (начиная с начала) и меньший из них записываем в финальный. И затем, в массиве у которого оказался меньший элемент, переходим к следующему элементу и сравниваем теперь его. В конце, если один из массивов закончился, мы просто дописываем в финальный другой массив. После мы наш финальный массив записываем заместо двух исходных и получаем отсортированный участок.&lt;br /&gt;
&lt;br /&gt;
Ниже приведён псевдокод процедуры слияния, который сливает две части массива &amp;lt;tex&amp;gt;A&amp;lt;/tex&amp;gt; {{---}} &amp;lt;tex&amp;gt;[left; mid)&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;[mid; right)&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 merge(a : '''int[N]'''; left, mid, right : '''int'''):&lt;br /&gt;
     it1 = 0&lt;br /&gt;
     it2 = 0&lt;br /&gt;
     result : '''int[right - left]'''&lt;br /&gt;
   &lt;br /&gt;
     '''while''' left + it1 &amp;lt; mid '''and''' mid + it2 &amp;lt; right&lt;br /&gt;
         '''if''' a[left + it1] &amp;lt; a[mid + it2]&lt;br /&gt;
             result[it1 + it2] = a[left + it1]&lt;br /&gt;
             it1 += 1&lt;br /&gt;
         '''else'''&lt;br /&gt;
             result[it1 + it2] = a[mid + it2]&lt;br /&gt;
             it2 += 1&lt;br /&gt;
   &lt;br /&gt;
     '''while''' left + it1 &amp;lt; mid&lt;br /&gt;
         result[it1 + it2] = a[left + it1]&lt;br /&gt;
         it1 += 1&lt;br /&gt;
   &lt;br /&gt;
     '''while''' mid + it2 &amp;lt; right&lt;br /&gt;
         result[it1 + it2] = a[mid + it2]&lt;br /&gt;
         it2 += 1&lt;br /&gt;
   &lt;br /&gt;
     '''for''' i = 0 '''to''' it1 + it2&lt;br /&gt;
         a[left + i] = result[i]&lt;br /&gt;
&lt;br /&gt;
===Рекурсивный алгоритм===&lt;br /&gt;
Функция сортирует подотрезок массива с индексами в полуинтервале &amp;lt;tex&amp;gt;[left; right)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
[[Файл:Merge sort1.png|300px|thumb|Пример работы рекурсивного алгоритма сортировки слиянием]]&lt;br /&gt;
&lt;br /&gt;
 mergeSortRecursive(a : '''int[N]'''; left, right : '''int'''):&lt;br /&gt;
     '''if''' left + 1 &amp;gt;= right&lt;br /&gt;
         '''return'''&lt;br /&gt;
     mid = (left + right) / 2&lt;br /&gt;
     mergeSortRecursive(a, left, mid)&lt;br /&gt;
     mergeSortRecursive(a, mid, right)&lt;br /&gt;
     merge(a, left, mid, right)&lt;br /&gt;
&lt;br /&gt;
===Итеративный алгоритм===&lt;br /&gt;
Функция сортирует подотрезок массива с индексами в полуинтервале &amp;lt;tex&amp;gt;[left; right)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
 mergeSortIterative(a : '''int[N]'''; left, right : '''int'''):&lt;br /&gt;
     '''for''' i = 1 '''to''' N, i *= 2&lt;br /&gt;
         '''for''' j = left '''to''' right - i, j += 2 * i&lt;br /&gt;
             Merge(a, j, j + i, min(j + 2 * i, right))&lt;br /&gt;
 &lt;br /&gt;
==Время работы==&lt;br /&gt;
Чтобы оценить время работы этого алгоритма, составим рекуррентное соотношение. Пускай &amp;lt;tex&amp;gt;T(n)&amp;lt;/tex&amp;gt; {{---}} время сортировки массива длины &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt;, тогда для сортировки слиянием справедливо &amp;lt;tex&amp;gt;T(n)=2T(n/2)+O(n)&amp;lt;/tex&amp;gt; &amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;tex&amp;gt;O(n)&amp;lt;/tex&amp;gt; {{---}} время, необходимое на то, чтобы слить два массива. Распишем это соотношение:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;T(n)=2T(n/2)+O(n)=4T(n/4)+2O(n)=\dots=2^kT(1)+kO(n)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Осталось оценить &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt;. Мы знаем, что &amp;lt;tex&amp;gt;2^k=n&amp;lt;/tex&amp;gt;, а значит &amp;lt;tex&amp;gt;k=\log n&amp;lt;/tex&amp;gt;. Уравнение примет вид &amp;lt;tex&amp;gt;T(n)=nT(1)+ \log n&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;O(n)&amp;lt;/tex&amp;gt;. Так как &amp;lt;tex&amp;gt;T(1)&amp;lt;/tex&amp;gt; {{---}} константа, то &amp;lt;tex&amp;gt;T(n)=O(n)+\log n &amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;O(n)=O(n\log n)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==Источники информации==&lt;br /&gt;
*[http://ru.wikipedia.org/wiki/Mergesort Википедия {{---}} сортировка слиянием]&lt;br /&gt;
&lt;br /&gt;
==См. также==&lt;br /&gt;
* [[Сортировка кучей]]&lt;br /&gt;
* [[Быстрая сортировка]]&lt;br /&gt;
*[[Cортировка слиянием с использованием O(1) дополнительной памяти]]&lt;br /&gt;
*[http://www.sorting-algorithms.com/merge-sort Визуализатор]&lt;br /&gt;
*[http://ru.wikibooks.org/wiki/%D0%9F%D1%80%D0%B8%D0%BC%D0%B5%D1%80%D1%8B_%D1%80%D0%B5%D0%B0%D0%BB%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D0%B8_%D1%81%D0%BE%D1%80%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B8_%D1%81%D0%BB%D0%B8%D1%8F%D0%BD%D0%B8%D0%B5%D0%BC Викиучебник {{---}} Примеры реализации на различных языках программирования]&lt;br /&gt;
&lt;br /&gt;
[[Категория: Дискретная математика и алгоритмы]]&lt;br /&gt;
[[Категория: Сортировка]]&lt;br /&gt;
[[Категория: Сортировки на сравнениях]]&lt;/div&gt;</summary>
		<author><name>Ильнар</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%A1%D0%BE%D1%80%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B0_%D1%81%D0%BB%D0%B8%D1%8F%D0%BD%D0%B8%D0%B5%D0%BC&amp;diff=46132</id>
		<title>Сортировка слиянием</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%A1%D0%BE%D1%80%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B0_%D1%81%D0%BB%D0%B8%D1%8F%D0%BD%D0%B8%D0%B5%D0%BC&amp;diff=46132"/>
				<updated>2015-05-09T08:27:43Z</updated>
		
		<summary type="html">&lt;p&gt;Ильнар: /* Время работы */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Описание==&lt;br /&gt;
'''Сортировка слиянием''' — алгоритм сортировки. Он был пред­ло­жен Джо­ном фон Ней­ма­ном в 1945 го­ду.&lt;br /&gt;
&lt;br /&gt;
Это устойчивый ал­го­ритм, использующий &amp;lt;tex&amp;gt;O(n)&amp;lt;/tex&amp;gt; дополнительной памяти и &amp;lt;tex&amp;gt;O(n&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;\log n)&amp;lt;/tex&amp;gt; времени.&lt;br /&gt;
&lt;br /&gt;
==Принцип работы==&lt;br /&gt;
[[Файл:Merging_two_arrays.png|270px|right|thumb|Пример работы процедуры слияния.]]&lt;br /&gt;
Алгоритм использует прицип «разделяй и властвуй»: задача разбивается на подзадачи меньшего размера, которые решаются по отдельности, после чего их решения комбинируются для получения решения исходной задачи. Конкретно процедуру сортировки слиянием можно описать следующим образом:&lt;br /&gt;
&lt;br /&gt;
# Если в рассматриваемом массиве один элемент, то он уже отсортирован — алгоритм завершает работу.&lt;br /&gt;
# Иначе массив разбивается на две части, которые сортируются рекурсивно.&lt;br /&gt;
# После сортировки двух частей массива к ним применяется процедура слияния, которая по двум отсортированным частям получает исходный отсортированный массив.&lt;br /&gt;
&lt;br /&gt;
===Слияние двух массивов===&lt;br /&gt;
У нас есть два массива &amp;lt;tex&amp;gt;A&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;B&amp;lt;/tex&amp;gt; (фактически это будут две части одного массива, но для удобства будем писать, что у нас просто два массива). Нам надо получить массив &amp;lt;tex&amp;gt;C&amp;lt;/tex&amp;gt; размером &amp;lt;tex&amp;gt;|A| + |B|&amp;lt;/tex&amp;gt;. Для этого можно применить процедуру слияния. Эта процедура заключается в том, что мы сравниваем элементы массивов (начиная с начала) и меньший из них записываем в финальный. И затем, в массиве у которого оказался меньший элемент, переходим к следующему элементу и сравниваем теперь его. В конце, если один из массивов закончился, мы просто дописываем в финальный другой массив. После мы наш финальный массив записываем заместо двух исходных и получаем отсортированный участок.&lt;br /&gt;
&lt;br /&gt;
Ниже приведён псевдокод процедуры слияния, который сливает две части массива A — &amp;lt;tex&amp;gt;[left; mid)&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;[mid; right)&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 Merge(A : '''int[1..N]'''; left, mid, right : '''int'''):&lt;br /&gt;
     it1 = 0&lt;br /&gt;
     it2 = 0&lt;br /&gt;
     result : '''int[right - left]'''&lt;br /&gt;
   &lt;br /&gt;
     '''while''' left + it1 &amp;lt; mid '''and''' mid + it2 &amp;lt; right&lt;br /&gt;
         '''if''' A[left + it1] &amp;lt; A[mid + it2]&lt;br /&gt;
             result[it1 + it2] = A[left + it1]&lt;br /&gt;
             it1 += 1&lt;br /&gt;
         '''else'''&lt;br /&gt;
             result[it1 + it2] = A[mid + it2]&lt;br /&gt;
             it2 += 1&lt;br /&gt;
   &lt;br /&gt;
     '''while''' left + it1 &amp;lt; mid&lt;br /&gt;
         result[it1 + it2] = A[left + it1]&lt;br /&gt;
         it1 += 1&lt;br /&gt;
   &lt;br /&gt;
     '''while''' mid + it2 &amp;lt; right&lt;br /&gt;
         result[it1 + it2] = A[mid + it2]&lt;br /&gt;
         it2 += 1&lt;br /&gt;
   &lt;br /&gt;
     '''for''' i = 0 '''to''' it1 + it2&lt;br /&gt;
         A[left + i] = result[i]&lt;br /&gt;
&lt;br /&gt;
===Рекурсивный алгоритм===&lt;br /&gt;
Функция сортирует подотрезок массива с индексами в полуинтервале &amp;lt;tex&amp;gt;[left; right)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
[[Файл:Merge sort1.png|300px|thumb|Пример работы рекурсивного алгоритма сортировки слиянием]]&lt;br /&gt;
&lt;br /&gt;
 MergeSort(A : '''int[1..N]'''; left, right : '''int'''):&lt;br /&gt;
     '''if''' left + 1 &amp;gt;= right&lt;br /&gt;
         return&lt;br /&gt;
     mid = (left + right) / 2&lt;br /&gt;
     MergeSort(A, left, mid)&lt;br /&gt;
     MergeSort(A, mid, right)&lt;br /&gt;
     Merge(A, left, mid, right)&lt;br /&gt;
&lt;br /&gt;
===Итеративный алгоритм===&lt;br /&gt;
Функция сортирует подотрезок массива с индексами в полуинтервале &amp;lt;tex&amp;gt;[left; right)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
 MergeSortIterative(A : '''int[1..N]'''; left, right : '''int'''):&lt;br /&gt;
     '''for''' i = 1 '''to''' N, i *= 2&lt;br /&gt;
         '''for''' j = left '''to''' right - i, j += 2 * i&lt;br /&gt;
             Merge(A, j, j + i, min(j + 2 * i, right))&lt;br /&gt;
 &lt;br /&gt;
==Время работы==&lt;br /&gt;
Чтобы оценить время работы этого алгоритма, составим рекуррентное соотношение. Пускай &amp;lt;tex&amp;gt;T(n)&amp;lt;/tex&amp;gt; — время сортировки массива длины &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt;, тогда для сортировки слиянием справедливо &amp;lt;tex&amp;gt;T(n)=2T(n/2)+O(n)&amp;lt;/tex&amp;gt; &amp;lt;br&amp;gt;&lt;br /&gt;
(&amp;lt;tex&amp;gt;O(n)&amp;lt;/tex&amp;gt; — это время, необходимое на то, чтобы слить два массива). Распишем это соотношение:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;T(n)=2T(n/2)+O(n)=4T(n/4)+2O(n)=\dots=2^kT(1)+kO(n)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Осталось оценить &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt;. Мы знаем, что &amp;lt;tex&amp;gt;2^k=n&amp;lt;/tex&amp;gt;, а значит &amp;lt;tex&amp;gt;k=\log n&amp;lt;/tex&amp;gt;. Уравнение примет вид &amp;lt;tex&amp;gt;T(n)=nT(1)+ \log n&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;O(n)&amp;lt;/tex&amp;gt;. Так как &amp;lt;tex&amp;gt;T(1)&amp;lt;/tex&amp;gt; — константа, то &amp;lt;tex&amp;gt;T(n)=O(n)+\log n &amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;O(n)=O(n\log n)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==Источники информации==&lt;br /&gt;
*[http://ru.wikipedia.org/wiki/Mergesort Википедия {{---}} сортировка слиянием]&lt;br /&gt;
&lt;br /&gt;
==Ссылки==&lt;br /&gt;
*[http://www.sorting-algorithms.com/merge-sort Визуализатор]&lt;br /&gt;
*[http://ru.wikibooks.org/wiki/%D0%9F%D1%80%D0%B8%D0%BC%D0%B5%D1%80%D1%8B_%D1%80%D0%B5%D0%B0%D0%BB%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D0%B8_%D1%81%D0%BE%D1%80%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B8_%D1%81%D0%BB%D0%B8%D1%8F%D0%BD%D0%B8%D0%B5%D0%BC Викиучебник {{---}} Примеры реализации на различных языках программирования]&lt;br /&gt;
&lt;br /&gt;
==См. также==&lt;br /&gt;
* [[Сортировка кучей]]&lt;br /&gt;
* [[Быстрая сортировка]]&lt;br /&gt;
*[[Сортировка слиянием с использованием O(1) дополнительной памяти]]&lt;br /&gt;
&lt;br /&gt;
[[Категория: Дискретная математика и алгоритмы]]&lt;br /&gt;
[[Категория: Сортировка]]&lt;br /&gt;
[[Категория: Сортировки на сравнениях]]&lt;/div&gt;</summary>
		<author><name>Ильнар</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%A1%D0%BE%D1%80%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B0_%D1%81%D0%BB%D0%B8%D1%8F%D0%BD%D0%B8%D0%B5%D0%BC&amp;diff=46131</id>
		<title>Сортировка слиянием</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%A1%D0%BE%D1%80%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B0_%D1%81%D0%BB%D0%B8%D1%8F%D0%BD%D0%B8%D0%B5%D0%BC&amp;diff=46131"/>
				<updated>2015-05-09T08:21:49Z</updated>
		
		<summary type="html">&lt;p&gt;Ильнар: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Описание==&lt;br /&gt;
'''Сортировка слиянием''' — алгоритм сортировки. Он был пред­ло­жен Джо­ном фон Ней­ма­ном в 1945 го­ду.&lt;br /&gt;
&lt;br /&gt;
Это устойчивый ал­го­ритм, использующий &amp;lt;tex&amp;gt;O(n)&amp;lt;/tex&amp;gt; дополнительной памяти и &amp;lt;tex&amp;gt;O(n&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;\log n)&amp;lt;/tex&amp;gt; времени.&lt;br /&gt;
&lt;br /&gt;
==Принцип работы==&lt;br /&gt;
[[Файл:Merging_two_arrays.png|270px|right|thumb|Пример работы процедуры слияния.]]&lt;br /&gt;
Алгоритм использует прицип «разделяй и властвуй»: задача разбивается на подзадачи меньшего размера, которые решаются по отдельности, после чего их решения комбинируются для получения решения исходной задачи. Конкретно процедуру сортировки слиянием можно описать следующим образом:&lt;br /&gt;
&lt;br /&gt;
# Если в рассматриваемом массиве один элемент, то он уже отсортирован — алгоритм завершает работу.&lt;br /&gt;
# Иначе массив разбивается на две части, которые сортируются рекурсивно.&lt;br /&gt;
# После сортировки двух частей массива к ним применяется процедура слияния, которая по двум отсортированным частям получает исходный отсортированный массив.&lt;br /&gt;
&lt;br /&gt;
===Слияние двух массивов===&lt;br /&gt;
У нас есть два массива &amp;lt;tex&amp;gt;A&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;B&amp;lt;/tex&amp;gt; (фактически это будут две части одного массива, но для удобства будем писать, что у нас просто два массива). Нам надо получить массив &amp;lt;tex&amp;gt;C&amp;lt;/tex&amp;gt; размером &amp;lt;tex&amp;gt;|A| + |B|&amp;lt;/tex&amp;gt;. Для этого можно применить процедуру слияния. Эта процедура заключается в том, что мы сравниваем элементы массивов (начиная с начала) и меньший из них записываем в финальный. И затем, в массиве у которого оказался меньший элемент, переходим к следующему элементу и сравниваем теперь его. В конце, если один из массивов закончился, мы просто дописываем в финальный другой массив. После мы наш финальный массив записываем заместо двух исходных и получаем отсортированный участок.&lt;br /&gt;
&lt;br /&gt;
Ниже приведён псевдокод процедуры слияния, который сливает две части массива A — &amp;lt;tex&amp;gt;[left; mid)&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;[mid; right)&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 Merge(A : '''int[1..N]'''; left, mid, right : '''int'''):&lt;br /&gt;
     it1 = 0&lt;br /&gt;
     it2 = 0&lt;br /&gt;
     result : '''int[right - left]'''&lt;br /&gt;
   &lt;br /&gt;
     '''while''' left + it1 &amp;lt; mid '''and''' mid + it2 &amp;lt; right&lt;br /&gt;
         '''if''' A[left + it1] &amp;lt; A[mid + it2]&lt;br /&gt;
             result[it1 + it2] = A[left + it1]&lt;br /&gt;
             it1 += 1&lt;br /&gt;
         '''else'''&lt;br /&gt;
             result[it1 + it2] = A[mid + it2]&lt;br /&gt;
             it2 += 1&lt;br /&gt;
   &lt;br /&gt;
     '''while''' left + it1 &amp;lt; mid&lt;br /&gt;
         result[it1 + it2] = A[left + it1]&lt;br /&gt;
         it1 += 1&lt;br /&gt;
   &lt;br /&gt;
     '''while''' mid + it2 &amp;lt; right&lt;br /&gt;
         result[it1 + it2] = A[mid + it2]&lt;br /&gt;
         it2 += 1&lt;br /&gt;
   &lt;br /&gt;
     '''for''' i = 0 '''to''' it1 + it2&lt;br /&gt;
         A[left + i] = result[i]&lt;br /&gt;
&lt;br /&gt;
===Рекурсивный алгоритм===&lt;br /&gt;
Функция сортирует подотрезок массива с индексами в полуинтервале &amp;lt;tex&amp;gt;[left; right)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
[[Файл:Merge sort1.png|300px|thumb|Пример работы рекурсивного алгоритма сортировки слиянием]]&lt;br /&gt;
&lt;br /&gt;
 MergeSort(A : '''int[1..N]'''; left, right : '''int'''):&lt;br /&gt;
     '''if''' left + 1 &amp;gt;= right&lt;br /&gt;
         return&lt;br /&gt;
     mid = (left + right) / 2&lt;br /&gt;
     MergeSort(A, left, mid)&lt;br /&gt;
     MergeSort(A, mid, right)&lt;br /&gt;
     Merge(A, left, mid, right)&lt;br /&gt;
&lt;br /&gt;
===Итеративный алгоритм===&lt;br /&gt;
Функция сортирует подотрезок массива с индексами в полуинтервале &amp;lt;tex&amp;gt;[left; right)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
 MergeSortIterative(A : '''int[1..N]'''; left, right : '''int'''):&lt;br /&gt;
     '''for''' i = 1 '''to''' N, i *= 2&lt;br /&gt;
         '''for''' j = left '''to''' right - i, j += 2 * i&lt;br /&gt;
             Merge(A, j, j + i, min(j + 2 * i, right))&lt;br /&gt;
 &lt;br /&gt;
==Время работы==&lt;br /&gt;
Чтобы оценить время работы этого алгоритма, составим рекуррентное соотношение. Пускай &amp;lt;tex&amp;gt;T(n)&amp;lt;/tex&amp;gt; — время сортировки массива длины n, тогда для сортировки слиянием справедливо &amp;lt;tex&amp;gt;T(n)=2T(n/2)+O(n)&amp;lt;/tex&amp;gt; &amp;lt;br&amp;gt;&lt;br /&gt;
(&amp;lt;tex&amp;gt;O(n)&amp;lt;/tex&amp;gt; — это время, необходимое на то, чтобы слить два массива). Распишем это соотношение:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;T(n)=2T(n/2)+O(n)=4T(n/4)+2O(n)=\dots=2^kT(1)+kO(n)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Осталось оценить &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt;. Мы знаем, что &amp;lt;tex&amp;gt;2^k=n&amp;lt;/tex&amp;gt;, а значит &amp;lt;tex&amp;gt;k=\log n&amp;lt;/tex&amp;gt;. Уравнение примет вид &amp;lt;tex&amp;gt;T(n)=nT(1)+ \log n&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;O(n)&amp;lt;/tex&amp;gt;. Так как &amp;lt;tex&amp;gt;T(1)&amp;lt;/tex&amp;gt; — константа, то &amp;lt;tex&amp;gt;T(n)=O(n)+\log n &amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;O(n)=O(n\log n)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==Источники информации==&lt;br /&gt;
*[http://ru.wikipedia.org/wiki/Mergesort Википедия {{---}} сортировка слиянием]&lt;br /&gt;
&lt;br /&gt;
==Ссылки==&lt;br /&gt;
*[http://www.sorting-algorithms.com/merge-sort Визуализатор]&lt;br /&gt;
*[http://ru.wikibooks.org/wiki/%D0%9F%D1%80%D0%B8%D0%BC%D0%B5%D1%80%D1%8B_%D1%80%D0%B5%D0%B0%D0%BB%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D0%B8_%D1%81%D0%BE%D1%80%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B8_%D1%81%D0%BB%D0%B8%D1%8F%D0%BD%D0%B8%D0%B5%D0%BC Викиучебник {{---}} Примеры реализации на различных языках программирования]&lt;br /&gt;
&lt;br /&gt;
==См. также==&lt;br /&gt;
* [[Сортировка кучей]]&lt;br /&gt;
* [[Быстрая сортировка]]&lt;br /&gt;
*[[Сортировка слиянием с использованием O(1) дополнительной памяти]]&lt;br /&gt;
&lt;br /&gt;
[[Категория: Дискретная математика и алгоритмы]]&lt;br /&gt;
[[Категория: Сортировка]]&lt;br /&gt;
[[Категория: Сортировки на сравнениях]]&lt;/div&gt;</summary>
		<author><name>Ильнар</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%A1%D0%BE%D1%80%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B0_%D1%81%D0%BB%D0%B8%D1%8F%D0%BD%D0%B8%D0%B5%D0%BC&amp;diff=45980</id>
		<title>Сортировка слиянием</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%A1%D0%BE%D1%80%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B0_%D1%81%D0%BB%D0%B8%D1%8F%D0%BD%D0%B8%D0%B5%D0%BC&amp;diff=45980"/>
				<updated>2015-05-03T18:14:40Z</updated>
		
		<summary type="html">&lt;p&gt;Ильнар: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Описание==&lt;br /&gt;
'''Сортировка слиянием''' — алгоритм сортировки. Он был пред­ло­жен Джо­ном фон Ней­ма­ном в 1945 го­ду.&lt;br /&gt;
&lt;br /&gt;
Это устойчивый ал­го­ритм, использующий &amp;lt;tex&amp;gt;O(n)&amp;lt;/tex&amp;gt; дополнительной памяти и &amp;lt;tex&amp;gt;O(n&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;\log n)&amp;lt;/tex&amp;gt; времени.&lt;br /&gt;
&lt;br /&gt;
==Принцип работы==&lt;br /&gt;
[[Файл:Merging_two_arrays.png|270px|right|thumb|Пример работы процедуры слияния.]]&lt;br /&gt;
Алгоритм использует прицип «разделяй и властвуй»: задача разбивается на подзадачи меньшего размера, которые решаются по отдельности, после чего их решения комбинируются для получения решения исходной задачи. Конкретно процедуру сортировки слиянием можно описать следующим образом:&lt;br /&gt;
&lt;br /&gt;
# Если в рассматриваемом массиве один элемент, то он уже отсортирован — алгоритм завершает работу.&lt;br /&gt;
# Иначе массив разбивается на две части, которые сортируются рекурсивно.&lt;br /&gt;
# После сортировки двух частей массива к ним применяется процедура слияния, которая по двум отсортированным частям получает исходный отсортированный массив.&lt;br /&gt;
&lt;br /&gt;
===Слияние двух массивов===&lt;br /&gt;
У нас есть два массива &amp;lt;tex&amp;gt;A&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;B&amp;lt;/tex&amp;gt; (фактически это будут две части одного массива, но для удобства будем писать, что у нас просто два массива). Нам надо получить массив &amp;lt;tex&amp;gt;C&amp;lt;/tex&amp;gt; размером &amp;lt;tex&amp;gt;|A| + |B|&amp;lt;/tex&amp;gt;. Для этого можно применить процедуру слияния. Эта процедура заключается в том, что мы сравниваем элементы массивов (начиная с начала) и меньший из них записываем в финальный. И затем, в массиве у которого оказался меньший элемент, переходим к следующему элементу и сравниваем теперь его. В конце, если один из массивов закончился, мы просто дописываем в финальный другой массив. После мы наш финальный массив записываем заместо двух исходных и получаем отсортированный участок.&lt;br /&gt;
&lt;br /&gt;
Ниже приведён псевдокод процедуры слияния, который сливает две части массива A — &amp;lt;tex&amp;gt;[left; mid)&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;[mid; right)&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 Merge(A : '''int[1..N]'''; left, mid, right : '''int'''):&lt;br /&gt;
     it1 = 0&lt;br /&gt;
     it2 = 0&lt;br /&gt;
     result : '''int[right - left]'''&lt;br /&gt;
   &lt;br /&gt;
     '''while''' left + it1 &amp;lt; mid '''and''' mid + it2 &amp;lt; right&lt;br /&gt;
         '''if''' A[left + it1] &amp;lt; A[mid + it2]&lt;br /&gt;
             result[it1 + it2] = A[left + it1]&lt;br /&gt;
             it1 += 1&lt;br /&gt;
         '''else'''&lt;br /&gt;
             result[it1 + it2] = A[mid + it2]&lt;br /&gt;
             it2 += 1&lt;br /&gt;
   &lt;br /&gt;
     '''while''' left + it1 &amp;lt; mid&lt;br /&gt;
         result[it1 + it2] = A[left + it1]&lt;br /&gt;
         it1 += 1&lt;br /&gt;
   &lt;br /&gt;
     '''while''' mid + it2 &amp;lt; right&lt;br /&gt;
         result[it1 + it2] = A[mid + it2]&lt;br /&gt;
         it2 += 1&lt;br /&gt;
   &lt;br /&gt;
     '''for''' i = 0 '''to''' it1 + it2&lt;br /&gt;
         A[left + i] = result[i]&lt;br /&gt;
&lt;br /&gt;
===Рекурсивный алгоритм===&lt;br /&gt;
Функция сортирует подотрезок массива с индексами в полуинтервале [left; right).&lt;br /&gt;
[[Файл:Merge sort1.png|300px|thumb|Пример работы рекурсивного алгоритма сортировки слиянием]]&lt;br /&gt;
&lt;br /&gt;
 MergeSort(A : '''int[1..N]'''; left, right : '''int'''):&lt;br /&gt;
     '''if''' left + 1 &amp;gt;= right&lt;br /&gt;
         return&lt;br /&gt;
     mid = (left + right) / 2&lt;br /&gt;
     MergeSort(A, left, mid)&lt;br /&gt;
     MergeSort(A, mid, right)&lt;br /&gt;
     Merge(A, left, mid, right)&lt;br /&gt;
&lt;br /&gt;
==Время работы==&lt;br /&gt;
Чтобы оценить время работы этого алгоритма, составим рекуррентное соотношение. Пускай &amp;lt;tex&amp;gt;T(n)&amp;lt;/tex&amp;gt; — время сортировки массива длины n, тогда для сортировки слиянием справедливо &amp;lt;tex&amp;gt;T(n)=2T(n/2)+O(n)&amp;lt;/tex&amp;gt; &amp;lt;br&amp;gt;&lt;br /&gt;
(&amp;lt;tex&amp;gt;O(n)&amp;lt;/tex&amp;gt; — это время, необходимое на то, чтобы слить два массива). Распишем это соотношение:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;T(n)=2T(n/2)+O(n)=4T(n/4)+2O(n)=\dots=2^kT(1)+kO(n)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Осталось оценить &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt;. Мы знаем, что &amp;lt;tex&amp;gt;2^k=n&amp;lt;/tex&amp;gt;, а значит &amp;lt;tex&amp;gt;k=\log n&amp;lt;/tex&amp;gt;. Уравнение примет вид &amp;lt;tex&amp;gt;T(n)=nT(1)+ \log n&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;O(n)&amp;lt;/tex&amp;gt;. Так как &amp;lt;tex&amp;gt;T(1)&amp;lt;/tex&amp;gt; — константа, то &amp;lt;tex&amp;gt;T(n)=O(n)+\log n &amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;O(n)=O(n\log n)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==Источники информации==&lt;br /&gt;
*[http://ru.wikipedia.org/wiki/Mergesort Википедия {{---}} сортировка слиянием]&lt;br /&gt;
&lt;br /&gt;
==Ссылки==&lt;br /&gt;
*[http://www.sorting-algorithms.com/merge-sort Визуализатор]&lt;br /&gt;
*[http://ru.wikibooks.org/wiki/%D0%9F%D1%80%D0%B8%D0%BC%D0%B5%D1%80%D1%8B_%D1%80%D0%B5%D0%B0%D0%BB%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D0%B8_%D1%81%D0%BE%D1%80%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B8_%D1%81%D0%BB%D0%B8%D1%8F%D0%BD%D0%B8%D0%B5%D0%BC Викиучебник {{---}} Примеры реализации на различных языках программирования]&lt;br /&gt;
&lt;br /&gt;
==См. также==&lt;br /&gt;
* [[Сортировка кучей]]&lt;br /&gt;
* [[Быстрая сортировка]]&lt;br /&gt;
*[[Cортировка слиянием с использованием O(1) дополнительной памяти]]&lt;br /&gt;
&lt;br /&gt;
[[Категория: Дискретная математика и алгоритмы]]&lt;br /&gt;
[[Категория: Сортировка]]&lt;br /&gt;
[[Категория: Сортировки на сравнениях]]&lt;/div&gt;</summary>
		<author><name>Ильнар</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:Merging_two_arrays.png&amp;diff=45979</id>
		<title>Файл:Merging two arrays.png</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:Merging_two_arrays.png&amp;diff=45979"/>
				<updated>2015-05-03T17:55:31Z</updated>
		
		<summary type="html">&lt;p&gt;Ильнар: загружена новая версия «Файл:Merging two arrays.png»: Merging two arrays in merge sort&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Merging two arrays in merge sort&lt;/div&gt;</summary>
		<author><name>Ильнар</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:Merging_two_arrays.png&amp;diff=45978</id>
		<title>Файл:Merging two arrays.png</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:Merging_two_arrays.png&amp;diff=45978"/>
				<updated>2015-05-03T17:55:10Z</updated>
		
		<summary type="html">&lt;p&gt;Ильнар: Merging two arrays in merge sort&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Merging two arrays in merge sort&lt;/div&gt;</summary>
		<author><name>Ильнар</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%A1%D0%BE%D1%80%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B0_%D1%81%D0%BB%D0%B8%D1%8F%D0%BD%D0%B8%D0%B5%D0%BC&amp;diff=45976</id>
		<title>Сортировка слиянием</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%A1%D0%BE%D1%80%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B0_%D1%81%D0%BB%D0%B8%D1%8F%D0%BD%D0%B8%D0%B5%D0%BC&amp;diff=45976"/>
				<updated>2015-05-03T16:00:23Z</updated>
		
		<summary type="html">&lt;p&gt;Ильнар: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Описание==&lt;br /&gt;
'''Сортировка слиянием''' — алгоритм сортировки. Он был пред­ло­жен Джо­ном фон Ней­ма­ном в 1945 го­ду.&lt;br /&gt;
&lt;br /&gt;
Это устойчивый ал­го­ритм, использующий &amp;lt;tex&amp;gt;O(n)&amp;lt;/tex&amp;gt; дополнительной памяти и &amp;lt;tex&amp;gt;O(n&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;\log n)&amp;lt;/tex&amp;gt; времени.&lt;br /&gt;
&lt;br /&gt;
==Принцип работы==&lt;br /&gt;
[[Файл:Merge-sort-example.png|right|300px|thumb|Пример работы процедуры слияния.]]&lt;br /&gt;
Алгоритм использует прицип «разделяй и властвуй»: задача разбивается на подзадачи меньшего размера, которые решаются по отдельности, после чего их решения комбинируются для получения решения исходной задачи. Конкретно процедуру сортировки слиянием можно описать следующим образом:&lt;br /&gt;
&lt;br /&gt;
# Если в рассматриваемом массиве один элемент, то он уже отсортирован — алгоритм завершает работу.&lt;br /&gt;
# Иначе массив разбивается на две части, которые сортируются рекурсивно.&lt;br /&gt;
# После сортировки двух частей массива к ним применяется процедура слияния, которая по двум отсортированным частям получает исходный отсортированный массив.&lt;br /&gt;
&lt;br /&gt;
===Слияние двух массивов===&lt;br /&gt;
У нас есть два массива &amp;lt;tex&amp;gt;A&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;B&amp;lt;/tex&amp;gt; (фактически это будут две части одного массива, но для удобства будем писать, что у нас просто два массива). Нам надо получить массив &amp;lt;tex&amp;gt;C&amp;lt;/tex&amp;gt; размером &amp;lt;tex&amp;gt;|A| + |B|&amp;lt;/tex&amp;gt;. Для этого можно применить процедуру слияния. Эта процедура заключается в том, что мы сравниваем элементы массивов (начиная с начала) и меньший из них записываем в финальный. И затем, в массиве у которого оказался меньший элемент, переходим к следующему элементу и сравниваем теперь его. В конце, если один из массивов закончился, мы просто дописываем в финальный другой массив. После мы наш финальный массив записываем заместо двух исходных и получаем отсортированный участок.&lt;br /&gt;
&lt;br /&gt;
Ниже приведён псевдокод процедуры слияния, который сливает две части массива A — &amp;lt;tex&amp;gt;[left; mid)&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;[mid; right)&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 Merge(A : '''int[1..N]'''; left, mid, right : '''int'''):&lt;br /&gt;
     it1 = 0&lt;br /&gt;
     it2 = 0&lt;br /&gt;
     result : '''int[right - left]'''&lt;br /&gt;
   &lt;br /&gt;
     '''while''' left + it1 &amp;lt; mid '''and''' mid + it2 &amp;lt; right&lt;br /&gt;
         '''if''' A[left + it1] &amp;lt; A[mid + it2]&lt;br /&gt;
             result[it1 + it2] = A[left + it1]&lt;br /&gt;
             it1 += 1&lt;br /&gt;
         '''else'''&lt;br /&gt;
             result[it1 + it2] = A[mid + it2]&lt;br /&gt;
             it2 += 1&lt;br /&gt;
   &lt;br /&gt;
     '''while''' left + it1 &amp;lt; mid&lt;br /&gt;
         result[it1 + it2] = A[left + it1]&lt;br /&gt;
         it1 += 1&lt;br /&gt;
   &lt;br /&gt;
     '''while''' mid + it2 &amp;lt; right&lt;br /&gt;
         result[it1 + it2] = A[mid + it2]&lt;br /&gt;
         it2 += 1&lt;br /&gt;
   &lt;br /&gt;
     '''for''' i = 0 '''to''' it1 + it2&lt;br /&gt;
         A[left + i] = result[i]&lt;br /&gt;
&lt;br /&gt;
===Рекурсивный алгоритм===&lt;br /&gt;
[[Файл:Merge sort1.png|300px|right|thumb|Пример работы рекурсивного алгоритма сортировки слиянием]]&lt;br /&gt;
Функция сортирует подотрезок массива с индексами в полуинтервале [left; right).&lt;br /&gt;
&lt;br /&gt;
 MergeSort(A : '''int[1..N]'''; left, right : '''int'''):&lt;br /&gt;
     '''if''' left + 1 &amp;gt;= right&lt;br /&gt;
         return&lt;br /&gt;
     mid = (left + right) / 2&lt;br /&gt;
     MergeSort(A, left, mid)&lt;br /&gt;
     MergeSort(A, mid, right)&lt;br /&gt;
     Merge(A, left, mid, right)&lt;br /&gt;
&lt;br /&gt;
Пример работы алгоритма показан на рисунке:&lt;br /&gt;
&lt;br /&gt;
==Время работы==&lt;br /&gt;
Чтобы оценить время работы этого алгоритма, составим рекуррентное соотношение. Пускай &amp;lt;tex&amp;gt;T(n)&amp;lt;/tex&amp;gt; — время сортировки массива длины n, тогда для сортировки слиянием справедливо &amp;lt;tex&amp;gt;T(n)=2T(n/2)+O(n)&amp;lt;/tex&amp;gt; &amp;lt;br&amp;gt;&lt;br /&gt;
(&amp;lt;tex&amp;gt;O(n)&amp;lt;/tex&amp;gt; — это время, необходимое на то, чтобы слить два массива). Распишем это соотношение:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;T(n)=2T(n/2)+O(n)=4T(n/4)+2O(n)=\dots=2^kT(1)+kO(n)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Осталось оценить &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt;. Мы знаем, что &amp;lt;tex&amp;gt;2^k=n&amp;lt;/tex&amp;gt;, а значит &amp;lt;tex&amp;gt;k=\log n&amp;lt;/tex&amp;gt;. Уравнение примет вид &amp;lt;tex&amp;gt;T(n)=nT(1)+ \log n&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;O(n)&amp;lt;/tex&amp;gt;. Так как &amp;lt;tex&amp;gt;T(1)&amp;lt;/tex&amp;gt; — константа, то &amp;lt;tex&amp;gt;T(n)=O(n)+\log n &amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;O(n)=O(n\log n)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==Источники информации==&lt;br /&gt;
*[http://ru.wikipedia.org/wiki/Mergesort Википедия {{---}} сортировка слиянием]&lt;br /&gt;
&lt;br /&gt;
==Ссылки==&lt;br /&gt;
*[http://www.sorting-algorithms.com/merge-sort Визуализатор]&lt;br /&gt;
*[http://ru.wikibooks.org/wiki/%D0%9F%D1%80%D0%B8%D0%BC%D0%B5%D1%80%D1%8B_%D1%80%D0%B5%D0%B0%D0%BB%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D0%B8_%D1%81%D0%BE%D1%80%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B8_%D1%81%D0%BB%D0%B8%D1%8F%D0%BD%D0%B8%D0%B5%D0%BC Викиучебник {{---}} Примеры реализации на различных языках программирования]&lt;br /&gt;
&lt;br /&gt;
==См. также==&lt;br /&gt;
* [[Сортировка кучей]]&lt;br /&gt;
* [[Быстрая сортировка]]&lt;br /&gt;
*[[Cортировка слиянием с использованием O(1) дополнительной памяти]]&lt;br /&gt;
&lt;br /&gt;
[[Категория: Дискретная математика и алгоритмы]]&lt;br /&gt;
[[Категория: Сортировка]]&lt;br /&gt;
[[Категория: Сортировки на сравнениях]]&lt;/div&gt;</summary>
		<author><name>Ильнар</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%A5%D0%B0%D1%84%D1%84%D0%BC%D0%B0%D0%BD%D0%B0_%D0%B7%D0%B0_O(n)&amp;diff=44324</id>
		<title>Алгоритм Хаффмана за O(n)</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%A5%D0%B0%D1%84%D1%84%D0%BC%D0%B0%D0%BD%D0%B0_%D0%B7%D0%B0_O(n)&amp;diff=44324"/>
				<updated>2015-01-12T17:08:30Z</updated>
		
		<summary type="html">&lt;p&gt;Ильнар: /* Псевдокод */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Задача&lt;br /&gt;
|definition =&lt;br /&gt;
Пусть у нас есть отсортированный по возрастанию алфавит &amp;lt;tex&amp;gt;\Sigma = \{a_1, a_2, \cdots, a_n\}&amp;lt;/tex&amp;gt;, &amp;lt;tex&amp;gt;|\Sigma| = n&amp;lt;/tex&amp;gt;. Где &amp;lt;tex&amp;gt;a_i&amp;lt;/tex&amp;gt; {{---}} число вхождений символа в строку.&lt;br /&gt;
Требуется построить [[Алгоритм_Хаффмана | код Хаффмана]] за &amp;lt;tex&amp;gt;O(n)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== Описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Eсли массив не отсортирован, то это можно сделать, например,[[Цифровая_сортировка | цифровой сортировкой]] за  &amp;lt;tex&amp;gt; O(n) &amp;lt;/tex&amp;gt;, что не ухудшит асимптотику.&lt;br /&gt;
&lt;br /&gt;
Идея алгоритма заключается в том, чтобы создать такую [[Дискретная_математика,_алгоритмы_и_структуры_данных#.D0.9F.D1.80.D0.B8.D0.BE.D1.80.D0.B8.D1.82.D0.B5.D1.82.D0.BD.D1.8B.D0.B5_.D0.BE.D1.87.D0.B5.D1.80.D0.B5.D0.B4.D0.B8 | очередь с приоритетами]], из которой можно было бы доставать два минимума за &amp;lt;tex&amp;gt; O(1) &amp;lt;/tex&amp;gt;, после чего в эту же очередь с приоритетами положить их сумму за &amp;lt;tex&amp;gt; O(1) &amp;lt;/tex&amp;gt;. У нас уже есть массив с отсортированными частотами, теперь заведем второй массив, в котором мы будем хранить суммы. &lt;br /&gt;
На каждой итерации мы будем выбирать два минимума из четырех элементов (первые 2 элемента первого массива и первые 2 элемента второго массива). Теперь рассмотрим одну итерацию подробнее. &lt;br /&gt;
&lt;br /&gt;
У нас есть три варианта возможных пар минимумов :&lt;br /&gt;
# Оба элемента из первого массива.&lt;br /&gt;
# Первый элемент первого массива и первый элемент второго массива.&lt;br /&gt;
# Два первых элемента второго массива.&lt;br /&gt;
&lt;br /&gt;
Во всех случаях мы дописываем сумму в конец второго массива и передвигаем указатели в массивах на еще не использованные элементы. &lt;br /&gt;
&lt;br /&gt;
Несложно заметить, что в этом массиве элементы тоже будут идти по неубыванию. Допустим, что на каком-то шаге сумма получилась меньше чем предыдущая, но это противоречит тому, что на каждом шаге мы выбираем два минимальных (т.е. на каждом последующем шаге мы выбираем два минимума из элементов не меньших, чем на предыдущем шаге). &lt;br /&gt;
&lt;br /&gt;
На каждом шаге количество элементов  уменьшается ровно на один, а минимум из 4-х элементов мы выбираем за константное время, поэтому асимптотика программы составляет &amp;lt;tex&amp;gt;O(n)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==Пример==&lt;br /&gt;
Для примера возьмем строку &amp;quot;абракадабра&amp;quot;.&lt;br /&gt;
&amp;lt;tex&amp;gt;i, j&amp;lt;/tex&amp;gt; {{---}} указатели на первые неиспользованные элементы в массиве 1 и 2, соответственно.&lt;br /&gt;
 &lt;br /&gt;
&amp;lt;tex&amp;gt;i = 0, j = 0&amp;lt;/tex&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Буква || д || к || б || р || а&lt;br /&gt;
|-&lt;br /&gt;
| Массив 1 || 1 || 1 || 2 || 2 || 5&lt;br /&gt;
|}&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!   || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| Массив 2 || &amp;lt;tex&amp;gt;\infty&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;\infty&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;\infty&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;\infty&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;\infty&amp;lt;/tex&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
На первом шаге два минимальных элемента {{---}} это первые две ячейки первого массива. Их сумму сохраняем во второй массив.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;i = 2, j = 0&amp;lt;/tex&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Буква || д || к || б || р || а&lt;br /&gt;
|-&lt;br /&gt;
| Массив 1 || 1|| 1 || 2 || 2 || 5&lt;br /&gt;
|}&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!  || дк || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| Массив 2 || 2 || &amp;lt;tex&amp;gt;\infty&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;\infty&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;\infty&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;\infty&amp;lt;/tex&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
На втором шаге снова суммируются первые две ячейки первого массива (нам все равно что взять, первый элемент второго массива или второй элемент первого).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;i = 4, j = 0&amp;lt;/tex&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Буква || д || к || б || р || а&lt;br /&gt;
|-&lt;br /&gt;
| Массив 1 || 1|| 1 || 2 || 2 || 5&lt;br /&gt;
|}&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!  || дк || бр || || ||&lt;br /&gt;
|-&lt;br /&gt;
| Массив 2 || 2 || 4 || &amp;lt;tex&amp;gt;\infty&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;\infty&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;\infty&amp;lt;/tex&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
На третьем шаге два минимальных элемента {{---}} это первые две ячейки второго массива.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;i = 4, j = 2&amp;lt;/tex&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Буква || д || к || б || р || а&lt;br /&gt;
|-&lt;br /&gt;
| Массив 1 || 1 || 1|| 2|| 2|| 5&lt;br /&gt;
|}&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!  || дк || бр || дкбр || ||&lt;br /&gt;
|-&lt;br /&gt;
| Массив 2 || 2|| 4|| 6 || &amp;lt;tex&amp;gt;\infty&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;\infty&amp;lt;/tex&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
На четвертом шаге складываются две оставшиеся ячейки.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt; i = 5, j = 3&amp;lt;/tex&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Буква || д || к || б || р || а&lt;br /&gt;
|-&lt;br /&gt;
| Массив 1 || 1 || 1 || 2 || 2 || 5&lt;br /&gt;
|}&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!  || дк || бр || дкбр || адкбр ||&lt;br /&gt;
|-&lt;br /&gt;
| Массив 2 || 2 || 4 || 6 || 11 || &amp;lt;tex&amp;gt;\infty&amp;lt;/tex&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Псевдокод==&lt;br /&gt;
Код возвращает число бит, необходимых для кодирования текста с заданным количеством вхождений каждого символа.&lt;br /&gt;
 '''int''' HuffmanCoding(a: '''int[0..n]'''):&lt;br /&gt;
    b: '''int[0..n]'''&lt;br /&gt;
    i, j, ans: '''int''' ''&amp;lt;font color=green&amp;gt;// i, j {{---}} указатели в массивах&amp;lt;/font&amp;gt;''&lt;br /&gt;
    '''for''' k = 0 '''to''' n&lt;br /&gt;
       b[k] = &amp;lt;tex&amp;gt;\infty&amp;lt;/tex&amp;gt;&lt;br /&gt;
    '''for''' k = 0 '''to''' n - 1&lt;br /&gt;
       '''if''' a[i] + a[i + 1] &amp;lt;= a[i] + b[j] '''and''' a[i] + a[i + 1] &amp;lt;= b[j] + b[j + 1]&lt;br /&gt;
          b[k] = a[i] + a[i + 1]&lt;br /&gt;
          ans += b[k]&lt;br /&gt;
          i += 2&lt;br /&gt;
          '''continue'''&lt;br /&gt;
       '''if''' a[i] + b[j] &amp;lt;= a[i] + a[i + 1] '''and''' a[i] + b[j] &amp;lt;= b[j] + b[j + 1]&lt;br /&gt;
          b[k] = a[i] + b[j]&lt;br /&gt;
          ans += b[k]&lt;br /&gt;
          i++&lt;br /&gt;
          j++&lt;br /&gt;
          '''continue'''&lt;br /&gt;
       '''if''' b[j] + b[j + 1] &amp;lt;= a[i] + a[i + 1] '''and''' b[j] + b[j + 1] &amp;lt;= a[i] + b[j]&lt;br /&gt;
          b[k] = b[j] + b[j + 1]&lt;br /&gt;
          ans += b[k]&lt;br /&gt;
          j += 2&lt;br /&gt;
    '''return''' ans&lt;br /&gt;
&lt;br /&gt;
==См. также==&lt;br /&gt;
*[[Оптимальное хранение словаря в алгоритме Хаффмана]]&lt;br /&gt;
&lt;br /&gt;
[[Категория: Дискретная математика и алгоритмы]]&lt;br /&gt;
&lt;br /&gt;
[[Категория: Алгоритмы сжатия ]]&lt;/div&gt;</summary>
		<author><name>Ильнар</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%A5%D0%B0%D1%84%D1%84%D0%BC%D0%B0%D0%BD%D0%B0_%D0%B7%D0%B0_O(n)&amp;diff=44323</id>
		<title>Алгоритм Хаффмана за O(n)</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%A5%D0%B0%D1%84%D1%84%D0%BC%D0%B0%D0%BD%D0%B0_%D0%B7%D0%B0_O(n)&amp;diff=44323"/>
				<updated>2015-01-12T17:02:45Z</updated>
		
		<summary type="html">&lt;p&gt;Ильнар: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Задача&lt;br /&gt;
|definition =&lt;br /&gt;
Пусть у нас есть отсортированный по возрастанию алфавит &amp;lt;tex&amp;gt;\Sigma = \{a_1, a_2, \cdots, a_n\}&amp;lt;/tex&amp;gt;, &amp;lt;tex&amp;gt;|\Sigma| = n&amp;lt;/tex&amp;gt;. Где &amp;lt;tex&amp;gt;a_i&amp;lt;/tex&amp;gt; {{---}} число вхождений символа в строку.&lt;br /&gt;
Требуется построить [[Алгоритм_Хаффмана | код Хаффмана]] за &amp;lt;tex&amp;gt;O(n)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== Описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Eсли массив не отсортирован, то это можно сделать, например,[[Цифровая_сортировка | цифровой сортировкой]] за  &amp;lt;tex&amp;gt; O(n) &amp;lt;/tex&amp;gt;, что не ухудшит асимптотику.&lt;br /&gt;
&lt;br /&gt;
Идея алгоритма заключается в том, чтобы создать такую [[Дискретная_математика,_алгоритмы_и_структуры_данных#.D0.9F.D1.80.D0.B8.D0.BE.D1.80.D0.B8.D1.82.D0.B5.D1.82.D0.BD.D1.8B.D0.B5_.D0.BE.D1.87.D0.B5.D1.80.D0.B5.D0.B4.D0.B8 | очередь с приоритетами]], из которой можно было бы доставать два минимума за &amp;lt;tex&amp;gt; O(1) &amp;lt;/tex&amp;gt;, после чего в эту же очередь с приоритетами положить их сумму за &amp;lt;tex&amp;gt; O(1) &amp;lt;/tex&amp;gt;. У нас уже есть массив с отсортированными частотами, теперь заведем второй массив, в котором мы будем хранить суммы. &lt;br /&gt;
На каждой итерации мы будем выбирать два минимума из четырех элементов (первые 2 элемента первого массива и первые 2 элемента второго массива). Теперь рассмотрим одну итерацию подробнее. &lt;br /&gt;
&lt;br /&gt;
У нас есть три варианта возможных пар минимумов :&lt;br /&gt;
# Оба элемента из первого массива.&lt;br /&gt;
# Первый элемент первого массива и первый элемент второго массива.&lt;br /&gt;
# Два первых элемента второго массива.&lt;br /&gt;
&lt;br /&gt;
Во всех случаях мы дописываем сумму в конец второго массива и передвигаем указатели в массивах на еще не использованные элементы. &lt;br /&gt;
&lt;br /&gt;
Несложно заметить, что в этом массиве элементы тоже будут идти по неубыванию. Допустим, что на каком-то шаге сумма получилась меньше чем предыдущая, но это противоречит тому, что на каждом шаге мы выбираем два минимальных (т.е. на каждом последующем шаге мы выбираем два минимума из элементов не меньших, чем на предыдущем шаге). &lt;br /&gt;
&lt;br /&gt;
На каждом шаге количество элементов  уменьшается ровно на один, а минимум из 4-х элементов мы выбираем за константное время, поэтому асимптотика программы составляет &amp;lt;tex&amp;gt;O(n)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==Пример==&lt;br /&gt;
Для примера возьмем строку &amp;quot;абракадабра&amp;quot;.&lt;br /&gt;
&amp;lt;tex&amp;gt;i, j&amp;lt;/tex&amp;gt; {{---}} указатели на первые неиспользованные элементы в массиве 1 и 2, соответственно.&lt;br /&gt;
 &lt;br /&gt;
&amp;lt;tex&amp;gt;i = 0, j = 0&amp;lt;/tex&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Буква || д || к || б || р || а&lt;br /&gt;
|-&lt;br /&gt;
| Массив 1 || 1 || 1 || 2 || 2 || 5&lt;br /&gt;
|}&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!   || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| Массив 2 || &amp;lt;tex&amp;gt;\infty&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;\infty&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;\infty&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;\infty&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;\infty&amp;lt;/tex&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
На первом шаге два минимальных элемента {{---}} это первые две ячейки первого массива. Их сумму сохраняем во второй массив.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;i = 2, j = 0&amp;lt;/tex&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Буква || д || к || б || р || а&lt;br /&gt;
|-&lt;br /&gt;
| Массив 1 || 1|| 1 || 2 || 2 || 5&lt;br /&gt;
|}&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!  || дк || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| Массив 2 || 2 || &amp;lt;tex&amp;gt;\infty&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;\infty&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;\infty&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;\infty&amp;lt;/tex&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
На втором шаге снова суммируются первые две ячейки первого массива (нам все равно что взять, первый элемент второго массива или второй элемент первого).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;i = 4, j = 0&amp;lt;/tex&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Буква || д || к || б || р || а&lt;br /&gt;
|-&lt;br /&gt;
| Массив 1 || 1|| 1 || 2 || 2 || 5&lt;br /&gt;
|}&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!  || дк || бр || || ||&lt;br /&gt;
|-&lt;br /&gt;
| Массив 2 || 2 || 4 || &amp;lt;tex&amp;gt;\infty&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;\infty&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;\infty&amp;lt;/tex&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
На третьем шаге два минимальных элемента {{---}} это первые две ячейки второго массива.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;i = 4, j = 2&amp;lt;/tex&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Буква || д || к || б || р || а&lt;br /&gt;
|-&lt;br /&gt;
| Массив 1 || 1 || 1|| 2|| 2|| 5&lt;br /&gt;
|}&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!  || дк || бр || дкбр || ||&lt;br /&gt;
|-&lt;br /&gt;
| Массив 2 || 2|| 4|| 6 || &amp;lt;tex&amp;gt;\infty&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;\infty&amp;lt;/tex&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
На четвертом шаге складываются две оставшиеся ячейки.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt; i = 5, j = 3&amp;lt;/tex&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Буква || д || к || б || р || а&lt;br /&gt;
|-&lt;br /&gt;
| Массив 1 || 1 || 1 || 2 || 2 || 5&lt;br /&gt;
|}&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!  || дк || бр || дкбр || адкбр ||&lt;br /&gt;
|-&lt;br /&gt;
| Массив 2 || 2 || 4 || 6 || 11 || &amp;lt;tex&amp;gt;\infty&amp;lt;/tex&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Псевдокод==&lt;br /&gt;
Код возвращает число бит, необходимых для кодирования текста с заданным количеством вхождений каждого символа.&lt;br /&gt;
 '''int''' HuffmanCoding(a: '''int[0..n]'''):&lt;br /&gt;
    b: '''int[0..n]'''&lt;br /&gt;
    i, j, ans: '''int''' ''&amp;lt;font color=green&amp;gt;// i, j {{---}} указатели в массивах, inf {{---}} большое число&amp;lt;/font&amp;gt;''&lt;br /&gt;
    '''for''' k = 0 '''to''' n&lt;br /&gt;
       b[k] = &amp;lt;tex&amp;gt;\infty&amp;lt;/tex&amp;gt;&lt;br /&gt;
    '''for''' k = 0 '''to''' n - 1&lt;br /&gt;
       '''if''' a[i] + a[i + 1] &amp;lt;= a[i] + b[j] '''and''' a[i] + a[i + 1] &amp;lt;= b[j] + b[j + 1]&lt;br /&gt;
          b[k] = a[i] + a[i + 1]&lt;br /&gt;
          ans += b[k]&lt;br /&gt;
          i += 2&lt;br /&gt;
          '''continue'''&lt;br /&gt;
       '''if''' a[i] + b[j] &amp;lt;= a[i] + a[i + 1] '''and''' a[i] + b[j] &amp;lt;= b[j] + b[j + 1]&lt;br /&gt;
          b[k] = a[i] + b[j]&lt;br /&gt;
          ans += b[k]&lt;br /&gt;
          i++&lt;br /&gt;
          j++&lt;br /&gt;
          '''continue'''&lt;br /&gt;
       '''if''' b[j] + b[j + 1] &amp;lt;= a[i] + a[i + 1] '''and''' b[j] + b[j + 1] &amp;lt;= a[i] + b[j]&lt;br /&gt;
          b[k] = b[j] + b[j + 1]&lt;br /&gt;
          ans += b[k]&lt;br /&gt;
          j += 2&lt;br /&gt;
    '''return''' ans&lt;br /&gt;
==См. также==&lt;br /&gt;
*[[Оптимальное хранение словаря в алгоритме Хаффмана]]&lt;br /&gt;
&lt;br /&gt;
[[Категория: Дискретная математика и алгоритмы]]&lt;br /&gt;
&lt;br /&gt;
[[Категория: Алгоритмы сжатия ]]&lt;/div&gt;</summary>
		<author><name>Ильнар</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%A5%D0%B0%D1%84%D1%84%D0%BC%D0%B0%D0%BD%D0%B0_%D0%B7%D0%B0_O(n)&amp;diff=44315</id>
		<title>Алгоритм Хаффмана за O(n)</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%A5%D0%B0%D1%84%D1%84%D0%BC%D0%B0%D0%BD%D0%B0_%D0%B7%D0%B0_O(n)&amp;diff=44315"/>
				<updated>2015-01-12T16:11:00Z</updated>
		
		<summary type="html">&lt;p&gt;Ильнар: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Задача&lt;br /&gt;
|definition =&lt;br /&gt;
Пусть у нас есть отсортированный по возрастанию алфавит &amp;lt;tex&amp;gt;\Sigma = \{a_1, a_2, \cdots, a_n\}&amp;lt;/tex&amp;gt;, &amp;lt;tex&amp;gt;|\Sigma| = n&amp;lt;/tex&amp;gt;. Где &amp;lt;tex&amp;gt;a_i&amp;lt;/tex&amp;gt; {{---}} число вхождений символа в строку.&lt;br /&gt;
Требуется построить [[Алгоритм_Хаффмана | код Хаффмана]] за &amp;lt;tex&amp;gt;O(n)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== Описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Eсли массив не отсортирован, то это можно сделать, например,[[Цифровая_сортировка | цифровой сортировкой]] за  &amp;lt;tex&amp;gt; O(n) &amp;lt;/tex&amp;gt;, что не ухудшит асимптотику.&lt;br /&gt;
&lt;br /&gt;
Идея алгоритма заключается в том, чтобы создать такую [[Дискретная_математика,_алгоритмы_и_структуры_данных#.D0.9F.D1.80.D0.B8.D0.BE.D1.80.D0.B8.D1.82.D0.B5.D1.82.D0.BD.D1.8B.D0.B5_.D0.BE.D1.87.D0.B5.D1.80.D0.B5.D0.B4.D0.B8 | очередь с приоритетами]], из которой можно было бы доставать два минимума за &amp;lt;tex&amp;gt; O(1) &amp;lt;/tex&amp;gt;, после чего в эту же очередь с приоритетами положить их сумму за &amp;lt;tex&amp;gt; O(1) &amp;lt;/tex&amp;gt;. У нас уже есть массив с отсортированными частотами, теперь заведем второй массив, в котором мы будем хранить суммы. &lt;br /&gt;
На каждой итерации мы будем выбирать два минимума из четырех элементов (первые 2 элемента первого массива и первые 2 элемента второго массива). Теперь рассмотрим одну итерацию подробнее. &lt;br /&gt;
&lt;br /&gt;
У нас есть три варианта возможных пар минимумов :&lt;br /&gt;
# Оба элемента из первого массива.&lt;br /&gt;
# Первый элемент первого массива и первый элемент второго массива.&lt;br /&gt;
# Два первых элемента второго массива.&lt;br /&gt;
&lt;br /&gt;
Во всех случаях мы дописываем сумму в конец второго массива и передвигаем указатели в массивах на еще не использованные элементы. &lt;br /&gt;
&lt;br /&gt;
Несложно заметить, что в этом массиве элементы тоже будут идти по неубыванию. Допустим, что на каком-то шаге сумма получилась меньше чем предыдущая, но это противоречит тому, что на каждом шаге мы выбираем два минимальных. &lt;br /&gt;
&lt;br /&gt;
На каждом шаге количество элементов  уменьшается ровно на один, а минимум из 4-х элементов мы выбираем за константное время, поэтому асимптотика программы составляет &amp;lt;tex&amp;gt;O(n)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==Пример==&lt;br /&gt;
Для примера возьмем строку &amp;quot;абракадабра&amp;quot;.&lt;br /&gt;
&amp;lt;tex&amp;gt;i, j&amp;lt;/tex&amp;gt; {{---}} указатели на первые неиспользованные элементы в массиве 1 и 2, соответственно.&lt;br /&gt;
 &lt;br /&gt;
&amp;lt;tex&amp;gt;i = 0, j = 0&amp;lt;/tex&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Буква || д || к || б || р || а&lt;br /&gt;
|-&lt;br /&gt;
| Массив 1 || 1 || 1 || 2 || 2 || 5&lt;br /&gt;
|}&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!   || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| Массив 2 || &amp;lt;tex&amp;gt;\infty&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;\infty&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;\infty&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;\infty&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;\infty&amp;lt;/tex&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
На первом шаге два минимальных элемента {{---}} это первые две ячейки первого массива. Их сумму сохраняем во второй массив.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;i = 2, j = 0&amp;lt;/tex&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Буква || д || к || б || р || а&lt;br /&gt;
|-&lt;br /&gt;
| Массив 1 || 1|| 1 || 2 || 2 || 5&lt;br /&gt;
|}&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!  || дк || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| Массив 2 || 2 || &amp;lt;tex&amp;gt;\infty&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;\infty&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;\infty&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;\infty&amp;lt;/tex&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
На втором шаге снова суммируются первые две ячейки первого массива (нам все равно что взять, первый элемент второго массива или второй элемент первого).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;i = 4, j = 0&amp;lt;/tex&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Буква || д || к || б || р || а&lt;br /&gt;
|-&lt;br /&gt;
| Массив 1 || 1|| 1 || 2 || 2 || 5&lt;br /&gt;
|}&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!  || дк || бр || || ||&lt;br /&gt;
|-&lt;br /&gt;
| Массив 2 || 2 || 4 || &amp;lt;tex&amp;gt;\infty&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;\infty&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;\infty&amp;lt;/tex&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
На третьем шаге два минимальных элемента {{---}} это первые две ячейки второго массива.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;i = 4, j = 2&amp;lt;/tex&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Буква || д || к || б || р || а&lt;br /&gt;
|-&lt;br /&gt;
| Массив 1 || 1 || 1|| 2|| 2|| 5&lt;br /&gt;
|}&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!  || дк || бр || дкбр || ||&lt;br /&gt;
|-&lt;br /&gt;
| Массив 2 || 2|| 4|| 6 || &amp;lt;tex&amp;gt;\infty&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;\infty&amp;lt;/tex&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
На четвертом шаге складываются две оставшиеся ячейки.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt; i = 5, j = 3&amp;lt;/tex&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Буква || д || к || б || р || а&lt;br /&gt;
|-&lt;br /&gt;
| Массив 1 || 1 || 1 || 2 || 2 || 5&lt;br /&gt;
|}&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!  || дк || бр || дкбр || адкбр ||&lt;br /&gt;
|-&lt;br /&gt;
| Массив 2 || 2 || 4 || 6 || 11 || &amp;lt;tex&amp;gt;\infty&amp;lt;/tex&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Псевдокод==&lt;br /&gt;
 '''int''' HuffmanCoding(a: '''int[0..n]'''):&lt;br /&gt;
    b: '''int[0..n]'''&lt;br /&gt;
    i, j, ans: '''int''' ''&amp;lt;font color=green&amp;gt;// i, j {{---}} указатели в массивах, inf {{---}} большое число&amp;lt;/font&amp;gt;''&lt;br /&gt;
    '''for''' k = 0 '''to''' n&lt;br /&gt;
       b[k] = &amp;lt;tex&amp;gt;\infty&amp;lt;/tex&amp;gt;&lt;br /&gt;
    '''for''' k = 0 '''to''' n - 1&lt;br /&gt;
       '''if''' a[i] + a[i + 1] &amp;lt;= a[i] + b[j] '''and''' a[i] + a[i + 1] &amp;lt;= b[j] + b[j + 1]&lt;br /&gt;
          b[k] = a[i] + a[i + 1]&lt;br /&gt;
          ans += b[k]&lt;br /&gt;
          i += 2&lt;br /&gt;
          '''continue'''&lt;br /&gt;
       '''if''' a[i] + b[j] &amp;lt;= a[i] + a[i + 1] '''and''' a[i] + b[j] &amp;lt;= b[j] + b[j + 1]&lt;br /&gt;
          b[k] = a[i] + b[j]&lt;br /&gt;
          ans += b[k]&lt;br /&gt;
          i++&lt;br /&gt;
          j++&lt;br /&gt;
          '''continue'''&lt;br /&gt;
       '''if''' b[j] + b[j + 1] &amp;lt;= a[i] + a[i + 1] '''and''' b[j] + b[j + 1] &amp;lt;= a[i] + b[j]&lt;br /&gt;
          b[k] = b[j] + b[j + 1]&lt;br /&gt;
          ans += b[k]&lt;br /&gt;
          j += 2&lt;br /&gt;
    '''return''' ans&lt;br /&gt;
==См. также==&lt;br /&gt;
*[[Оптимальное хранение словаря в алгоритме Хаффмана]]&lt;br /&gt;
&lt;br /&gt;
[[Категория: Дискретная математика и алгоритмы]]&lt;br /&gt;
&lt;br /&gt;
[[Категория: Алгоритмы сжатия ]]&lt;/div&gt;</summary>
		<author><name>Ильнар</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%A5%D0%B0%D1%84%D1%84%D0%BC%D0%B0%D0%BD%D0%B0_%D0%B7%D0%B0_O(n)&amp;diff=44308</id>
		<title>Алгоритм Хаффмана за O(n)</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%A5%D0%B0%D1%84%D1%84%D0%BC%D0%B0%D0%BD%D0%B0_%D0%B7%D0%B0_O(n)&amp;diff=44308"/>
				<updated>2015-01-12T15:56:07Z</updated>
		
		<summary type="html">&lt;p&gt;Ильнар: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Задача&lt;br /&gt;
|definition =&lt;br /&gt;
Пусть у нас есть отсортированный по возрастанию алфавит &amp;lt;tex&amp;gt;\Sigma = \{a_1, a_2, \cdots, a_n\}&amp;lt;/tex&amp;gt;, &amp;lt;tex&amp;gt;|\Sigma| = n&amp;lt;/tex&amp;gt;. Где &amp;lt;tex&amp;gt;a_i&amp;lt;/tex&amp;gt; {{---}} число вхождений символа в строку.&lt;br /&gt;
Требуется построить [[Алгоритм_Хаффмана | код Хаффмана]] за &amp;lt;tex&amp;gt;O(n)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== Описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Eсли массив не отсортирован, то это можно сделать, например,[[Цифровая_сортировка | цифровой сортировкой]] за  &amp;lt;tex&amp;gt; O(n) &amp;lt;/tex&amp;gt;, что не ухудшит асимптотику.&lt;br /&gt;
&lt;br /&gt;
Идея алгоритма заключается в том, чтобы создать такую [[Дискретная_математика,_алгоритмы_и_структуры_данных#.D0.9F.D1.80.D0.B8.D0.BE.D1.80.D0.B8.D1.82.D0.B5.D1.82.D0.BD.D1.8B.D0.B5_.D0.BE.D1.87.D0.B5.D1.80.D0.B5.D0.B4.D0.B8 | очередь с приоритетами]], из которой можно было бы доставать два минимума за &amp;lt;tex&amp;gt; O(1) &amp;lt;/tex&amp;gt;, после чего в эту же очередь с приоритетами положить их сумму за &amp;lt;tex&amp;gt; O(1) &amp;lt;/tex&amp;gt;. У нас уже есть массив с отсортированными частотами, теперь давайте заведем второй массив, в котором мы будем хранить суммы. &lt;br /&gt;
На каждой итерации мы будем выбирать два минимума из четырех элементов (первые 2 элемента первого массива и первые 2 элемента второго массива). Теперь рассмотрим одну итерацию подробнее. &lt;br /&gt;
&lt;br /&gt;
У нас есть три варианта возможных пар минимумов :&lt;br /&gt;
# Оба элемента из первого массива.&lt;br /&gt;
# Первый элемент первого массива и первый элемент второго массива.&lt;br /&gt;
# Два первых элемента второго массива.&lt;br /&gt;
&lt;br /&gt;
Во всех случаях мы дописываем сумму в конец второго массива и передвигаем указатели в массивах на еще не использованные элементы. &lt;br /&gt;
&lt;br /&gt;
Несложно заметить, что в этом массиве элементы тоже будут идти по неубыванию. Допустим, что на каком-то шаге сумма получилась меньше чем предыдущая, но это противоречит тому, что на каждом шаге мы выбираем два минимальных. &lt;br /&gt;
&lt;br /&gt;
На каждом шаге количество элементов  уменьшается ровно на один, а минимум из 4-х элементов мы выбираем за константное время, следовательно, программа делает ровно &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt; итераций.&lt;br /&gt;
&lt;br /&gt;
==Пример==&lt;br /&gt;
Для примера возьмем строку &amp;quot;абракадабра&amp;quot;.&lt;br /&gt;
&amp;lt;tex&amp;gt;i, j&amp;lt;/tex&amp;gt; {{---}} указатели на первые неиспользованные элементы в массиве 1 и 2, соответственно.&lt;br /&gt;
 &lt;br /&gt;
&amp;lt;tex&amp;gt;i = 0, j = 0&amp;lt;/tex&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Буква || д || к || б || р || а&lt;br /&gt;
|-&lt;br /&gt;
| Массив 1 || 1 || 1 || 2 || 2 || 5&lt;br /&gt;
|}&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!   || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| Массив 2 || &amp;lt;tex&amp;gt;\infty&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;\infty&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;\infty&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;\infty&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;\infty&amp;lt;/tex&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
На первом шаге два минимальных элемента - это первые две ячейки первого массива. Их сумму сохраняем во второй массив.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;i = 2, j = 0&amp;lt;/tex&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Буква || д || к || б || р || а&lt;br /&gt;
|-&lt;br /&gt;
| Массив 1 || 1|| 1 || 2 || 2 || 5&lt;br /&gt;
|}&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!  || дк || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| Массив 2 || 2 || &amp;lt;tex&amp;gt;\infty&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;\infty&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;\infty&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;\infty&amp;lt;/tex&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
На втором шаге снова суммируются первые две ячейки первого массива(нам все равно что взять, первый элемент второго массива или второй элемент первого).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;i = 4, j = 0&amp;lt;/tex&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Буква || д || к || б || р || а&lt;br /&gt;
|-&lt;br /&gt;
| Массив 1 || 1|| 1 || 2 || 2 || 5&lt;br /&gt;
|}&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!  || дк || бр || || ||&lt;br /&gt;
|-&lt;br /&gt;
| Массив 2 || 2 || 4 || &amp;lt;tex&amp;gt;\infty&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;\infty&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;\infty&amp;lt;/tex&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
На третьем шаге два минимальных элемента - это первые две ячейки второго массива.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;i = 4, j = 2&amp;lt;/tex&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Буква || д || к || б || р || а&lt;br /&gt;
|-&lt;br /&gt;
| Массив 1 || 1 || 1|| 2|| 2|| 5&lt;br /&gt;
|}&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!  || дк || бр || дкбр || ||&lt;br /&gt;
|-&lt;br /&gt;
| Массив 2 || 2|| 4|| 6 || &amp;lt;tex&amp;gt;\infty&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;\infty&amp;lt;/tex&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
На четвертом шаге складываются две оставшиеся ячейки.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt; i = 5, j = 3&amp;lt;/tex&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Буква || д || к || б || р || а&lt;br /&gt;
|-&lt;br /&gt;
| Массив 1 || 1 || 1 || 2 || 2 || 5&lt;br /&gt;
|}&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!  || дк || бр || дкбр || адкбр ||&lt;br /&gt;
|-&lt;br /&gt;
| Массив 2 || 2 || 4 || 6 || 11 || &amp;lt;tex&amp;gt;\infty&amp;lt;/tex&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Псевдокод==&lt;br /&gt;
 '''int''' HuffmanCoding(a: '''int[0..n]'''):&lt;br /&gt;
    b: '''int[0..n]'''&lt;br /&gt;
    i, j, ans: '''int''' ''&amp;lt;font color=green&amp;gt;// i, j {{---}} указатели в массивах, inf {{---}} большое число&amp;lt;/font&amp;gt;''&lt;br /&gt;
    '''for''' k = 0 '''to''' n&lt;br /&gt;
       b[k] = &amp;lt;tex&amp;gt;\infty&amp;lt;/tex&amp;gt;&lt;br /&gt;
    '''for''' k = 0 '''to''' n - 1&lt;br /&gt;
       '''if''' a[i] + a[i + 1] &amp;lt;= a[i] + b[j] &amp;amp;&amp;amp; a[i] + a[i + 1] &amp;lt;= b[j] + b[j + 1]&lt;br /&gt;
          b[k] = a[i] + a[i + 1]&lt;br /&gt;
          ans += b[k]&lt;br /&gt;
          i += 2&lt;br /&gt;
          '''continue'''&lt;br /&gt;
       '''if''' a[i] + b[j] &amp;lt;= a[i] + a[i + 1] &amp;amp;&amp;amp; a[i] + b[j] &amp;lt;= b[j] + b[j + 1]&lt;br /&gt;
          b[k] = a[i] + b[j]&lt;br /&gt;
          ans += b[k]&lt;br /&gt;
          i++&lt;br /&gt;
          j++&lt;br /&gt;
          '''continue'''&lt;br /&gt;
       '''if''' b[j] + b[j + 1] &amp;lt;= a[i] + a[i + 1] &amp;amp;&amp;amp; b[j] + b[j + 1] &amp;lt;= a[i] + b[j]&lt;br /&gt;
          b[k] = b[j] + b[j + 1]&lt;br /&gt;
          ans += b[k]&lt;br /&gt;
          j += 2&lt;br /&gt;
    '''return''' ans&lt;br /&gt;
==См. также==&lt;br /&gt;
*[[Алгоритм Хаффмана]]&lt;br /&gt;
*[[Оптимальное хранение словаря в алгоритме Хаффмана]]&lt;br /&gt;
&lt;br /&gt;
[[Категория: Дискретная математика и алгоритмы]]&lt;br /&gt;
&lt;br /&gt;
[[Категория: Алгоритмы сжатия ]]&lt;/div&gt;</summary>
		<author><name>Ильнар</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%A5%D0%B0%D1%84%D1%84%D0%BC%D0%B0%D0%BD%D0%B0_%D0%B7%D0%B0_O(n)&amp;diff=44307</id>
		<title>Алгоритм Хаффмана за O(n)</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%A5%D0%B0%D1%84%D1%84%D0%BC%D0%B0%D0%BD%D0%B0_%D0%B7%D0%B0_O(n)&amp;diff=44307"/>
				<updated>2015-01-12T15:54:08Z</updated>
		
		<summary type="html">&lt;p&gt;Ильнар: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Задача&lt;br /&gt;
|definition =&lt;br /&gt;
Пусть у нас есть отсортированный по возрастанию алфавит &amp;lt;tex&amp;gt;\Sigma = \{a_1, a_2, \cdots, a_n\}&amp;lt;/tex&amp;gt;, &amp;lt;tex&amp;gt;|\Sigma| = n&amp;lt;/tex&amp;gt;. Где &amp;lt;tex&amp;gt;a_i&amp;lt;/tex&amp;gt; {{---}} число вхождений символа в строку.&lt;br /&gt;
Требуется построить [[Алгоритм_Хаффмана | код Хаффмана]] за &amp;lt;tex&amp;gt;O(n)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== Описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Eсли массив не отсортирован, то это можно сделать, например,[[Цифровая_сортировка | цифровой сортировкой]] за  &amp;lt;tex&amp;gt; O(n) &amp;lt;/tex&amp;gt;, что не ухудшит асимптотику.&lt;br /&gt;
&lt;br /&gt;
Идея алгоритма заключается в том, чтобы создать такую [[Дискретная_математика,_алгоритмы_и_структуры_данных#.D0.9F.D1.80.D0.B8.D0.BE.D1.80.D0.B8.D1.82.D0.B5.D1.82.D0.BD.D1.8B.D0.B5_.D0.BE.D1.87.D0.B5.D1.80.D0.B5.D0.B4.D0.B8 | очередь с приоритетами]], из которой можно было бы доставать два минимума за &amp;lt;tex&amp;gt; O(1) &amp;lt;/tex&amp;gt;, после чего в эту же очередь с приоритетами положить их сумму за &amp;lt;tex&amp;gt; O(1) &amp;lt;/tex&amp;gt;. У нас уже есть массив с отсортированными частотами, теперь давайте заведем второй массив, в котором мы будем хранить суммы. &lt;br /&gt;
На каждой итерации мы будем выбирать два минимума из четырех элементов (первые 2 элемента первого массива и первые 2 элемента второго массива). Теперь рассмотрим одну итерацию подробнее. &lt;br /&gt;
&lt;br /&gt;
У нас есть три варианта возможных пар минимумов :&lt;br /&gt;
# Оба элемента из первого массива.&lt;br /&gt;
# Первый элемент первого массива и первый элемент второго массива.&lt;br /&gt;
# Два первых элемента второго массива.&lt;br /&gt;
&lt;br /&gt;
Во всех случаях мы дописываем сумму в конец второго массива и передвигаем указатели в массивах на еще не использованные элементы. &lt;br /&gt;
&lt;br /&gt;
Несложно заметить, что в этом массиве элементы тоже будут идти по неубыванию. Допустим, что на каком-то шаге сумма получилась меньше чем предыдущая, но это противоречит тому, что на каждом шаге мы выбираем два минимальных. &lt;br /&gt;
&lt;br /&gt;
На каждом шаге количество элементов  уменьшается ровно на один, а минимум из 4-х элементов мы выбираем за константное время, следовательно, программа делает ровно &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt; итераций.&lt;br /&gt;
&lt;br /&gt;
==Пример==&lt;br /&gt;
Для примера возьмем строку &amp;quot;абракадабра&amp;quot;.&lt;br /&gt;
&amp;lt;tex&amp;gt;i, j&amp;lt;/tex&amp;gt; {{---}} указатели на первые неиспользованные элементы в массиве 1 и 2, соответственно.&lt;br /&gt;
 &lt;br /&gt;
&amp;lt;tex&amp;gt;i = 0, j = 0&amp;lt;/tex&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Буква || д || к || б || р || а&lt;br /&gt;
|-&lt;br /&gt;
| Массив 1 || 1 || 1 || 2 || 2 || 5&lt;br /&gt;
|}&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!   || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| Массив 2 || &amp;lt;tex&amp;gt;\infty&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;\infty&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;\infty&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;\infty&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;\infty&amp;lt;/tex&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
На первом шаге два минимальных элемента - это первые две ячейки первого массива. Их сумму сохраняем во второй массив.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;i = 2, j = 0&amp;lt;/tex&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Буква || д || к || б || р || а&lt;br /&gt;
|-&lt;br /&gt;
| Массив 1 || 1|| 1 || 2 || 2 || 5&lt;br /&gt;
|}&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!  || дк || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| Массив 2 || 2 || &amp;lt;tex&amp;gt;\infty&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;\infty&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;\infty&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;\infty&amp;lt;/tex&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
На втором шаге снова суммируются первые две ячейки первого массива(нам все равно что взять, первый элемент второго массива или второй элемент первого).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;i = 4, j = 0&amp;lt;/tex&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Буква || д || к || б || р || а&lt;br /&gt;
|-&lt;br /&gt;
| Массив 1 || 1|| 1 || 2 || 2 || 5&lt;br /&gt;
|}&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!  || дк || бр || || ||&lt;br /&gt;
|-&lt;br /&gt;
| Массив 2 || 2 || 4 || &amp;lt;tex&amp;gt;\infty&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;\infty&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;\infty&amp;lt;/tex&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
На третьем шаге два минимальных элемента - это первые две ячейки второго массива.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;i = 4, j = 2&amp;lt;/tex&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Буква || д || к || б || р || а&lt;br /&gt;
|-&lt;br /&gt;
| Массив 1 || 1 || 1|| 2|| 2|| 5&lt;br /&gt;
|}&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!  || дк || бр || дкбр || ||&lt;br /&gt;
|-&lt;br /&gt;
| Массив 2 || 2|| 4|| 6 || &amp;lt;tex&amp;gt;\infty&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;\infty&amp;lt;/tex&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
На четвертом шаге складываются две оставшиеся ячейки.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt; i = 5, j = 3&amp;lt;/tex&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Буква || д || к || б || р || а&lt;br /&gt;
|-&lt;br /&gt;
| Массив 1 || 1 || 1 || 2 || 2 || 5&lt;br /&gt;
|}&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!  || дк || бр || дкбр || адкбр ||&lt;br /&gt;
|-&lt;br /&gt;
| Массив 2 || 2 || 4 || 6 || 11 || &amp;lt;tex&amp;gt;\infty&amp;lt;/tex&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Псевдокод==&lt;br /&gt;
 '''int''' HuffmanCoding(a: '''int[0..n]'''):&lt;br /&gt;
    b: '''int[0..n]'''&lt;br /&gt;
    i, j, ans: '''int''' ''&amp;lt;font color=green&amp;gt;// i, j {{---}} указатели в массивах, inf {{---}} большое число&amp;lt;/font&amp;gt;''&lt;br /&gt;
    '''for''' k = 0 '''to''' n&lt;br /&gt;
       b[k] = &amp;lt;tex&amp;gt;\infty&amp;lt;/tex&amp;gt;&lt;br /&gt;
    '''for''' k = 0 '''to''' n - 1&lt;br /&gt;
       '''if''' a[i] + a[i + 1] &amp;lt;= a[i] + b[j] &amp;amp;&amp;amp; a[i] + a[i + 1] &amp;lt;= b[j] + b[j + 1]&lt;br /&gt;
          b[k] = a[i] + a[i + 1]&lt;br /&gt;
          ans += b[k]&lt;br /&gt;
          i += 2&lt;br /&gt;
          '''continue'''&lt;br /&gt;
       '''if''' a[i] + b[j] &amp;lt;= a[i] + a[i + 1] &amp;amp;&amp;amp; a[i] + b[j] &amp;lt;= b[j] + b[j + 1]&lt;br /&gt;
          b[k] = a[i] + b[j]&lt;br /&gt;
          ans += b[k]&lt;br /&gt;
          i++&lt;br /&gt;
          j++&lt;br /&gt;
          '''continue'''&lt;br /&gt;
       '''if''' b[j] + b[j + 1] &amp;lt;= a[i] + a[i + 1] &amp;amp;&amp;amp; b[j] + b[j + 1] &amp;lt;= a[i] + b[j]&lt;br /&gt;
          b[k] = b[j] + b[j + 1]&lt;br /&gt;
          ans += b[k]&lt;br /&gt;
          j += 2&lt;br /&gt;
    '''return''' ans&lt;br /&gt;
==См. также==&lt;br /&gt;
*[[Алгоритм Хаффмана]]&lt;br /&gt;
*[[Оптимальное хранение словаря в алгоритме Хаффмана]]&lt;/div&gt;</summary>
		<author><name>Ильнар</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%A5%D0%B0%D1%84%D1%84%D0%BC%D0%B0%D0%BD%D0%B0_%D0%B7%D0%B0_O(n)&amp;diff=44296</id>
		<title>Алгоритм Хаффмана за O(n)</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%A5%D0%B0%D1%84%D1%84%D0%BC%D0%B0%D0%BD%D0%B0_%D0%B7%D0%B0_O(n)&amp;diff=44296"/>
				<updated>2015-01-12T14:36:32Z</updated>
		
		<summary type="html">&lt;p&gt;Ильнар: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Задача&lt;br /&gt;
|definition =&lt;br /&gt;
Пусть у нас есть отсортированный по возрастанию алфавит &amp;lt;tex&amp;gt;\Sigma = \{a_1, a_2, \cdots, a_n\}&amp;lt;/tex&amp;gt;, &amp;lt;tex&amp;gt;|\Sigma| = n&amp;lt;/tex&amp;gt;. Где &amp;lt;tex&amp;gt;a_i&amp;lt;/tex&amp;gt; {{---}} число вхождений символа в строку.&lt;br /&gt;
Требуется построить код Хаффмана за &amp;lt;tex&amp;gt;O(n)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== Описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Eсли массив не отсортирован, то это можно сделать, например,[[Цифровая_сортировка | цифровой сортировкой]] за  &amp;lt;tex&amp;gt; O(n) &amp;lt;/tex&amp;gt;, что не ухудшит асимптотику.&lt;br /&gt;
&lt;br /&gt;
Идея алгоритма заключается в том, чтобы создать такую [[Дискретная_математика,_алгоритмы_и_структуры_данных#.D0.9F.D1.80.D0.B8.D0.BE.D1.80.D0.B8.D1.82.D0.B5.D1.82.D0.BD.D1.8B.D0.B5_.D0.BE.D1.87.D0.B5.D1.80.D0.B5.D0.B4.D0.B8 | очередь с приоритетами]], из которой можно было бы доставать два минимума за &amp;lt;tex&amp;gt; O(1) &amp;lt;/tex&amp;gt;, после чего в эту же очередь с приоритетами положить их сумму за &amp;lt;tex&amp;gt; O(1) &amp;lt;/tex&amp;gt;. У нас уже есть массив с отсортированными частотами, теперь давайте заведем второй массив, в котором мы будем хранить суммы. Несложно заметить, что в этом массиве элементы тоже будут идти по неубыванию. Допустим, что на каком-то шаге сумма получилась меньше чем предыдущая, но это противоречит тому, что на каждом шаге мы выбираем два минимальных. &lt;br /&gt;
На каждой итерации мы будет выбирать два минимума из четырех элементов (первые 2 элемента первого массива и первые 2 элемента второго массива). Теперь рассмотрим одну итерацию подробнее. &lt;br /&gt;
&lt;br /&gt;
У нас есть три варианта возможных пар минимумов :&lt;br /&gt;
# Оба элемента из первого массива.&lt;br /&gt;
# Первый элемент первого массива и первый элемент второго массива.&lt;br /&gt;
# Два первых элемента второго массива.&lt;br /&gt;
&lt;br /&gt;
Во всех случаях мы дописываем сумму в конец второго массива и передвигаем указатели в массивах на еще не использованные элементы. &lt;br /&gt;
&lt;br /&gt;
На каждом шаге количество элементов  уменьшается ровно на один, а минимум из 4-х элементов мы выбираем за константное время, следовательно, программа делает ровно &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt; итераций.&lt;br /&gt;
&lt;br /&gt;
==Пример==&lt;br /&gt;
Для примера возьмем строку &amp;quot;абракадабра&amp;quot;.&lt;br /&gt;
&amp;lt;tex&amp;gt;i, j&amp;lt;/tex&amp;gt; {{---}} указатели на первые неиспользованные элементы в массиве 1 и 2, соответственно.&lt;br /&gt;
 &lt;br /&gt;
&amp;lt;tex&amp;gt;i = 0, j = 0&amp;lt;/tex&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Буква || д || к || б || р || а&lt;br /&gt;
|-&lt;br /&gt;
| Массив 1 || 1 || 1 || 2 || 2 || 5&lt;br /&gt;
|}&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!   || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| Массив 2 || &amp;lt;tex&amp;gt;\infty&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;\infty&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;\infty&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;\infty&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;\infty&amp;lt;/tex&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
На первом шаге два минимальных элемента - это первые две ячейки первого массива. Их сумму сохраняем во второй массив.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;i = 2, j = 0&amp;lt;/tex&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Буква || д || к || б || р || а&lt;br /&gt;
|-&lt;br /&gt;
| Массив 1 || 1|| 1 || 2 || 2 || 5&lt;br /&gt;
|}&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!  || дк || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| Массив 2 || 2 || &amp;lt;tex&amp;gt;\infty&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;\infty&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;\infty&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;\infty&amp;lt;/tex&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
На втором шаге снова суммируются первые две ячейки первого массива(нам все равно что взять, первый элемент второго массива или второй элемент первого).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;i = 4, j = 0&amp;lt;/tex&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Буква || д || к || б || р || а&lt;br /&gt;
|-&lt;br /&gt;
| Массив 1 || 1|| 1 || 2 || 2 || 5&lt;br /&gt;
|}&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!  || дк || бр || || ||&lt;br /&gt;
|-&lt;br /&gt;
| Массив 2 || 2 || 4 || &amp;lt;tex&amp;gt;\infty&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;\infty&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;\infty&amp;lt;/tex&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
На третьем шаге два минимальных элемента - это первые две ячейки второго массива.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;i = 4, j = 2&amp;lt;/tex&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Буква || д || к || б || р || а&lt;br /&gt;
|-&lt;br /&gt;
| Массив 1 || 1 || 1|| 2|| 2|| 5&lt;br /&gt;
|}&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!  || дк || бр || дкбр || ||&lt;br /&gt;
|-&lt;br /&gt;
| Массив 2 || 2|| 4|| 6 || &amp;lt;tex&amp;gt;\infty&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;\infty&amp;lt;/tex&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
На четвертом шаге складываются две оставшиеся ячейки.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt; i = 5, j = 3&amp;lt;/tex&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Буква || д || к || б || р || а&lt;br /&gt;
|-&lt;br /&gt;
| Массив 1 || 1 || 1 || 2 || 2 || 5&lt;br /&gt;
|}&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!  || дк || бр || дкбр || адкбр ||&lt;br /&gt;
|-&lt;br /&gt;
| Массив 2 || 2 || 4 || 6 || 11 || &amp;lt;tex&amp;gt;\infty&amp;lt;/tex&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Псевдокод==&lt;br /&gt;
 '''int''' HuffmanCoding(a: '''int[0..n]'''):&lt;br /&gt;
    b: '''int[0..n]'''&lt;br /&gt;
    i, j, inf, ans: '''int''' ''&amp;lt;font color=green&amp;gt;// i, j {{---}} указатели в массивах, inf {{---}} большое число&amp;lt;/font&amp;gt;''&lt;br /&gt;
    '''for''' k = 0 '''to''' n&lt;br /&gt;
       b[k] = inf&lt;br /&gt;
    '''for''' k = 0 '''to''' n - 1&lt;br /&gt;
       '''if''' a[i] + a[i + 1] &amp;lt;= a[i] + b[j] &amp;amp;&amp;amp; a[i] + a[i + 1] &amp;lt;= b[j] + b[j + 1]&lt;br /&gt;
          b[k] = a[i] + a[i + 1]&lt;br /&gt;
          ans += b[k]&lt;br /&gt;
          i += 2&lt;br /&gt;
          '''continue'''&lt;br /&gt;
       '''if''' a[i] + b[j] &amp;lt;= a[i] + a[i + 1] &amp;amp;&amp;amp; a[i] + b[j] &amp;lt;= b[j] + b[j + 1]&lt;br /&gt;
          b[k] = a[i] + b[j]&lt;br /&gt;
          ans += b[k]&lt;br /&gt;
          i++&lt;br /&gt;
          j++&lt;br /&gt;
          '''continue'''&lt;br /&gt;
       '''if''' b[j] + b[j + 1] &amp;lt;= a[i] + a[i + 1] &amp;amp;&amp;amp; b[j] + b[j + 1] &amp;lt;= a[i] + b[j]&lt;br /&gt;
          b[k] = b[j] + b[j + 1]&lt;br /&gt;
          ans += b[k]&lt;br /&gt;
          j += 2&lt;br /&gt;
    '''return''' ans&lt;br /&gt;
==См. также==&lt;br /&gt;
*[[Алгоритм Хаффмана]]&lt;br /&gt;
*[[Оптимальное хранение словаря в алгоритме Хаффмана]]&lt;/div&gt;</summary>
		<author><name>Ильнар</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%A5%D0%B0%D1%84%D1%84%D0%BC%D0%B0%D0%BD%D0%B0_%D0%B7%D0%B0_O(n)&amp;diff=44293</id>
		<title>Алгоритм Хаффмана за O(n)</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%A5%D0%B0%D1%84%D1%84%D0%BC%D0%B0%D0%BD%D0%B0_%D0%B7%D0%B0_O(n)&amp;diff=44293"/>
				<updated>2015-01-12T13:50:05Z</updated>
		
		<summary type="html">&lt;p&gt;Ильнар: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Задача&lt;br /&gt;
|definition =&lt;br /&gt;
Пусть у нас есть отсортированный по возрастанию алфавит &amp;lt;tex&amp;gt;\Sigma = \{a_1, a_2, \cdots, a_n\}&amp;lt;/tex&amp;gt;, &amp;lt;tex&amp;gt;|\Sigma| = n&amp;lt;/tex&amp;gt;. Где &amp;lt;tex&amp;gt;a_i&amp;lt;/tex&amp;gt; {{---}} число вхождений символа в строку.&lt;br /&gt;
Требуется построить код Хаффмана за &amp;lt;tex&amp;gt;O(n)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== Описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Eсли массив не отсортирован, то это можно сделать, например,[[Цифровая_сортировка | цифровой сортировкой]] за  &amp;lt;tex&amp;gt; O(n) &amp;lt;/tex&amp;gt;, что не ухудшит асимптотику.&lt;br /&gt;
&lt;br /&gt;
Идея алгоритма заключается в том, чтобы создать такую [[Дискретная_математика,_алгоритмы_и_структуры_данных#.D0.9F.D1.80.D0.B8.D0.BE.D1.80.D0.B8.D1.82.D0.B5.D1.82.D0.BD.D1.8B.D0.B5_.D0.BE.D1.87.D0.B5.D1.80.D0.B5.D0.B4.D0.B8 | очередь с приоритетами]], из которой можно было бы доставать два минимума за &amp;lt;tex&amp;gt; O(1) &amp;lt;/tex&amp;gt;, после чего в эту же очередь с приоритетами положить их сумму за &amp;lt;tex&amp;gt; O(1) &amp;lt;/tex&amp;gt;. У нас уже есть массив с отсортированными частотами, теперь давайте заведем второй массив, в котором мы будем хранить суммы. Несложно заметить, что в этом массиве элементы тоже будут идти по неубыванию. Допустим, что на каком-то шаге сумма получилась меньше чем предыдущая, но это противоречит тому, что на каждом шаге мы выбираем два минимальных. &lt;br /&gt;
На каждой итерации мы будет выбирать два минимума из четырех элементов (первые 2 элемента первого массива и первые 2 элемента второго массива). Теперь рассмотрим одну итерацию подробнее. &lt;br /&gt;
&lt;br /&gt;
У нас есть три варианта возможных пар минимумов :&lt;br /&gt;
# Оба элемента из первого массива.&lt;br /&gt;
# Первый элемент первого массива и первый элемент второго массива.&lt;br /&gt;
# Два первых элемента второго массива.&lt;br /&gt;
&lt;br /&gt;
Во всех случаях мы дописываем сумму в конец второго массива и передвигаем указатели в массивах на еще не использованные элементы. &lt;br /&gt;
&lt;br /&gt;
На каждом шаге количество элементов  уменьшается ровно на один, а минимум из 4-х элементов мы выбираем за константное время, следовательно, программа делает ровно &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt; итераций.&lt;br /&gt;
&lt;br /&gt;
==Пример==&lt;br /&gt;
Для примера возьмем строку &amp;quot;абракадабра&amp;quot;.&lt;br /&gt;
&amp;lt;tex&amp;gt;i, j&amp;lt;/tex&amp;gt; {{---}} указатели на первые неиспользованные элементы в массиве 1 и 2, соответственно.&lt;br /&gt;
 &lt;br /&gt;
&amp;lt;tex&amp;gt;i = 0, j = 0&amp;lt;/tex&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Буква || д || к || б || р || а&lt;br /&gt;
|-&lt;br /&gt;
| Массив 1 || 1 || 1 || 2 || 2 || 5&lt;br /&gt;
|}&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!   || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| Массив 2 || &amp;lt;tex&amp;gt;\infty&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;\infty&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;\infty&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;\infty&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;\infty&amp;lt;/tex&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
На первом шаге два минимальных элемента - это первые две ячейки первого массива. Их сумму сохраняем во второй массив.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;i = 2, j = 0&amp;lt;/tex&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Буква || д || к || б || р || а&lt;br /&gt;
|-&lt;br /&gt;
| Массив 1 || 1|| 1 || 2 || 2 || 5&lt;br /&gt;
|}&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!  || дк || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| Массив 2 || 2 || &amp;lt;tex&amp;gt;\infty&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;\infty&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;\infty&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;\infty&amp;lt;/tex&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
На втором шаге снова суммируются первые две ячейки первого массива(нам все равно что взять, первый элемент второго массива или второй элемент первого).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;i = 4, j = 0&amp;lt;/tex&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Буква || д || к || б || р || а&lt;br /&gt;
|-&lt;br /&gt;
| Массив 1 || 1|| 1 || 2 || 2 || 5&lt;br /&gt;
|}&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!  || дк || бр || || ||&lt;br /&gt;
|-&lt;br /&gt;
| Массив 2 || 2 || 4 || &amp;lt;tex&amp;gt;\infty&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;\infty&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;\infty&amp;lt;/tex&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
На третьем шаге два минимальных элемента - это первые две ячейки второго массива.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;i = 4, j = 2&amp;lt;/tex&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Буква || д || к || б || р || а&lt;br /&gt;
|-&lt;br /&gt;
| Массив 1 || 1 || 1|| 2|| 2|| 5&lt;br /&gt;
|}&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!  || дк || бр || дкбр || ||&lt;br /&gt;
|-&lt;br /&gt;
| Массив 2 || 2|| 4|| 6 || &amp;lt;tex&amp;gt;\infty&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;\infty&amp;lt;/tex&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
На четвертом шаге складываются две оставшиеся ячейки.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt; i = 5, j = 3&amp;lt;/tex&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Буква || д || к || б || р || а&lt;br /&gt;
|-&lt;br /&gt;
| Массив 1 || 1 || 1 || 2 || 2 || 5&lt;br /&gt;
|}&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!  || дк || бр || дкбр || адкбр ||&lt;br /&gt;
|-&lt;br /&gt;
| Массив 2 || 2 || 4 || 6 || 11 || &amp;lt;tex&amp;gt;\infty&amp;lt;/tex&amp;gt;&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Ильнар</name></author>	</entry>

	</feed>