<?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=91.203.168.184&amp;*</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=91.203.168.184&amp;*"/>
		<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/91.203.168.184"/>
		<updated>2026-05-19T18:46:35Z</updated>
		<subtitle>Вклад участника</subtitle>
		<generator>MediaWiki 1.30.0</generator>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=C%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_%D1%81_%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5%D0%BC_O(1)_%D0%B4%D0%BE%D0%BF%D0%BE%D0%BB%D0%BD%D0%B8%D1%82%D0%B5%D0%BB%D1%8C%D0%BD%D0%BE%D0%B9_%D0%BF%D0%B0%D0%BC%D1%8F%D1%82%D0%B8&amp;diff=24590</id>
		<title>Cортировка слиянием с использованием O(1) дополнительной памяти</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=C%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_%D1%81_%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5%D0%BC_O(1)_%D0%B4%D0%BE%D0%BF%D0%BE%D0%BB%D0%BD%D0%B8%D1%82%D0%B5%D0%BB%D1%8C%D0%BD%D0%BE%D0%B9_%D0%BF%D0%B0%D0%BC%D1%8F%D1%82%D0%B8&amp;diff=24590"/>
				<updated>2012-06-09T14:03:33Z</updated>
		
		<summary type="html">&lt;p&gt;91.203.168.184: /* Алгоритм */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;На вход алгоритм получает массив, который состоит из двух отсортированных частей. Нам необходимо за &amp;lt;tex&amp;gt;O(1)&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;
&lt;br /&gt;
[[Файл:Merge_O(1)_1.png|525px]]&lt;br /&gt;
&lt;br /&gt;
Разобьем наш массив на &amp;lt;tex&amp;gt;cnt&amp;lt;/tex&amp;gt; подряд идущих блоков длиной &amp;lt;tex&amp;gt;len = \lfloor \sqrt{n} \rfloor &amp;lt;/tex&amp;gt;. Остаток трогать не будем. &lt;br /&gt;
&lt;br /&gt;
[[Файл:Merge_O(1)_2.png|525px]]&lt;br /&gt;
&lt;br /&gt;
Найдем блок, содержащий конец первой отсортированной части. Поменяем его с последним блоком. В дальнейшем будем использовать его как буфер обмена. &lt;br /&gt;
&lt;br /&gt;
[[Файл:Merge_O(1)_3.png|525px]]&lt;br /&gt;
&lt;br /&gt;
Отсортируем блоки по возрастанию по первому элементу (если первые элементы равны, тогда по последнему). Для этого подойдет любая квадратичная или более быстрая сортировка, которая требует &amp;lt;tex&amp;gt; O (1) &amp;lt;/tex&amp;gt; дополнительной памяти. Для линейной асимптотики надо использовать алгоритм, линейный по числу обменов, т.е. подходит [[Сортировка выбором|сортировка выбором]]. Следует заметить, что, после сортировки этих блоков, элементы, которые стоят левее заданного и больше его, находились в противоположной части отсортированного массива, также они находятся в пределах одной группы, поэтому количество инверсий для каждого элемента не больше &amp;lt;tex&amp;gt;\sqrt{n}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Так как блоков &amp;lt;tex&amp;gt; \sqrt{n} &amp;lt;/tex&amp;gt;, то количество операций на этом  шаге &amp;lt;tex&amp;gt; O(n) &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
[[Файл:Merge_O(1)_4.png|525px]]&lt;br /&gt;
&lt;br /&gt;
Пользуясь буфером обмена, последовательно сольем пары соседних блоков (процесс слияния блоков описан ниже) &amp;lt;tex&amp;gt;([0, ~ len - 1]&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;[len, ~ 2 ~ len - 1],&amp;lt;/tex&amp;gt; потом &amp;lt;tex&amp;gt;[len, ~ 2 ~ len - 1]&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;[2 ~ len, ~ 3 ~ len - 1],&amp;lt;/tex&amp;gt; и т.д.&amp;lt;tex&amp;gt;)&amp;lt;/tex&amp;gt;. Так как после предыдущего шага количество инверсий для каждого элемента не больше &amp;lt;tex&amp;gt;\sqrt{n}&amp;lt;/tex&amp;gt;, то ему надо сдвинуться влево не больше, чем на &amp;lt;tex&amp;gt;\sqrt{n}&amp;lt;/tex&amp;gt; элементов, поэтому в результате мы получим, что первые &amp;lt;tex&amp;gt;len \cdot (cnt - 1)&amp;lt;/tex&amp;gt; элементов исходного массива отсортированы.&lt;br /&gt;
&lt;br /&gt;
Количество блоков &amp;lt;tex&amp;gt; \sqrt{n} &amp;lt;/tex&amp;gt; и каждое слияние работает за &amp;lt;tex&amp;gt; О O(\sqrt{n}) &amp;lt;/tex&amp;gt; , поэтому количество операций на этом шаге &amp;lt;tex&amp;gt; O(n) &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
[[Файл:Merge_O(1)_5.png|525px]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;S&amp;lt;/tex&amp;gt; {{---}} размер остатка вместе с буфером. Используя квадратичную или более быструю сортировку, которая требует  &amp;lt;tex&amp;gt; O(1) &amp;lt;/tex&amp;gt; дополнительной памяти, отсортируем подмассив длиной &amp;lt;tex&amp;gt; 2S &amp;lt;/tex&amp;gt;, который находится в конце.&lt;br /&gt;
&lt;br /&gt;
Так как &amp;lt;tex&amp;gt;S &amp;lt; 2 \sqrt{n}&amp;lt;/tex&amp;gt;, то сортировка пройдет за &amp;lt;tex&amp;gt;O(n)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
[[Файл:Merge_O(1)_6.png|525px]]&lt;br /&gt;
&lt;br /&gt;
Теперь на последних &amp;lt;tex&amp;gt; S &amp;lt;/tex&amp;gt; местах будут находиться &amp;lt;tex&amp;gt; S &amp;lt;/tex&amp;gt; максимальных элементов. Оставшаяся часть представляет собой массив, содержащий две отсортированные части, причем размер второй равен &amp;lt;tex&amp;gt; S &amp;lt;/tex&amp;gt;. По аналогии с тем что делали раньше, только в обратную сторону, отсортируем оставшуюся часть, разделив ее на блоки длиной &amp;lt;tex&amp;gt;S&amp;lt;/tex&amp;gt;, используя последние &amp;lt;tex&amp;gt;S&amp;lt;/tex&amp;gt; как буфер обмена. Не забудем после отсортировать буфер обмена.&lt;br /&gt;
&lt;br /&gt;
[[Файл:Merge_O(1)_7.png|525px]]&lt;br /&gt;
&lt;br /&gt;
В результате мы получили отсортированный исходный массив.&lt;br /&gt;
&lt;br /&gt;
== Использование буфера обмена ==&lt;br /&gt;
Попытаемся слить первый и второй блок. Поменяем местами первый блок с буфером обмена. И, как в обычном слиянии, пользуясь двумя указателями, сливаем второй блок и только что измененный буфер. Результат начинаем записывать с начала первого блока. Чтобы не потерять данные, вместо записи используем обмен элементов. Так как блоки имеют одинаковую длину и между указателем на второй блок и указателем на запись расстояние равно длине блока, то слияние произойдет корректно.&lt;br /&gt;
&lt;br /&gt;
[[Файл:Merge_O(1)_buffer.png|355px]]&lt;br /&gt;
&lt;br /&gt;
== Ссылки и литература ==&lt;br /&gt;
*[http://habrahabr.ru/post/138146/ Сортировка слиянием без использования дополнительной памяти]&lt;br /&gt;
*[http://e-maxx.ru/bookz/files/knuth_3.djvu Д.Е.Кнут - Искусство программирования (том 3) упр 18 к разделу 5.2.4]&lt;br /&gt;
*[http://pastebin.com/hN2SnEfP  Реализация алгоритма на JAVA]&lt;br /&gt;
&lt;br /&gt;
[[Категория: Дискретная математика и алгоритмы]]&lt;br /&gt;
[[Категория: Сортировки]]&lt;/div&gt;</summary>
		<author><name>91.203.168.184</name></author>	</entry>

	</feed>