<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="ru">
	<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Ashabokov+415</id>
	<title>Алговики - Вклад [ru]</title>
	<link rel="self" type="application/atom+xml" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Ashabokov+415"/>
	<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/ru/%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/Ashabokov_415"/>
	<updated>2026-10-22T18:16:00Z</updated>
	<subtitle>Вклад</subtitle>
	<generator>MediaWiki 1.43.5</generator>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Ashabokov_415/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%B1%D1%8B%D1%81%D1%82%D1%80%D0%BE%D0%B9_%D1%81%D0%BE%D1%80%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B8&amp;diff=27644</id>
		<title>Участник:Ashabokov 415/Алгоритм быстрой сортировки</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Ashabokov_415/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%B1%D1%8B%D1%81%D1%82%D1%80%D0%BE%D0%B9_%D1%81%D0%BE%D1%80%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B8&amp;diff=27644"/>
		<updated>2019-12-02T15:08:42Z</updated>

		<summary type="html">&lt;p&gt;Ashabokov 415: /* Существующие реализации алгоритма */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&#039;&#039;&#039;Алгоритм быстрой сортировки&#039;&#039;&#039; &lt;br /&gt;
&lt;br /&gt;
== Свойства и структура алгоритмов ==&lt;br /&gt;
&lt;br /&gt;
=== Общее описание алгоритма &amp;lt;ref&amp;gt; https://en.wikipedia.org/wiki/Quicksort — From Wikipedia, the free encyclopedia &amp;lt;/ref&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
Быстрая сортировка, сортировка Хоара —  широко известный алгоритм сортировки, разработанный английским информатиком Чарльзом Хоаром во время его работы в МГУ в 1960 году.&lt;br /&gt;
&lt;br /&gt;
Один из самых быстрых известных универсальных алгоритмов сортировки массивов: в среднем  &amp;lt;math&amp;gt; O (n \log n) &amp;lt;/math&amp;gt; обменов при упорядочении &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; элементов; из-за наличия ряда недостатков на практике обычно используется с некоторыми доработками. Фактически данный алгоритм является улучшением алгоритма сортировки прямого обмена (см. ниже).&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
Алгоритм состоит из трех основных шагов:&lt;br /&gt;
&lt;br /&gt;
1. Выбрать опорный элемент (см. ниже). Пусть это будет элемент &amp;lt;math&amp;gt; a&#039; &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
2. Используя операции сравнения элементов массива с опорным и перестановки элементов массива, привести исходный массив к виду: &amp;lt;math&amp;gt; a_1 ... a_m a&#039; a_{m+2} ... a_n &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt; a_j &amp;lt; a&#039;, j = 1 ... m &amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt; a_i \geq a&#039;, i = (m+1) ... n  &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; — длина массива.&lt;br /&gt;
&lt;br /&gt;
3. Рекурсивно применить алгоритм к каждому из массивов: &amp;lt;math&amp;gt; a_1 ... a_m &amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt; a_{m+1} ... a_n &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Рассмотрим подробнее метод сравнения и перестановки данных в массиве, применяющийся на шаге 2. Для этого часто используют так называемое разбиение Хоара &amp;lt;ref&amp;gt; https://en.wikipedia.org/wiki/Quicksort — From Wikipedia, the free encyclopedia &amp;lt;/ref&amp;gt;. Суть данного метода заключается в следующем: выбираются два указателя, указывающие на первый и последний элементы массива соответственно, пусть для наглядности это будут &amp;lt;math&amp;gt; i = 1 &amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt; j = n &amp;lt;/math&amp;gt;. Далее начинаем сдвигать левый указатель вправо, а правый — влево до тех пор, пока выполнены условия: &amp;lt;math&amp;gt; a_i &amp;lt; a&#039;, a_j \geq a&#039;, i &amp;lt; j &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt; a&#039; &amp;lt;/math&amp;gt; — опорный элемент. Как только найдутся такие &amp;lt;math&amp;gt; i, j &amp;lt;/math&amp;gt;, что &amp;lt;math&amp;gt; a_i \geq a&#039;, a_j &amp;lt; a&#039; &amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt; i &amp;lt; j &amp;lt;/math&amp;gt;, производим перестановку этих двух элементов. Продолжаем этот процесс до тех пор, пока выполнено &amp;lt;math&amp;gt; i &amp;lt; j &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
Вычислительным ядром данного алгоритма являются операции сравнения и перестановки &amp;lt;math&amp;gt; i&amp;lt;/math&amp;gt;-ого и &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;-ого элементов массива на каждой итерации рекурсивного алгоритма.&lt;br /&gt;
&lt;br /&gt;
Сложность операции разделения массива на два подмассива (сравнение и перестановка элементов массива относительно опорного элемента) занимет время &amp;lt;math&amp;gt; O (log_2 n) &amp;lt;/math&amp;gt;. &amp;lt;ref&amp;gt; https://ru.wikipedia.org/wiki/Быстрая_сортировка &amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
Как и написано выше, в разделе &amp;quot;Вычислительное ядро алгоритма&amp;quot;, основную часть данного метода сортировки составляет операция разделения массива относительно опорного элемента, которая в свою очередь состоит из операций сравнения и перестановки.&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма ===&lt;br /&gt;
1. Случайным образом выбрать опорный элемент массива.&lt;br /&gt;
&lt;br /&gt;
2. Сравнить все элементы сортируемого массива с опорным и разделить исходный массив на два подмассива: с элементами меньше опорного и с элементами больше или равными опорному. &lt;br /&gt;
&lt;br /&gt;
3. Рекурсивно повторить алгоритм для получившихся подмассивов.&lt;br /&gt;
&lt;br /&gt;
Случайный выбор опорного элемента считается наиболее эффективным, так как при фиксировании позиции опорного элемента (например, в качестве опорного всегда берется элемент, стоящий на первой позиции) может привести к существенному снижению эффективности для массивов определенного вида из-за неравномерного распределения элементов в получившихся подмассивах. Также в качестве опорного элемента можно выбирать медиану массива, но считается, что вычисление медианы на каждой итерации рекурсивного алгоритма — слишком затратная операция.&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
Последовательная сложность данного алгоритма зависит от глубины рекурсии, что в свою очередь зависит от того, насколько удачно были выбраны опорные элементы на каждом витке рекурсии. Рассмотрим несколько возможных случаев.&lt;br /&gt;
&lt;br /&gt;
1. В наилучшем случае выбор опорного элемента на каждом витке рекурсии происходит таким образом, что в результате разбиения исходного массива образуются подмассивы одинаковой длины (с точностью до одного элемента). В таком случае глубина рекурсии составит &amp;lt;math&amp;gt; log_2 n &amp;lt;/math&amp;gt;, следовательно, общая сложность алгоритма равна &amp;lt;math&amp;gt; O(n log_2 n) &amp;lt;/math&amp;gt;. &amp;lt;ref&amp;gt; https://neerc.ifmo.ru/wiki/index.php?title=Быстрая_сортировка &amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
2. В наихудшем случае каждое разбиение приводит к образованию подмассивов длины &amp;lt;math&amp;gt; 1 &amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt; n - 1&amp;lt;/math&amp;gt; соответственно. Общая сложность алгоритма в таком случае равна &amp;lt;math&amp;gt; O(n^2) &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
Так как для проведения вычислений задействовано &amp;lt;math&amp;gt; p = 2^N &amp;lt;/math&amp;gt; процессоров, можно воспользоваться следующим алгоритмом распределения данных между процессорами. Распределим произвольным образом данные между процессорами, далее выбираем некоторым образом ведущий элемент и рассылаем его всем процессорам системы. Т.к. топология системы имеет вид n-мерного куба, номер каждого процессора имеет двоичное представление длины &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, следовательно, можно ввести правило: на каждом процессоре происходит сравнение имеющегося блока данных с текущим ведущим элементом, после чего элементы меньше ведущего отправляются от процессора с номером &amp;lt;math&amp;gt;n_1&amp;lt;/math&amp;gt; процессору номер &amp;lt;math&amp;gt;n_2&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;n_1&amp;lt;/math&amp;gt; отличается от &amp;lt;math&amp;gt;n_2&amp;lt;/math&amp;gt; только в n-том разряде двоичного представления, в двоичном представлении числа &amp;lt;math&amp;gt;n_1&amp;lt;/math&amp;gt; на n-той позиции стоит 1, а &amp;lt;math&amp;gt;n_2&amp;lt;/math&amp;gt; — &amp;lt;math&amp;gt;0&amp;lt;/math&amp;gt;. Таким образом, после данной операции все данные будут разделены между процессорами, образующими &amp;lt;math&amp;gt;n-1&amp;lt;/math&amp;gt;-мерные кубы таким образом, что элемент блока данных любого процессора из первого куба больше любого элемента блока данных процессора из второго куба. Повторив аналогичные действия для каждого из &amp;lt;math&amp;gt;n-1&amp;lt;/math&amp;gt;-мерных кубов, получим 4 &amp;lt;math&amp;gt;n-2&amp;lt;/math&amp;gt;-мерных куба и т.д. &lt;br /&gt;
&lt;br /&gt;
Для наглядности приведем пример: пусть &amp;lt;math&amp;gt; p = 2^3 = 8 &amp;lt;/math&amp;gt;. Ниже приведены графы, иллюстрирующие распределение данных на каждой итерации.&lt;br /&gt;
&lt;br /&gt;
[[file:Gr 1.png|thumb|center|700px|Рисунок 1. Итерация 1.]]&lt;br /&gt;
[[file:Gr 2.png|thumb|center|700px|Рисунок 2. Итерация 2.]]&lt;br /&gt;
[[file:Gr 3.png|thumb|center|700px|Рисунок 3. Итерация 3.]]&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма алгоритма ===&lt;br /&gt;
Основной идеей данного алгоритма является разбиение всего массива данных на блоки меньшего размера таким образом, что между соответствующими блоками после разбиения можно установить отношение упорядоченности. Сортировка производится следующим образом: выбирается некоторым образом ведущий элемент, после чего происходит разделение исходного массива данных на два блока относительно ведущего элемента: в первый блок помещаются элементы, меньшие ведущего, а во второй — большие ведущего. Таким образом, можно утверждать, что наибольший элемент первого блока меньше наименьшего элемента второго блока. Это означает, что повторив эту операцию для каждого из блоков отдельно некоторое количество раз и объединив результаты, получим массив с исходными данными в отсортированном виде. Из описания становится очевидно, что данный алгоритм можно легко обобщить для параллельной вычислительной системы с количеством процессоров &amp;lt;math&amp;gt;p = 2^n&amp;lt;/math&amp;gt;. Для этого алгоритм необходимо лишь дополнить методом выбора процессоров, между которыми будут происходить обмены данными на i-ом шаге. Подробное описание метода распределения данных между вычислительными узлами можно найти в разделе 1.7. Последним этапом работы алгоритма является объединение разрозненных блоков отсортированных данных в единый массив в правильном порядке. Порядок объединения не трудно восстановить исходя из двоичных представлений номеров процессоров.&lt;br /&gt;
&lt;br /&gt;
Очевидно, что наиболее медленной операцией в описанной выше схеме является операция обмена данными между процессорами, следовательно, хотелось бы получить некоторую оценку количества обменов. Такая оценка приведена ниже:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\sum_{i=1}^{n} i = n(n+1)/2 ≈ \log^2 p &amp;lt;/math&amp;gt; &amp;lt;ref&amp;gt; http://ssd.sscc.ru/ru — Supercomputer Software Department &amp;lt;/ref&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt; p &amp;lt;/math&amp;gt; — количество задействованных процессоров.&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные алгоритма ===&lt;br /&gt;
&#039;&#039;&#039;Входные данные:&#039;&#039;&#039; любая числовая последовательность произвольной конечной длины. Так как параллельный алгоритм предполагает выбор разделяющего элемента случайным образом, построение последовательностей специального вида не приводит к увеличению вероятности неравномерного распределения данных между вычислительными узлами. Это значит, что эффективность алгоритма не зависит от вида входной последовательности. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные:&#039;&#039;&#039; последовательность чисел в отсортированном виде.&lt;br /&gt;
&lt;br /&gt;
=== Свойства алгоритма ===&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Особенности реализации последовательного алгоритма ===&lt;br /&gt;
&lt;br /&gt;
=== Локальность данных и вычислений ===&lt;br /&gt;
&lt;br /&gt;
=== Возможные способы и особенности параллельной реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
=== Масштабируемость алгоритма и его реализация ===&lt;br /&gt;
Проведём исследование масштабируемости параллельной реализации алгоритма быстрой сортировки согласно [[Scalability methodology|методике]]. Исследование проводится для числа процессоров [8 : 128] с шагом 8.&lt;br /&gt;
&lt;br /&gt;
[[file:User ashabokov 415 eff.png|thumb|center|700px|Рисунок 4. Изменение эффективности в зависимости от числа процессоров и входных данных.]]&lt;br /&gt;
&lt;br /&gt;
Далее построим оценку масштабируемости:&lt;br /&gt;
&lt;br /&gt;
1. По числу процессоров: 1.0581. Это значит, что с увеличением количества задействованных процессоров эффективность увеличивается. Такое поведение можно объяснить тем, что при увеличении числа процессоров размер сортируемого участка массива для каждого отдельного процессора уменьшается.&lt;br /&gt;
&lt;br /&gt;
2. По числу входных данных: -0.6059. Это значит, что с ростом размеров входных данных эффективность алгоритма падает. Это можно объяснить тем, что при алгоритм предполагает многократный обмен массивами данных, а это значит, что при увеличении размера задачи накладные расходы на обмен данными между процессорами тоже сильно возрастает.&lt;br /&gt;
&lt;br /&gt;
3. По двум направлениям: 0.0386. Это значит, что с ростом числа процессоров и размерами входных данных эффективность все же возрастает, но скорость не слишком велика.&lt;br /&gt;
&lt;br /&gt;
=== Динамические характеристики и эффективность реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
=== Выводы для классов архитектур ===&lt;br /&gt;
&lt;br /&gt;
=== Существующие реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Реализация алгоритма быстрой сортировки имеется во многих стандартных библиотеках. Например, для языков программирования C и C++ этот алгоритм можно найти в стандартных библиотеках stdlib.h и cstdlib соответственно. В языке программирования Python имеется встроенная функция sorted(). Язык программирования Java содержит реализацию данного алгоритма в библиотеке java.util.&amp;lt;ref&amp;gt;https://docs.oracle.com/javase/7/docs/api/java/util/Arrays.html &amp;lt;/ref&amp;gt; Также реализацию этого алгоритма можно найти в пакете LAPACK DLASRT.&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;br /&gt;
&amp;lt;references /&amp;gt;&lt;/div&gt;</summary>
		<author><name>Ashabokov 415</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Ashabokov_415/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%B1%D1%8B%D1%81%D1%82%D1%80%D0%BE%D0%B9_%D1%81%D0%BE%D1%80%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B8&amp;diff=27643</id>
		<title>Участник:Ashabokov 415/Алгоритм быстрой сортировки</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Ashabokov_415/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%B1%D1%8B%D1%81%D1%82%D1%80%D0%BE%D0%B9_%D1%81%D0%BE%D1%80%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B8&amp;diff=27643"/>
		<updated>2019-12-02T15:08:10Z</updated>

		<summary type="html">&lt;p&gt;Ashabokov 415: /* Существующие реализации алгоритма */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&#039;&#039;&#039;Алгоритм быстрой сортировки&#039;&#039;&#039; &lt;br /&gt;
&lt;br /&gt;
== Свойства и структура алгоритмов ==&lt;br /&gt;
&lt;br /&gt;
=== Общее описание алгоритма &amp;lt;ref&amp;gt; https://en.wikipedia.org/wiki/Quicksort — From Wikipedia, the free encyclopedia &amp;lt;/ref&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
Быстрая сортировка, сортировка Хоара —  широко известный алгоритм сортировки, разработанный английским информатиком Чарльзом Хоаром во время его работы в МГУ в 1960 году.&lt;br /&gt;
&lt;br /&gt;
Один из самых быстрых известных универсальных алгоритмов сортировки массивов: в среднем  &amp;lt;math&amp;gt; O (n \log n) &amp;lt;/math&amp;gt; обменов при упорядочении &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; элементов; из-за наличия ряда недостатков на практике обычно используется с некоторыми доработками. Фактически данный алгоритм является улучшением алгоритма сортировки прямого обмена (см. ниже).&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
Алгоритм состоит из трех основных шагов:&lt;br /&gt;
&lt;br /&gt;
1. Выбрать опорный элемент (см. ниже). Пусть это будет элемент &amp;lt;math&amp;gt; a&#039; &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
2. Используя операции сравнения элементов массива с опорным и перестановки элементов массива, привести исходный массив к виду: &amp;lt;math&amp;gt; a_1 ... a_m a&#039; a_{m+2} ... a_n &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt; a_j &amp;lt; a&#039;, j = 1 ... m &amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt; a_i \geq a&#039;, i = (m+1) ... n  &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; — длина массива.&lt;br /&gt;
&lt;br /&gt;
3. Рекурсивно применить алгоритм к каждому из массивов: &amp;lt;math&amp;gt; a_1 ... a_m &amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt; a_{m+1} ... a_n &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Рассмотрим подробнее метод сравнения и перестановки данных в массиве, применяющийся на шаге 2. Для этого часто используют так называемое разбиение Хоара &amp;lt;ref&amp;gt; https://en.wikipedia.org/wiki/Quicksort — From Wikipedia, the free encyclopedia &amp;lt;/ref&amp;gt;. Суть данного метода заключается в следующем: выбираются два указателя, указывающие на первый и последний элементы массива соответственно, пусть для наглядности это будут &amp;lt;math&amp;gt; i = 1 &amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt; j = n &amp;lt;/math&amp;gt;. Далее начинаем сдвигать левый указатель вправо, а правый — влево до тех пор, пока выполнены условия: &amp;lt;math&amp;gt; a_i &amp;lt; a&#039;, a_j \geq a&#039;, i &amp;lt; j &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt; a&#039; &amp;lt;/math&amp;gt; — опорный элемент. Как только найдутся такие &amp;lt;math&amp;gt; i, j &amp;lt;/math&amp;gt;, что &amp;lt;math&amp;gt; a_i \geq a&#039;, a_j &amp;lt; a&#039; &amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt; i &amp;lt; j &amp;lt;/math&amp;gt;, производим перестановку этих двух элементов. Продолжаем этот процесс до тех пор, пока выполнено &amp;lt;math&amp;gt; i &amp;lt; j &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
Вычислительным ядром данного алгоритма являются операции сравнения и перестановки &amp;lt;math&amp;gt; i&amp;lt;/math&amp;gt;-ого и &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;-ого элементов массива на каждой итерации рекурсивного алгоритма.&lt;br /&gt;
&lt;br /&gt;
Сложность операции разделения массива на два подмассива (сравнение и перестановка элементов массива относительно опорного элемента) занимет время &amp;lt;math&amp;gt; O (log_2 n) &amp;lt;/math&amp;gt;. &amp;lt;ref&amp;gt; https://ru.wikipedia.org/wiki/Быстрая_сортировка &amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
Как и написано выше, в разделе &amp;quot;Вычислительное ядро алгоритма&amp;quot;, основную часть данного метода сортировки составляет операция разделения массива относительно опорного элемента, которая в свою очередь состоит из операций сравнения и перестановки.&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма ===&lt;br /&gt;
1. Случайным образом выбрать опорный элемент массива.&lt;br /&gt;
&lt;br /&gt;
2. Сравнить все элементы сортируемого массива с опорным и разделить исходный массив на два подмассива: с элементами меньше опорного и с элементами больше или равными опорному. &lt;br /&gt;
&lt;br /&gt;
3. Рекурсивно повторить алгоритм для получившихся подмассивов.&lt;br /&gt;
&lt;br /&gt;
Случайный выбор опорного элемента считается наиболее эффективным, так как при фиксировании позиции опорного элемента (например, в качестве опорного всегда берется элемент, стоящий на первой позиции) может привести к существенному снижению эффективности для массивов определенного вида из-за неравномерного распределения элементов в получившихся подмассивах. Также в качестве опорного элемента можно выбирать медиану массива, но считается, что вычисление медианы на каждой итерации рекурсивного алгоритма — слишком затратная операция.&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
Последовательная сложность данного алгоритма зависит от глубины рекурсии, что в свою очередь зависит от того, насколько удачно были выбраны опорные элементы на каждом витке рекурсии. Рассмотрим несколько возможных случаев.&lt;br /&gt;
&lt;br /&gt;
1. В наилучшем случае выбор опорного элемента на каждом витке рекурсии происходит таким образом, что в результате разбиения исходного массива образуются подмассивы одинаковой длины (с точностью до одного элемента). В таком случае глубина рекурсии составит &amp;lt;math&amp;gt; log_2 n &amp;lt;/math&amp;gt;, следовательно, общая сложность алгоритма равна &amp;lt;math&amp;gt; O(n log_2 n) &amp;lt;/math&amp;gt;. &amp;lt;ref&amp;gt; https://neerc.ifmo.ru/wiki/index.php?title=Быстрая_сортировка &amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
2. В наихудшем случае каждое разбиение приводит к образованию подмассивов длины &amp;lt;math&amp;gt; 1 &amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt; n - 1&amp;lt;/math&amp;gt; соответственно. Общая сложность алгоритма в таком случае равна &amp;lt;math&amp;gt; O(n^2) &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
Так как для проведения вычислений задействовано &amp;lt;math&amp;gt; p = 2^N &amp;lt;/math&amp;gt; процессоров, можно воспользоваться следующим алгоритмом распределения данных между процессорами. Распределим произвольным образом данные между процессорами, далее выбираем некоторым образом ведущий элемент и рассылаем его всем процессорам системы. Т.к. топология системы имеет вид n-мерного куба, номер каждого процессора имеет двоичное представление длины &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, следовательно, можно ввести правило: на каждом процессоре происходит сравнение имеющегося блока данных с текущим ведущим элементом, после чего элементы меньше ведущего отправляются от процессора с номером &amp;lt;math&amp;gt;n_1&amp;lt;/math&amp;gt; процессору номер &amp;lt;math&amp;gt;n_2&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;n_1&amp;lt;/math&amp;gt; отличается от &amp;lt;math&amp;gt;n_2&amp;lt;/math&amp;gt; только в n-том разряде двоичного представления, в двоичном представлении числа &amp;lt;math&amp;gt;n_1&amp;lt;/math&amp;gt; на n-той позиции стоит 1, а &amp;lt;math&amp;gt;n_2&amp;lt;/math&amp;gt; — &amp;lt;math&amp;gt;0&amp;lt;/math&amp;gt;. Таким образом, после данной операции все данные будут разделены между процессорами, образующими &amp;lt;math&amp;gt;n-1&amp;lt;/math&amp;gt;-мерные кубы таким образом, что элемент блока данных любого процессора из первого куба больше любого элемента блока данных процессора из второго куба. Повторив аналогичные действия для каждого из &amp;lt;math&amp;gt;n-1&amp;lt;/math&amp;gt;-мерных кубов, получим 4 &amp;lt;math&amp;gt;n-2&amp;lt;/math&amp;gt;-мерных куба и т.д. &lt;br /&gt;
&lt;br /&gt;
Для наглядности приведем пример: пусть &amp;lt;math&amp;gt; p = 2^3 = 8 &amp;lt;/math&amp;gt;. Ниже приведены графы, иллюстрирующие распределение данных на каждой итерации.&lt;br /&gt;
&lt;br /&gt;
[[file:Gr 1.png|thumb|center|700px|Рисунок 1. Итерация 1.]]&lt;br /&gt;
[[file:Gr 2.png|thumb|center|700px|Рисунок 2. Итерация 2.]]&lt;br /&gt;
[[file:Gr 3.png|thumb|center|700px|Рисунок 3. Итерация 3.]]&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма алгоритма ===&lt;br /&gt;
Основной идеей данного алгоритма является разбиение всего массива данных на блоки меньшего размера таким образом, что между соответствующими блоками после разбиения можно установить отношение упорядоченности. Сортировка производится следующим образом: выбирается некоторым образом ведущий элемент, после чего происходит разделение исходного массива данных на два блока относительно ведущего элемента: в первый блок помещаются элементы, меньшие ведущего, а во второй — большие ведущего. Таким образом, можно утверждать, что наибольший элемент первого блока меньше наименьшего элемента второго блока. Это означает, что повторив эту операцию для каждого из блоков отдельно некоторое количество раз и объединив результаты, получим массив с исходными данными в отсортированном виде. Из описания становится очевидно, что данный алгоритм можно легко обобщить для параллельной вычислительной системы с количеством процессоров &amp;lt;math&amp;gt;p = 2^n&amp;lt;/math&amp;gt;. Для этого алгоритм необходимо лишь дополнить методом выбора процессоров, между которыми будут происходить обмены данными на i-ом шаге. Подробное описание метода распределения данных между вычислительными узлами можно найти в разделе 1.7. Последним этапом работы алгоритма является объединение разрозненных блоков отсортированных данных в единый массив в правильном порядке. Порядок объединения не трудно восстановить исходя из двоичных представлений номеров процессоров.&lt;br /&gt;
&lt;br /&gt;
Очевидно, что наиболее медленной операцией в описанной выше схеме является операция обмена данными между процессорами, следовательно, хотелось бы получить некоторую оценку количества обменов. Такая оценка приведена ниже:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\sum_{i=1}^{n} i = n(n+1)/2 ≈ \log^2 p &amp;lt;/math&amp;gt; &amp;lt;ref&amp;gt; http://ssd.sscc.ru/ru — Supercomputer Software Department &amp;lt;/ref&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt; p &amp;lt;/math&amp;gt; — количество задействованных процессоров.&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные алгоритма ===&lt;br /&gt;
&#039;&#039;&#039;Входные данные:&#039;&#039;&#039; любая числовая последовательность произвольной конечной длины. Так как параллельный алгоритм предполагает выбор разделяющего элемента случайным образом, построение последовательностей специального вида не приводит к увеличению вероятности неравномерного распределения данных между вычислительными узлами. Это значит, что эффективность алгоритма не зависит от вида входной последовательности. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные:&#039;&#039;&#039; последовательность чисел в отсортированном виде.&lt;br /&gt;
&lt;br /&gt;
=== Свойства алгоритма ===&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Особенности реализации последовательного алгоритма ===&lt;br /&gt;
&lt;br /&gt;
=== Локальность данных и вычислений ===&lt;br /&gt;
&lt;br /&gt;
=== Возможные способы и особенности параллельной реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
=== Масштабируемость алгоритма и его реализация ===&lt;br /&gt;
Проведём исследование масштабируемости параллельной реализации алгоритма быстрой сортировки согласно [[Scalability methodology|методике]]. Исследование проводится для числа процессоров [8 : 128] с шагом 8.&lt;br /&gt;
&lt;br /&gt;
[[file:User ashabokov 415 eff.png|thumb|center|700px|Рисунок 4. Изменение эффективности в зависимости от числа процессоров и входных данных.]]&lt;br /&gt;
&lt;br /&gt;
Далее построим оценку масштабируемости:&lt;br /&gt;
&lt;br /&gt;
1. По числу процессоров: 1.0581. Это значит, что с увеличением количества задействованных процессоров эффективность увеличивается. Такое поведение можно объяснить тем, что при увеличении числа процессоров размер сортируемого участка массива для каждого отдельного процессора уменьшается.&lt;br /&gt;
&lt;br /&gt;
2. По числу входных данных: -0.6059. Это значит, что с ростом размеров входных данных эффективность алгоритма падает. Это можно объяснить тем, что при алгоритм предполагает многократный обмен массивами данных, а это значит, что при увеличении размера задачи накладные расходы на обмен данными между процессорами тоже сильно возрастает.&lt;br /&gt;
&lt;br /&gt;
3. По двум направлениям: 0.0386. Это значит, что с ростом числа процессоров и размерами входных данных эффективность все же возрастает, но скорость не слишком велика.&lt;br /&gt;
&lt;br /&gt;
=== Динамические характеристики и эффективность реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
=== Выводы для классов архитектур ===&lt;br /&gt;
&lt;br /&gt;
=== Существующие реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Реализация алгоритма быстрой сортировки имеется во многих стандартных библиотеках. Например, для языков программирования C и C++ этот алгоритм можно найти в стандартных библиотеках stdlib.h и cstdlib соответственно. В языке программирования Python имеется встроенная функция sorted(). Язык программирования Java содержит реализацию данного алгоритма в библиотеке java.util. Также реализацию этого алгоритма можно найти в пакете LAPACK DLASRT.&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;br /&gt;
&amp;lt;references /&amp;gt;&lt;/div&gt;</summary>
		<author><name>Ashabokov 415</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Ashabokov_415/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%B1%D1%8B%D1%81%D1%82%D1%80%D0%BE%D0%B9_%D1%81%D0%BE%D1%80%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B8&amp;diff=27642</id>
		<title>Участник:Ashabokov 415/Алгоритм быстрой сортировки</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Ashabokov_415/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%B1%D1%8B%D1%81%D1%82%D1%80%D0%BE%D0%B9_%D1%81%D0%BE%D1%80%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B8&amp;diff=27642"/>
		<updated>2019-12-02T14:53:56Z</updated>

		<summary type="html">&lt;p&gt;Ashabokov 415: /* Информационный граф */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&#039;&#039;&#039;Алгоритм быстрой сортировки&#039;&#039;&#039; &lt;br /&gt;
&lt;br /&gt;
== Свойства и структура алгоритмов ==&lt;br /&gt;
&lt;br /&gt;
=== Общее описание алгоритма &amp;lt;ref&amp;gt; https://en.wikipedia.org/wiki/Quicksort — From Wikipedia, the free encyclopedia &amp;lt;/ref&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
Быстрая сортировка, сортировка Хоара —  широко известный алгоритм сортировки, разработанный английским информатиком Чарльзом Хоаром во время его работы в МГУ в 1960 году.&lt;br /&gt;
&lt;br /&gt;
Один из самых быстрых известных универсальных алгоритмов сортировки массивов: в среднем  &amp;lt;math&amp;gt; O (n \log n) &amp;lt;/math&amp;gt; обменов при упорядочении &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; элементов; из-за наличия ряда недостатков на практике обычно используется с некоторыми доработками. Фактически данный алгоритм является улучшением алгоритма сортировки прямого обмена (см. ниже).&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
Алгоритм состоит из трех основных шагов:&lt;br /&gt;
&lt;br /&gt;
1. Выбрать опорный элемент (см. ниже). Пусть это будет элемент &amp;lt;math&amp;gt; a&#039; &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
2. Используя операции сравнения элементов массива с опорным и перестановки элементов массива, привести исходный массив к виду: &amp;lt;math&amp;gt; a_1 ... a_m a&#039; a_{m+2} ... a_n &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt; a_j &amp;lt; a&#039;, j = 1 ... m &amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt; a_i \geq a&#039;, i = (m+1) ... n  &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; — длина массива.&lt;br /&gt;
&lt;br /&gt;
3. Рекурсивно применить алгоритм к каждому из массивов: &amp;lt;math&amp;gt; a_1 ... a_m &amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt; a_{m+1} ... a_n &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Рассмотрим подробнее метод сравнения и перестановки данных в массиве, применяющийся на шаге 2. Для этого часто используют так называемое разбиение Хоара &amp;lt;ref&amp;gt; https://en.wikipedia.org/wiki/Quicksort — From Wikipedia, the free encyclopedia &amp;lt;/ref&amp;gt;. Суть данного метода заключается в следующем: выбираются два указателя, указывающие на первый и последний элементы массива соответственно, пусть для наглядности это будут &amp;lt;math&amp;gt; i = 1 &amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt; j = n &amp;lt;/math&amp;gt;. Далее начинаем сдвигать левый указатель вправо, а правый — влево до тех пор, пока выполнены условия: &amp;lt;math&amp;gt; a_i &amp;lt; a&#039;, a_j \geq a&#039;, i &amp;lt; j &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt; a&#039; &amp;lt;/math&amp;gt; — опорный элемент. Как только найдутся такие &amp;lt;math&amp;gt; i, j &amp;lt;/math&amp;gt;, что &amp;lt;math&amp;gt; a_i \geq a&#039;, a_j &amp;lt; a&#039; &amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt; i &amp;lt; j &amp;lt;/math&amp;gt;, производим перестановку этих двух элементов. Продолжаем этот процесс до тех пор, пока выполнено &amp;lt;math&amp;gt; i &amp;lt; j &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
Вычислительным ядром данного алгоритма являются операции сравнения и перестановки &amp;lt;math&amp;gt; i&amp;lt;/math&amp;gt;-ого и &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;-ого элементов массива на каждой итерации рекурсивного алгоритма.&lt;br /&gt;
&lt;br /&gt;
Сложность операции разделения массива на два подмассива (сравнение и перестановка элементов массива относительно опорного элемента) занимет время &amp;lt;math&amp;gt; O (log_2 n) &amp;lt;/math&amp;gt;. &amp;lt;ref&amp;gt; https://ru.wikipedia.org/wiki/Быстрая_сортировка &amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
Как и написано выше, в разделе &amp;quot;Вычислительное ядро алгоритма&amp;quot;, основную часть данного метода сортировки составляет операция разделения массива относительно опорного элемента, которая в свою очередь состоит из операций сравнения и перестановки.&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма ===&lt;br /&gt;
1. Случайным образом выбрать опорный элемент массива.&lt;br /&gt;
&lt;br /&gt;
2. Сравнить все элементы сортируемого массива с опорным и разделить исходный массив на два подмассива: с элементами меньше опорного и с элементами больше или равными опорному. &lt;br /&gt;
&lt;br /&gt;
3. Рекурсивно повторить алгоритм для получившихся подмассивов.&lt;br /&gt;
&lt;br /&gt;
Случайный выбор опорного элемента считается наиболее эффективным, так как при фиксировании позиции опорного элемента (например, в качестве опорного всегда берется элемент, стоящий на первой позиции) может привести к существенному снижению эффективности для массивов определенного вида из-за неравномерного распределения элементов в получившихся подмассивах. Также в качестве опорного элемента можно выбирать медиану массива, но считается, что вычисление медианы на каждой итерации рекурсивного алгоритма — слишком затратная операция.&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
Последовательная сложность данного алгоритма зависит от глубины рекурсии, что в свою очередь зависит от того, насколько удачно были выбраны опорные элементы на каждом витке рекурсии. Рассмотрим несколько возможных случаев.&lt;br /&gt;
&lt;br /&gt;
1. В наилучшем случае выбор опорного элемента на каждом витке рекурсии происходит таким образом, что в результате разбиения исходного массива образуются подмассивы одинаковой длины (с точностью до одного элемента). В таком случае глубина рекурсии составит &amp;lt;math&amp;gt; log_2 n &amp;lt;/math&amp;gt;, следовательно, общая сложность алгоритма равна &amp;lt;math&amp;gt; O(n log_2 n) &amp;lt;/math&amp;gt;. &amp;lt;ref&amp;gt; https://neerc.ifmo.ru/wiki/index.php?title=Быстрая_сортировка &amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
2. В наихудшем случае каждое разбиение приводит к образованию подмассивов длины &amp;lt;math&amp;gt; 1 &amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt; n - 1&amp;lt;/math&amp;gt; соответственно. Общая сложность алгоритма в таком случае равна &amp;lt;math&amp;gt; O(n^2) &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
Так как для проведения вычислений задействовано &amp;lt;math&amp;gt; p = 2^N &amp;lt;/math&amp;gt; процессоров, можно воспользоваться следующим алгоритмом распределения данных между процессорами. Распределим произвольным образом данные между процессорами, далее выбираем некоторым образом ведущий элемент и рассылаем его всем процессорам системы. Т.к. топология системы имеет вид n-мерного куба, номер каждого процессора имеет двоичное представление длины &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, следовательно, можно ввести правило: на каждом процессоре происходит сравнение имеющегося блока данных с текущим ведущим элементом, после чего элементы меньше ведущего отправляются от процессора с номером &amp;lt;math&amp;gt;n_1&amp;lt;/math&amp;gt; процессору номер &amp;lt;math&amp;gt;n_2&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;n_1&amp;lt;/math&amp;gt; отличается от &amp;lt;math&amp;gt;n_2&amp;lt;/math&amp;gt; только в n-том разряде двоичного представления, в двоичном представлении числа &amp;lt;math&amp;gt;n_1&amp;lt;/math&amp;gt; на n-той позиции стоит 1, а &amp;lt;math&amp;gt;n_2&amp;lt;/math&amp;gt; — &amp;lt;math&amp;gt;0&amp;lt;/math&amp;gt;. Таким образом, после данной операции все данные будут разделены между процессорами, образующими &amp;lt;math&amp;gt;n-1&amp;lt;/math&amp;gt;-мерные кубы таким образом, что элемент блока данных любого процессора из первого куба больше любого элемента блока данных процессора из второго куба. Повторив аналогичные действия для каждого из &amp;lt;math&amp;gt;n-1&amp;lt;/math&amp;gt;-мерных кубов, получим 4 &amp;lt;math&amp;gt;n-2&amp;lt;/math&amp;gt;-мерных куба и т.д. &lt;br /&gt;
&lt;br /&gt;
Для наглядности приведем пример: пусть &amp;lt;math&amp;gt; p = 2^3 = 8 &amp;lt;/math&amp;gt;. Ниже приведены графы, иллюстрирующие распределение данных на каждой итерации.&lt;br /&gt;
&lt;br /&gt;
[[file:Gr 1.png|thumb|center|700px|Рисунок 1. Итерация 1.]]&lt;br /&gt;
[[file:Gr 2.png|thumb|center|700px|Рисунок 2. Итерация 2.]]&lt;br /&gt;
[[file:Gr 3.png|thumb|center|700px|Рисунок 3. Итерация 3.]]&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма алгоритма ===&lt;br /&gt;
Основной идеей данного алгоритма является разбиение всего массива данных на блоки меньшего размера таким образом, что между соответствующими блоками после разбиения можно установить отношение упорядоченности. Сортировка производится следующим образом: выбирается некоторым образом ведущий элемент, после чего происходит разделение исходного массива данных на два блока относительно ведущего элемента: в первый блок помещаются элементы, меньшие ведущего, а во второй — большие ведущего. Таким образом, можно утверждать, что наибольший элемент первого блока меньше наименьшего элемента второго блока. Это означает, что повторив эту операцию для каждого из блоков отдельно некоторое количество раз и объединив результаты, получим массив с исходными данными в отсортированном виде. Из описания становится очевидно, что данный алгоритм можно легко обобщить для параллельной вычислительной системы с количеством процессоров &amp;lt;math&amp;gt;p = 2^n&amp;lt;/math&amp;gt;. Для этого алгоритм необходимо лишь дополнить методом выбора процессоров, между которыми будут происходить обмены данными на i-ом шаге. Подробное описание метода распределения данных между вычислительными узлами можно найти в разделе 1.7. Последним этапом работы алгоритма является объединение разрозненных блоков отсортированных данных в единый массив в правильном порядке. Порядок объединения не трудно восстановить исходя из двоичных представлений номеров процессоров.&lt;br /&gt;
&lt;br /&gt;
Очевидно, что наиболее медленной операцией в описанной выше схеме является операция обмена данными между процессорами, следовательно, хотелось бы получить некоторую оценку количества обменов. Такая оценка приведена ниже:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\sum_{i=1}^{n} i = n(n+1)/2 ≈ \log^2 p &amp;lt;/math&amp;gt; &amp;lt;ref&amp;gt; http://ssd.sscc.ru/ru — Supercomputer Software Department &amp;lt;/ref&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt; p &amp;lt;/math&amp;gt; — количество задействованных процессоров.&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные алгоритма ===&lt;br /&gt;
&#039;&#039;&#039;Входные данные:&#039;&#039;&#039; любая числовая последовательность произвольной конечной длины. Так как параллельный алгоритм предполагает выбор разделяющего элемента случайным образом, построение последовательностей специального вида не приводит к увеличению вероятности неравномерного распределения данных между вычислительными узлами. Это значит, что эффективность алгоритма не зависит от вида входной последовательности. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные:&#039;&#039;&#039; последовательность чисел в отсортированном виде.&lt;br /&gt;
&lt;br /&gt;
=== Свойства алгоритма ===&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Особенности реализации последовательного алгоритма ===&lt;br /&gt;
&lt;br /&gt;
=== Локальность данных и вычислений ===&lt;br /&gt;
&lt;br /&gt;
=== Возможные способы и особенности параллельной реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
=== Масштабируемость алгоритма и его реализация ===&lt;br /&gt;
Проведём исследование масштабируемости параллельной реализации алгоритма быстрой сортировки согласно [[Scalability methodology|методике]]. Исследование проводится для числа процессоров [8 : 128] с шагом 8.&lt;br /&gt;
&lt;br /&gt;
[[file:User ashabokov 415 eff.png|thumb|center|700px|Рисунок 4. Изменение эффективности в зависимости от числа процессоров и входных данных.]]&lt;br /&gt;
&lt;br /&gt;
Далее построим оценку масштабируемости:&lt;br /&gt;
&lt;br /&gt;
1. По числу процессоров: 1.0581. Это значит, что с увеличением количества задействованных процессоров эффективность увеличивается. Такое поведение можно объяснить тем, что при увеличении числа процессоров размер сортируемого участка массива для каждого отдельного процессора уменьшается.&lt;br /&gt;
&lt;br /&gt;
2. По числу входных данных: -0.6059. Это значит, что с ростом размеров входных данных эффективность алгоритма падает. Это можно объяснить тем, что при алгоритм предполагает многократный обмен массивами данных, а это значит, что при увеличении размера задачи накладные расходы на обмен данными между процессорами тоже сильно возрастает.&lt;br /&gt;
&lt;br /&gt;
3. По двум направлениям: 0.0386. Это значит, что с ростом числа процессоров и размерами входных данных эффективность все же возрастает, но скорость не слишком велика.&lt;br /&gt;
&lt;br /&gt;
=== Динамические характеристики и эффективность реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
=== Выводы для классов архитектур ===&lt;br /&gt;
&lt;br /&gt;
=== Существующие реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Реализация алгоритма быстрой сортировки имеется во многих стандартных библиотеках. Например, для языков программирования C и C++ этот алгоритм можно найти в стандартных библиотеках stdlib.h и cstdlib соответственно. В языке программирования Python имеется встроенная функция sorted(). Также реализацию этого алгоритма можно найти в пакете LAPACK DLASRT.&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;br /&gt;
&amp;lt;references /&amp;gt;&lt;/div&gt;</summary>
		<author><name>Ashabokov 415</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Ashabokov_415/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%B1%D1%8B%D1%81%D1%82%D1%80%D0%BE%D0%B9_%D1%81%D0%BE%D1%80%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B8&amp;diff=27641</id>
		<title>Участник:Ashabokov 415/Алгоритм быстрой сортировки</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Ashabokov_415/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%B1%D1%8B%D1%81%D1%82%D1%80%D0%BE%D0%B9_%D1%81%D0%BE%D1%80%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B8&amp;diff=27641"/>
		<updated>2019-12-02T14:53:29Z</updated>

		<summary type="html">&lt;p&gt;Ashabokov 415: /* Информационный граф */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&#039;&#039;&#039;Алгоритм быстрой сортировки&#039;&#039;&#039; &lt;br /&gt;
&lt;br /&gt;
== Свойства и структура алгоритмов ==&lt;br /&gt;
&lt;br /&gt;
=== Общее описание алгоритма &amp;lt;ref&amp;gt; https://en.wikipedia.org/wiki/Quicksort — From Wikipedia, the free encyclopedia &amp;lt;/ref&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
Быстрая сортировка, сортировка Хоара —  широко известный алгоритм сортировки, разработанный английским информатиком Чарльзом Хоаром во время его работы в МГУ в 1960 году.&lt;br /&gt;
&lt;br /&gt;
Один из самых быстрых известных универсальных алгоритмов сортировки массивов: в среднем  &amp;lt;math&amp;gt; O (n \log n) &amp;lt;/math&amp;gt; обменов при упорядочении &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; элементов; из-за наличия ряда недостатков на практике обычно используется с некоторыми доработками. Фактически данный алгоритм является улучшением алгоритма сортировки прямого обмена (см. ниже).&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
Алгоритм состоит из трех основных шагов:&lt;br /&gt;
&lt;br /&gt;
1. Выбрать опорный элемент (см. ниже). Пусть это будет элемент &amp;lt;math&amp;gt; a&#039; &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
2. Используя операции сравнения элементов массива с опорным и перестановки элементов массива, привести исходный массив к виду: &amp;lt;math&amp;gt; a_1 ... a_m a&#039; a_{m+2} ... a_n &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt; a_j &amp;lt; a&#039;, j = 1 ... m &amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt; a_i \geq a&#039;, i = (m+1) ... n  &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; — длина массива.&lt;br /&gt;
&lt;br /&gt;
3. Рекурсивно применить алгоритм к каждому из массивов: &amp;lt;math&amp;gt; a_1 ... a_m &amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt; a_{m+1} ... a_n &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Рассмотрим подробнее метод сравнения и перестановки данных в массиве, применяющийся на шаге 2. Для этого часто используют так называемое разбиение Хоара &amp;lt;ref&amp;gt; https://en.wikipedia.org/wiki/Quicksort — From Wikipedia, the free encyclopedia &amp;lt;/ref&amp;gt;. Суть данного метода заключается в следующем: выбираются два указателя, указывающие на первый и последний элементы массива соответственно, пусть для наглядности это будут &amp;lt;math&amp;gt; i = 1 &amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt; j = n &amp;lt;/math&amp;gt;. Далее начинаем сдвигать левый указатель вправо, а правый — влево до тех пор, пока выполнены условия: &amp;lt;math&amp;gt; a_i &amp;lt; a&#039;, a_j \geq a&#039;, i &amp;lt; j &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt; a&#039; &amp;lt;/math&amp;gt; — опорный элемент. Как только найдутся такие &amp;lt;math&amp;gt; i, j &amp;lt;/math&amp;gt;, что &amp;lt;math&amp;gt; a_i \geq a&#039;, a_j &amp;lt; a&#039; &amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt; i &amp;lt; j &amp;lt;/math&amp;gt;, производим перестановку этих двух элементов. Продолжаем этот процесс до тех пор, пока выполнено &amp;lt;math&amp;gt; i &amp;lt; j &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
Вычислительным ядром данного алгоритма являются операции сравнения и перестановки &amp;lt;math&amp;gt; i&amp;lt;/math&amp;gt;-ого и &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;-ого элементов массива на каждой итерации рекурсивного алгоритма.&lt;br /&gt;
&lt;br /&gt;
Сложность операции разделения массива на два подмассива (сравнение и перестановка элементов массива относительно опорного элемента) занимет время &amp;lt;math&amp;gt; O (log_2 n) &amp;lt;/math&amp;gt;. &amp;lt;ref&amp;gt; https://ru.wikipedia.org/wiki/Быстрая_сортировка &amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
Как и написано выше, в разделе &amp;quot;Вычислительное ядро алгоритма&amp;quot;, основную часть данного метода сортировки составляет операция разделения массива относительно опорного элемента, которая в свою очередь состоит из операций сравнения и перестановки.&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма ===&lt;br /&gt;
1. Случайным образом выбрать опорный элемент массива.&lt;br /&gt;
&lt;br /&gt;
2. Сравнить все элементы сортируемого массива с опорным и разделить исходный массив на два подмассива: с элементами меньше опорного и с элементами больше или равными опорному. &lt;br /&gt;
&lt;br /&gt;
3. Рекурсивно повторить алгоритм для получившихся подмассивов.&lt;br /&gt;
&lt;br /&gt;
Случайный выбор опорного элемента считается наиболее эффективным, так как при фиксировании позиции опорного элемента (например, в качестве опорного всегда берется элемент, стоящий на первой позиции) может привести к существенному снижению эффективности для массивов определенного вида из-за неравномерного распределения элементов в получившихся подмассивах. Также в качестве опорного элемента можно выбирать медиану массива, но считается, что вычисление медианы на каждой итерации рекурсивного алгоритма — слишком затратная операция.&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
Последовательная сложность данного алгоритма зависит от глубины рекурсии, что в свою очередь зависит от того, насколько удачно были выбраны опорные элементы на каждом витке рекурсии. Рассмотрим несколько возможных случаев.&lt;br /&gt;
&lt;br /&gt;
1. В наилучшем случае выбор опорного элемента на каждом витке рекурсии происходит таким образом, что в результате разбиения исходного массива образуются подмассивы одинаковой длины (с точностью до одного элемента). В таком случае глубина рекурсии составит &amp;lt;math&amp;gt; log_2 n &amp;lt;/math&amp;gt;, следовательно, общая сложность алгоритма равна &amp;lt;math&amp;gt; O(n log_2 n) &amp;lt;/math&amp;gt;. &amp;lt;ref&amp;gt; https://neerc.ifmo.ru/wiki/index.php?title=Быстрая_сортировка &amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
2. В наихудшем случае каждое разбиение приводит к образованию подмассивов длины &amp;lt;math&amp;gt; 1 &amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt; n - 1&amp;lt;/math&amp;gt; соответственно. Общая сложность алгоритма в таком случае равна &amp;lt;math&amp;gt; O(n^2) &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
Так как для проведения вычислений задействовано &amp;lt;math&amp;gt; p = 2^N &amp;lt;/math&amp;gt; процессоров, можно воспользоваться следующим алгоритмом распределения данных между процессорами. Распределим произвольным образом данные между процессорами, далее выбираем некоторым образом ведущий элемент и рассылаем его всем процессорам системы. Т.к. топология системы имеет вид n-мерного куба, номер каждого процессора имеет двоичное представление длины &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, следовательно, можно ввести правило: на каждом процессоре происходит сравнение имеющегося блока данных с текущим ведущим элементом, после чего элементы меньше ведущего отправляются от процессора с номером &amp;lt;math&amp;gt;n_1&amp;lt;/math&amp;gt; процессору номер &amp;lt;math&amp;gt;n_2&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;n_1&amp;lt;/math&amp;gt; отличается от &amp;lt;math&amp;gt;n_2&amp;lt;/math&amp;gt; только в n-том разряде двоичного представления, в двоичном представлении числа &amp;lt;math&amp;gt;n_1&amp;lt;/math&amp;gt; на n-той позиции стоит 1, а &amp;lt;math&amp;gt;n_2&amp;lt;/math&amp;gt; — 0. Таким образом, после данной операции все данные будут разделены между процессорами, образующими &amp;lt;math&amp;gt;n-1&amp;lt;/math&amp;gt;-мерные кубы таким образом, что элемент блока данных любого процессора из первого куба больше любого элемента блока данных процессора из второго куба. Повторив аналогичные действия для каждого из &amp;lt;math&amp;gt;n-1&amp;lt;/math&amp;gt;-мерных кубов, получим 4 &amp;lt;math&amp;gt;n-2&amp;lt;/math&amp;gt;-мерных куба и т.д. &lt;br /&gt;
&lt;br /&gt;
Для наглядности приведем пример: пусть &amp;lt;math&amp;gt; p = 2^3 = 8 &amp;lt;/math&amp;gt;. Ниже приведены графы, иллюстрирующие распределение данных на каждой итерации.&lt;br /&gt;
&lt;br /&gt;
[[file:Gr 1.png|thumb|center|700px|Рисунок 1. Итерация 1.]]&lt;br /&gt;
[[file:Gr 2.png|thumb|center|700px|Рисунок 2. Итерация 2.]]&lt;br /&gt;
[[file:Gr 3.png|thumb|center|700px|Рисунок 3. Итерация 3.]]&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма алгоритма ===&lt;br /&gt;
Основной идеей данного алгоритма является разбиение всего массива данных на блоки меньшего размера таким образом, что между соответствующими блоками после разбиения можно установить отношение упорядоченности. Сортировка производится следующим образом: выбирается некоторым образом ведущий элемент, после чего происходит разделение исходного массива данных на два блока относительно ведущего элемента: в первый блок помещаются элементы, меньшие ведущего, а во второй — большие ведущего. Таким образом, можно утверждать, что наибольший элемент первого блока меньше наименьшего элемента второго блока. Это означает, что повторив эту операцию для каждого из блоков отдельно некоторое количество раз и объединив результаты, получим массив с исходными данными в отсортированном виде. Из описания становится очевидно, что данный алгоритм можно легко обобщить для параллельной вычислительной системы с количеством процессоров &amp;lt;math&amp;gt;p = 2^n&amp;lt;/math&amp;gt;. Для этого алгоритм необходимо лишь дополнить методом выбора процессоров, между которыми будут происходить обмены данными на i-ом шаге. Подробное описание метода распределения данных между вычислительными узлами можно найти в разделе 1.7. Последним этапом работы алгоритма является объединение разрозненных блоков отсортированных данных в единый массив в правильном порядке. Порядок объединения не трудно восстановить исходя из двоичных представлений номеров процессоров.&lt;br /&gt;
&lt;br /&gt;
Очевидно, что наиболее медленной операцией в описанной выше схеме является операция обмена данными между процессорами, следовательно, хотелось бы получить некоторую оценку количества обменов. Такая оценка приведена ниже:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\sum_{i=1}^{n} i = n(n+1)/2 ≈ \log^2 p &amp;lt;/math&amp;gt; &amp;lt;ref&amp;gt; http://ssd.sscc.ru/ru — Supercomputer Software Department &amp;lt;/ref&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt; p &amp;lt;/math&amp;gt; — количество задействованных процессоров.&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные алгоритма ===&lt;br /&gt;
&#039;&#039;&#039;Входные данные:&#039;&#039;&#039; любая числовая последовательность произвольной конечной длины. Так как параллельный алгоритм предполагает выбор разделяющего элемента случайным образом, построение последовательностей специального вида не приводит к увеличению вероятности неравномерного распределения данных между вычислительными узлами. Это значит, что эффективность алгоритма не зависит от вида входной последовательности. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные:&#039;&#039;&#039; последовательность чисел в отсортированном виде.&lt;br /&gt;
&lt;br /&gt;
=== Свойства алгоритма ===&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Особенности реализации последовательного алгоритма ===&lt;br /&gt;
&lt;br /&gt;
=== Локальность данных и вычислений ===&lt;br /&gt;
&lt;br /&gt;
=== Возможные способы и особенности параллельной реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
=== Масштабируемость алгоритма и его реализация ===&lt;br /&gt;
Проведём исследование масштабируемости параллельной реализации алгоритма быстрой сортировки согласно [[Scalability methodology|методике]]. Исследование проводится для числа процессоров [8 : 128] с шагом 8.&lt;br /&gt;
&lt;br /&gt;
[[file:User ashabokov 415 eff.png|thumb|center|700px|Рисунок 4. Изменение эффективности в зависимости от числа процессоров и входных данных.]]&lt;br /&gt;
&lt;br /&gt;
Далее построим оценку масштабируемости:&lt;br /&gt;
&lt;br /&gt;
1. По числу процессоров: 1.0581. Это значит, что с увеличением количества задействованных процессоров эффективность увеличивается. Такое поведение можно объяснить тем, что при увеличении числа процессоров размер сортируемого участка массива для каждого отдельного процессора уменьшается.&lt;br /&gt;
&lt;br /&gt;
2. По числу входных данных: -0.6059. Это значит, что с ростом размеров входных данных эффективность алгоритма падает. Это можно объяснить тем, что при алгоритм предполагает многократный обмен массивами данных, а это значит, что при увеличении размера задачи накладные расходы на обмен данными между процессорами тоже сильно возрастает.&lt;br /&gt;
&lt;br /&gt;
3. По двум направлениям: 0.0386. Это значит, что с ростом числа процессоров и размерами входных данных эффективность все же возрастает, но скорость не слишком велика.&lt;br /&gt;
&lt;br /&gt;
=== Динамические характеристики и эффективность реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
=== Выводы для классов архитектур ===&lt;br /&gt;
&lt;br /&gt;
=== Существующие реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Реализация алгоритма быстрой сортировки имеется во многих стандартных библиотеках. Например, для языков программирования C и C++ этот алгоритм можно найти в стандартных библиотеках stdlib.h и cstdlib соответственно. В языке программирования Python имеется встроенная функция sorted(). Также реализацию этого алгоритма можно найти в пакете LAPACK DLASRT.&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;br /&gt;
&amp;lt;references /&amp;gt;&lt;/div&gt;</summary>
		<author><name>Ashabokov 415</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Ashabokov_415/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%B1%D1%8B%D1%81%D1%82%D1%80%D0%BE%D0%B9_%D1%81%D0%BE%D1%80%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B8&amp;diff=27640</id>
		<title>Участник:Ashabokov 415/Алгоритм быстрой сортировки</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Ashabokov_415/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%B1%D1%8B%D1%81%D1%82%D1%80%D0%BE%D0%B9_%D1%81%D0%BE%D1%80%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B8&amp;diff=27640"/>
		<updated>2019-12-02T14:48:37Z</updated>

		<summary type="html">&lt;p&gt;Ashabokov 415: /* Схема реализации последовательного алгоритма */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&#039;&#039;&#039;Алгоритм быстрой сортировки&#039;&#039;&#039; &lt;br /&gt;
&lt;br /&gt;
== Свойства и структура алгоритмов ==&lt;br /&gt;
&lt;br /&gt;
=== Общее описание алгоритма &amp;lt;ref&amp;gt; https://en.wikipedia.org/wiki/Quicksort — From Wikipedia, the free encyclopedia &amp;lt;/ref&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
Быстрая сортировка, сортировка Хоара —  широко известный алгоритм сортировки, разработанный английским информатиком Чарльзом Хоаром во время его работы в МГУ в 1960 году.&lt;br /&gt;
&lt;br /&gt;
Один из самых быстрых известных универсальных алгоритмов сортировки массивов: в среднем  &amp;lt;math&amp;gt; O (n \log n) &amp;lt;/math&amp;gt; обменов при упорядочении &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; элементов; из-за наличия ряда недостатков на практике обычно используется с некоторыми доработками. Фактически данный алгоритм является улучшением алгоритма сортировки прямого обмена (см. ниже).&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
Алгоритм состоит из трех основных шагов:&lt;br /&gt;
&lt;br /&gt;
1. Выбрать опорный элемент (см. ниже). Пусть это будет элемент &amp;lt;math&amp;gt; a&#039; &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
2. Используя операции сравнения элементов массива с опорным и перестановки элементов массива, привести исходный массив к виду: &amp;lt;math&amp;gt; a_1 ... a_m a&#039; a_{m+2} ... a_n &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt; a_j &amp;lt; a&#039;, j = 1 ... m &amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt; a_i \geq a&#039;, i = (m+1) ... n  &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; — длина массива.&lt;br /&gt;
&lt;br /&gt;
3. Рекурсивно применить алгоритм к каждому из массивов: &amp;lt;math&amp;gt; a_1 ... a_m &amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt; a_{m+1} ... a_n &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Рассмотрим подробнее метод сравнения и перестановки данных в массиве, применяющийся на шаге 2. Для этого часто используют так называемое разбиение Хоара &amp;lt;ref&amp;gt; https://en.wikipedia.org/wiki/Quicksort — From Wikipedia, the free encyclopedia &amp;lt;/ref&amp;gt;. Суть данного метода заключается в следующем: выбираются два указателя, указывающие на первый и последний элементы массива соответственно, пусть для наглядности это будут &amp;lt;math&amp;gt; i = 1 &amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt; j = n &amp;lt;/math&amp;gt;. Далее начинаем сдвигать левый указатель вправо, а правый — влево до тех пор, пока выполнены условия: &amp;lt;math&amp;gt; a_i &amp;lt; a&#039;, a_j \geq a&#039;, i &amp;lt; j &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt; a&#039; &amp;lt;/math&amp;gt; — опорный элемент. Как только найдутся такие &amp;lt;math&amp;gt; i, j &amp;lt;/math&amp;gt;, что &amp;lt;math&amp;gt; a_i \geq a&#039;, a_j &amp;lt; a&#039; &amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt; i &amp;lt; j &amp;lt;/math&amp;gt;, производим перестановку этих двух элементов. Продолжаем этот процесс до тех пор, пока выполнено &amp;lt;math&amp;gt; i &amp;lt; j &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
Вычислительным ядром данного алгоритма являются операции сравнения и перестановки &amp;lt;math&amp;gt; i&amp;lt;/math&amp;gt;-ого и &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;-ого элементов массива на каждой итерации рекурсивного алгоритма.&lt;br /&gt;
&lt;br /&gt;
Сложность операции разделения массива на два подмассива (сравнение и перестановка элементов массива относительно опорного элемента) занимет время &amp;lt;math&amp;gt; O (log_2 n) &amp;lt;/math&amp;gt;. &amp;lt;ref&amp;gt; https://ru.wikipedia.org/wiki/Быстрая_сортировка &amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
Как и написано выше, в разделе &amp;quot;Вычислительное ядро алгоритма&amp;quot;, основную часть данного метода сортировки составляет операция разделения массива относительно опорного элемента, которая в свою очередь состоит из операций сравнения и перестановки.&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма ===&lt;br /&gt;
1. Случайным образом выбрать опорный элемент массива.&lt;br /&gt;
&lt;br /&gt;
2. Сравнить все элементы сортируемого массива с опорным и разделить исходный массив на два подмассива: с элементами меньше опорного и с элементами больше или равными опорному. &lt;br /&gt;
&lt;br /&gt;
3. Рекурсивно повторить алгоритм для получившихся подмассивов.&lt;br /&gt;
&lt;br /&gt;
Случайный выбор опорного элемента считается наиболее эффективным, так как при фиксировании позиции опорного элемента (например, в качестве опорного всегда берется элемент, стоящий на первой позиции) может привести к существенному снижению эффективности для массивов определенного вида из-за неравномерного распределения элементов в получившихся подмассивах. Также в качестве опорного элемента можно выбирать медиану массива, но считается, что вычисление медианы на каждой итерации рекурсивного алгоритма — слишком затратная операция.&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
Последовательная сложность данного алгоритма зависит от глубины рекурсии, что в свою очередь зависит от того, насколько удачно были выбраны опорные элементы на каждом витке рекурсии. Рассмотрим несколько возможных случаев.&lt;br /&gt;
&lt;br /&gt;
1. В наилучшем случае выбор опорного элемента на каждом витке рекурсии происходит таким образом, что в результате разбиения исходного массива образуются подмассивы одинаковой длины (с точностью до одного элемента). В таком случае глубина рекурсии составит &amp;lt;math&amp;gt; log_2 n &amp;lt;/math&amp;gt;, следовательно, общая сложность алгоритма равна &amp;lt;math&amp;gt; O(n log_2 n) &amp;lt;/math&amp;gt;. &amp;lt;ref&amp;gt; https://neerc.ifmo.ru/wiki/index.php?title=Быстрая_сортировка &amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
2. В наихудшем случае каждое разбиение приводит к образованию подмассивов длины &amp;lt;math&amp;gt; 1 &amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt; n - 1&amp;lt;/math&amp;gt; соответственно. Общая сложность алгоритма в таком случае равна &amp;lt;math&amp;gt; O(n^2) &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
Так как для проведения вычислений задействовано &amp;lt;math&amp;gt; p = 2^N &amp;lt;/math&amp;gt; процессоров, можно воспользоваться следующим алгоритмом распределения данных между процессорами. Распределим произвольным образом данные между процессорами, далее выбираем некоторым образом ведущий элемент и рассылаем его всем процессорам системы. Т.к. топология системы имеет вид n-мерного куба, номер каждого процессора имеет двоичное представление длины &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, следовательно, можно ввести правило: на каждом процессоре происходит сравнение имеющегося блока данных с текущим ведущим элементом, после чего элементы меньше ведущего отправляются от процессора с номером &amp;lt;math&amp;gt;n_1&amp;lt;/math&amp;gt; процессору номер &amp;lt;math&amp;gt;n_2&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;n_1&amp;lt;/math&amp;gt; отличается от &amp;lt;math&amp;gt;n_2&amp;lt;/math&amp;gt; только в n-том разряде двоичного представления, в двоичном представлении числа &amp;lt;math&amp;gt;n_1&amp;lt;/math&amp;gt; на n-той позиции стоит 1, а &amp;lt;math&amp;gt;n_2&amp;lt;/math&amp;gt; — 0. Таким образом, после данной операции все данные будут разделены между процессорами, образующими n-1-мерные кубы таким образом, что элемент блока данных любого процессора из первого куба больше любого элемента блока данных процессора из второго куба. Повторив аналогичные действия для каждого из n-1-мерных кубов, получим 4 n-2-мерных куба и т.д. &lt;br /&gt;
&lt;br /&gt;
Для наглядности приведем пример: пусть &amp;lt;math&amp;gt; p = 2^3 = 8 &amp;lt;/math&amp;gt;. Ниже приведены графы, иллюстрирующие распределение данных на каждой итерации.&lt;br /&gt;
&lt;br /&gt;
[[file:Gr 1.png|thumb|center|700px|Рисунок 1. Итерация 1.]]&lt;br /&gt;
[[file:Gr 2.png|thumb|center|700px|Рисунок 2. Итерация 2.]]&lt;br /&gt;
[[file:Gr 3.png|thumb|center|700px|Рисунок 3. Итерация 3.]]&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма алгоритма ===&lt;br /&gt;
Основной идеей данного алгоритма является разбиение всего массива данных на блоки меньшего размера таким образом, что между соответствующими блоками после разбиения можно установить отношение упорядоченности. Сортировка производится следующим образом: выбирается некоторым образом ведущий элемент, после чего происходит разделение исходного массива данных на два блока относительно ведущего элемента: в первый блок помещаются элементы, меньшие ведущего, а во второй — большие ведущего. Таким образом, можно утверждать, что наибольший элемент первого блока меньше наименьшего элемента второго блока. Это означает, что повторив эту операцию для каждого из блоков отдельно некоторое количество раз и объединив результаты, получим массив с исходными данными в отсортированном виде. Из описания становится очевидно, что данный алгоритм можно легко обобщить для параллельной вычислительной системы с количеством процессоров &amp;lt;math&amp;gt;p = 2^n&amp;lt;/math&amp;gt;. Для этого алгоритм необходимо лишь дополнить методом выбора процессоров, между которыми будут происходить обмены данными на i-ом шаге. Подробное описание метода распределения данных между вычислительными узлами можно найти в разделе 1.7. Последним этапом работы алгоритма является объединение разрозненных блоков отсортированных данных в единый массив в правильном порядке. Порядок объединения не трудно восстановить исходя из двоичных представлений номеров процессоров.&lt;br /&gt;
&lt;br /&gt;
Очевидно, что наиболее медленной операцией в описанной выше схеме является операция обмена данными между процессорами, следовательно, хотелось бы получить некоторую оценку количества обменов. Такая оценка приведена ниже:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\sum_{i=1}^{n} i = n(n+1)/2 ≈ \log^2 p &amp;lt;/math&amp;gt; &amp;lt;ref&amp;gt; http://ssd.sscc.ru/ru — Supercomputer Software Department &amp;lt;/ref&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt; p &amp;lt;/math&amp;gt; — количество задействованных процессоров.&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные алгоритма ===&lt;br /&gt;
&#039;&#039;&#039;Входные данные:&#039;&#039;&#039; любая числовая последовательность произвольной конечной длины. Так как параллельный алгоритм предполагает выбор разделяющего элемента случайным образом, построение последовательностей специального вида не приводит к увеличению вероятности неравномерного распределения данных между вычислительными узлами. Это значит, что эффективность алгоритма не зависит от вида входной последовательности. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные:&#039;&#039;&#039; последовательность чисел в отсортированном виде.&lt;br /&gt;
&lt;br /&gt;
=== Свойства алгоритма ===&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Особенности реализации последовательного алгоритма ===&lt;br /&gt;
&lt;br /&gt;
=== Локальность данных и вычислений ===&lt;br /&gt;
&lt;br /&gt;
=== Возможные способы и особенности параллельной реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
=== Масштабируемость алгоритма и его реализация ===&lt;br /&gt;
Проведём исследование масштабируемости параллельной реализации алгоритма быстрой сортировки согласно [[Scalability methodology|методике]]. Исследование проводится для числа процессоров [8 : 128] с шагом 8.&lt;br /&gt;
&lt;br /&gt;
[[file:User ashabokov 415 eff.png|thumb|center|700px|Рисунок 4. Изменение эффективности в зависимости от числа процессоров и входных данных.]]&lt;br /&gt;
&lt;br /&gt;
Далее построим оценку масштабируемости:&lt;br /&gt;
&lt;br /&gt;
1. По числу процессоров: 1.0581. Это значит, что с увеличением количества задействованных процессоров эффективность увеличивается. Такое поведение можно объяснить тем, что при увеличении числа процессоров размер сортируемого участка массива для каждого отдельного процессора уменьшается.&lt;br /&gt;
&lt;br /&gt;
2. По числу входных данных: -0.6059. Это значит, что с ростом размеров входных данных эффективность алгоритма падает. Это можно объяснить тем, что при алгоритм предполагает многократный обмен массивами данных, а это значит, что при увеличении размера задачи накладные расходы на обмен данными между процессорами тоже сильно возрастает.&lt;br /&gt;
&lt;br /&gt;
3. По двум направлениям: 0.0386. Это значит, что с ростом числа процессоров и размерами входных данных эффективность все же возрастает, но скорость не слишком велика.&lt;br /&gt;
&lt;br /&gt;
=== Динамические характеристики и эффективность реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
=== Выводы для классов архитектур ===&lt;br /&gt;
&lt;br /&gt;
=== Существующие реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Реализация алгоритма быстрой сортировки имеется во многих стандартных библиотеках. Например, для языков программирования C и C++ этот алгоритм можно найти в стандартных библиотеках stdlib.h и cstdlib соответственно. В языке программирования Python имеется встроенная функция sorted(). Также реализацию этого алгоритма можно найти в пакете LAPACK DLASRT.&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;br /&gt;
&amp;lt;references /&amp;gt;&lt;/div&gt;</summary>
		<author><name>Ashabokov 415</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Ashabokov_415/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%B1%D1%8B%D1%81%D1%82%D1%80%D0%BE%D0%B9_%D1%81%D0%BE%D1%80%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B8&amp;diff=27639</id>
		<title>Участник:Ashabokov 415/Алгоритм быстрой сортировки</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Ashabokov_415/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%B1%D1%8B%D1%81%D1%82%D1%80%D0%BE%D0%B9_%D1%81%D0%BE%D1%80%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B8&amp;diff=27639"/>
		<updated>2019-12-02T14:47:41Z</updated>

		<summary type="html">&lt;p&gt;Ashabokov 415: /* Схема реализации последовательного алгоритма */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&#039;&#039;&#039;Алгоритм быстрой сортировки&#039;&#039;&#039; &lt;br /&gt;
&lt;br /&gt;
== Свойства и структура алгоритмов ==&lt;br /&gt;
&lt;br /&gt;
=== Общее описание алгоритма &amp;lt;ref&amp;gt; https://en.wikipedia.org/wiki/Quicksort — From Wikipedia, the free encyclopedia &amp;lt;/ref&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
Быстрая сортировка, сортировка Хоара —  широко известный алгоритм сортировки, разработанный английским информатиком Чарльзом Хоаром во время его работы в МГУ в 1960 году.&lt;br /&gt;
&lt;br /&gt;
Один из самых быстрых известных универсальных алгоритмов сортировки массивов: в среднем  &amp;lt;math&amp;gt; O (n \log n) &amp;lt;/math&amp;gt; обменов при упорядочении &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; элементов; из-за наличия ряда недостатков на практике обычно используется с некоторыми доработками. Фактически данный алгоритм является улучшением алгоритма сортировки прямого обмена (см. ниже).&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
Алгоритм состоит из трех основных шагов:&lt;br /&gt;
&lt;br /&gt;
1. Выбрать опорный элемент (см. ниже). Пусть это будет элемент &amp;lt;math&amp;gt; a&#039; &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
2. Используя операции сравнения элементов массива с опорным и перестановки элементов массива, привести исходный массив к виду: &amp;lt;math&amp;gt; a_1 ... a_m a&#039; a_{m+2} ... a_n &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt; a_j &amp;lt; a&#039;, j = 1 ... m &amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt; a_i \geq a&#039;, i = (m+1) ... n  &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; — длина массива.&lt;br /&gt;
&lt;br /&gt;
3. Рекурсивно применить алгоритм к каждому из массивов: &amp;lt;math&amp;gt; a_1 ... a_m &amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt; a_{m+1} ... a_n &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Рассмотрим подробнее метод сравнения и перестановки данных в массиве, применяющийся на шаге 2. Для этого часто используют так называемое разбиение Хоара &amp;lt;ref&amp;gt; https://en.wikipedia.org/wiki/Quicksort — From Wikipedia, the free encyclopedia &amp;lt;/ref&amp;gt;. Суть данного метода заключается в следующем: выбираются два указателя, указывающие на первый и последний элементы массива соответственно, пусть для наглядности это будут &amp;lt;math&amp;gt; i = 1 &amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt; j = n &amp;lt;/math&amp;gt;. Далее начинаем сдвигать левый указатель вправо, а правый — влево до тех пор, пока выполнены условия: &amp;lt;math&amp;gt; a_i &amp;lt; a&#039;, a_j \geq a&#039;, i &amp;lt; j &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt; a&#039; &amp;lt;/math&amp;gt; — опорный элемент. Как только найдутся такие &amp;lt;math&amp;gt; i, j &amp;lt;/math&amp;gt;, что &amp;lt;math&amp;gt; a_i \geq a&#039;, a_j &amp;lt; a&#039; &amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt; i &amp;lt; j &amp;lt;/math&amp;gt;, производим перестановку этих двух элементов. Продолжаем этот процесс до тех пор, пока выполнено &amp;lt;math&amp;gt; i &amp;lt; j &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
Вычислительным ядром данного алгоритма являются операции сравнения и перестановки &amp;lt;math&amp;gt; i&amp;lt;/math&amp;gt;-ого и &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;-ого элементов массива на каждой итерации рекурсивного алгоритма.&lt;br /&gt;
&lt;br /&gt;
Сложность операции разделения массива на два подмассива (сравнение и перестановка элементов массива относительно опорного элемента) занимет время &amp;lt;math&amp;gt; O (log_2 n) &amp;lt;/math&amp;gt;. &amp;lt;ref&amp;gt; https://ru.wikipedia.org/wiki/Быстрая_сортировка &amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
Как и написано выше, в разделе &amp;quot;Вычислительное ядро алгоритма&amp;quot;, основную часть данного метода сортировки составляет операция разделения массива относительно опорного элемента, которая в свою очередь состоит из операций сравнения и перестановки.&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма ===&lt;br /&gt;
1. Случайным образом выбрать опорный элемент массива.&lt;br /&gt;
&lt;br /&gt;
2. Сравнить все элементы сортируемого массива с опорным и разделить исходный массив на два подмассива: с элементами меньше опорного и с элементами больше или равным опорному. &lt;br /&gt;
&lt;br /&gt;
3. Рекурсивно повторить алгоритм для получившихся подмассивов.&lt;br /&gt;
&lt;br /&gt;
Случайный выбор опорного элемента считается наиболее эффективным, так как при фиксировании позиции опорного элемента (например, в качестве опорного всегда берется элемент, стоящий на первой позиции) может привести к существенному снижению эффективности для массивов определенного вида из-за неравномерного распределения элементов в получившихся подмассивах. Также в качестве опорного элемента можно выбирать медиану массива, но считается, что вычисление медианы на каждой итерации рекурсивного алгоритма — слишком затратная операция.&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
Последовательная сложность данного алгоритма зависит от глубины рекурсии, что в свою очередь зависит от того, насколько удачно были выбраны опорные элементы на каждом витке рекурсии. Рассмотрим несколько возможных случаев.&lt;br /&gt;
&lt;br /&gt;
1. В наилучшем случае выбор опорного элемента на каждом витке рекурсии происходит таким образом, что в результате разбиения исходного массива образуются подмассивы одинаковой длины (с точностью до одного элемента). В таком случае глубина рекурсии составит &amp;lt;math&amp;gt; log_2 n &amp;lt;/math&amp;gt;, следовательно, общая сложность алгоритма равна &amp;lt;math&amp;gt; O(n log_2 n) &amp;lt;/math&amp;gt;. &amp;lt;ref&amp;gt; https://neerc.ifmo.ru/wiki/index.php?title=Быстрая_сортировка &amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
2. В наихудшем случае каждое разбиение приводит к образованию подмассивов длины &amp;lt;math&amp;gt; 1 &amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt; n - 1&amp;lt;/math&amp;gt; соответственно. Общая сложность алгоритма в таком случае равна &amp;lt;math&amp;gt; O(n^2) &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
Так как для проведения вычислений задействовано &amp;lt;math&amp;gt; p = 2^N &amp;lt;/math&amp;gt; процессоров, можно воспользоваться следующим алгоритмом распределения данных между процессорами. Распределим произвольным образом данные между процессорами, далее выбираем некоторым образом ведущий элемент и рассылаем его всем процессорам системы. Т.к. топология системы имеет вид n-мерного куба, номер каждого процессора имеет двоичное представление длины &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, следовательно, можно ввести правило: на каждом процессоре происходит сравнение имеющегося блока данных с текущим ведущим элементом, после чего элементы меньше ведущего отправляются от процессора с номером &amp;lt;math&amp;gt;n_1&amp;lt;/math&amp;gt; процессору номер &amp;lt;math&amp;gt;n_2&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;n_1&amp;lt;/math&amp;gt; отличается от &amp;lt;math&amp;gt;n_2&amp;lt;/math&amp;gt; только в n-том разряде двоичного представления, в двоичном представлении числа &amp;lt;math&amp;gt;n_1&amp;lt;/math&amp;gt; на n-той позиции стоит 1, а &amp;lt;math&amp;gt;n_2&amp;lt;/math&amp;gt; — 0. Таким образом, после данной операции все данные будут разделены между процессорами, образующими n-1-мерные кубы таким образом, что элемент блока данных любого процессора из первого куба больше любого элемента блока данных процессора из второго куба. Повторив аналогичные действия для каждого из n-1-мерных кубов, получим 4 n-2-мерных куба и т.д. &lt;br /&gt;
&lt;br /&gt;
Для наглядности приведем пример: пусть &amp;lt;math&amp;gt; p = 2^3 = 8 &amp;lt;/math&amp;gt;. Ниже приведены графы, иллюстрирующие распределение данных на каждой итерации.&lt;br /&gt;
&lt;br /&gt;
[[file:Gr 1.png|thumb|center|700px|Рисунок 1. Итерация 1.]]&lt;br /&gt;
[[file:Gr 2.png|thumb|center|700px|Рисунок 2. Итерация 2.]]&lt;br /&gt;
[[file:Gr 3.png|thumb|center|700px|Рисунок 3. Итерация 3.]]&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма алгоритма ===&lt;br /&gt;
Основной идеей данного алгоритма является разбиение всего массива данных на блоки меньшего размера таким образом, что между соответствующими блоками после разбиения можно установить отношение упорядоченности. Сортировка производится следующим образом: выбирается некоторым образом ведущий элемент, после чего происходит разделение исходного массива данных на два блока относительно ведущего элемента: в первый блок помещаются элементы, меньшие ведущего, а во второй — большие ведущего. Таким образом, можно утверждать, что наибольший элемент первого блока меньше наименьшего элемента второго блока. Это означает, что повторив эту операцию для каждого из блоков отдельно некоторое количество раз и объединив результаты, получим массив с исходными данными в отсортированном виде. Из описания становится очевидно, что данный алгоритм можно легко обобщить для параллельной вычислительной системы с количеством процессоров &amp;lt;math&amp;gt;p = 2^n&amp;lt;/math&amp;gt;. Для этого алгоритм необходимо лишь дополнить методом выбора процессоров, между которыми будут происходить обмены данными на i-ом шаге. Подробное описание метода распределения данных между вычислительными узлами можно найти в разделе 1.7. Последним этапом работы алгоритма является объединение разрозненных блоков отсортированных данных в единый массив в правильном порядке. Порядок объединения не трудно восстановить исходя из двоичных представлений номеров процессоров.&lt;br /&gt;
&lt;br /&gt;
Очевидно, что наиболее медленной операцией в описанной выше схеме является операция обмена данными между процессорами, следовательно, хотелось бы получить некоторую оценку количества обменов. Такая оценка приведена ниже:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\sum_{i=1}^{n} i = n(n+1)/2 ≈ \log^2 p &amp;lt;/math&amp;gt; &amp;lt;ref&amp;gt; http://ssd.sscc.ru/ru — Supercomputer Software Department &amp;lt;/ref&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt; p &amp;lt;/math&amp;gt; — количество задействованных процессоров.&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные алгоритма ===&lt;br /&gt;
&#039;&#039;&#039;Входные данные:&#039;&#039;&#039; любая числовая последовательность произвольной конечной длины. Так как параллельный алгоритм предполагает выбор разделяющего элемента случайным образом, построение последовательностей специального вида не приводит к увеличению вероятности неравномерного распределения данных между вычислительными узлами. Это значит, что эффективность алгоритма не зависит от вида входной последовательности. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные:&#039;&#039;&#039; последовательность чисел в отсортированном виде.&lt;br /&gt;
&lt;br /&gt;
=== Свойства алгоритма ===&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Особенности реализации последовательного алгоритма ===&lt;br /&gt;
&lt;br /&gt;
=== Локальность данных и вычислений ===&lt;br /&gt;
&lt;br /&gt;
=== Возможные способы и особенности параллельной реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
=== Масштабируемость алгоритма и его реализация ===&lt;br /&gt;
Проведём исследование масштабируемости параллельной реализации алгоритма быстрой сортировки согласно [[Scalability methodology|методике]]. Исследование проводится для числа процессоров [8 : 128] с шагом 8.&lt;br /&gt;
&lt;br /&gt;
[[file:User ashabokov 415 eff.png|thumb|center|700px|Рисунок 4. Изменение эффективности в зависимости от числа процессоров и входных данных.]]&lt;br /&gt;
&lt;br /&gt;
Далее построим оценку масштабируемости:&lt;br /&gt;
&lt;br /&gt;
1. По числу процессоров: 1.0581. Это значит, что с увеличением количества задействованных процессоров эффективность увеличивается. Такое поведение можно объяснить тем, что при увеличении числа процессоров размер сортируемого участка массива для каждого отдельного процессора уменьшается.&lt;br /&gt;
&lt;br /&gt;
2. По числу входных данных: -0.6059. Это значит, что с ростом размеров входных данных эффективность алгоритма падает. Это можно объяснить тем, что при алгоритм предполагает многократный обмен массивами данных, а это значит, что при увеличении размера задачи накладные расходы на обмен данными между процессорами тоже сильно возрастает.&lt;br /&gt;
&lt;br /&gt;
3. По двум направлениям: 0.0386. Это значит, что с ростом числа процессоров и размерами входных данных эффективность все же возрастает, но скорость не слишком велика.&lt;br /&gt;
&lt;br /&gt;
=== Динамические характеристики и эффективность реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
=== Выводы для классов архитектур ===&lt;br /&gt;
&lt;br /&gt;
=== Существующие реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Реализация алгоритма быстрой сортировки имеется во многих стандартных библиотеках. Например, для языков программирования C и C++ этот алгоритм можно найти в стандартных библиотеках stdlib.h и cstdlib соответственно. В языке программирования Python имеется встроенная функция sorted(). Также реализацию этого алгоритма можно найти в пакете LAPACK DLASRT.&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;br /&gt;
&amp;lt;references /&amp;gt;&lt;/div&gt;</summary>
		<author><name>Ashabokov 415</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Ashabokov_415/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%B1%D1%8B%D1%81%D1%82%D1%80%D0%BE%D0%B9_%D1%81%D0%BE%D1%80%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B8&amp;diff=27638</id>
		<title>Участник:Ashabokov 415/Алгоритм быстрой сортировки</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Ashabokov_415/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%B1%D1%8B%D1%81%D1%82%D1%80%D0%BE%D0%B9_%D1%81%D0%BE%D1%80%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B8&amp;diff=27638"/>
		<updated>2019-12-02T14:47:08Z</updated>

		<summary type="html">&lt;p&gt;Ashabokov 415: /* Схема реализации последовательного алгоритма */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&#039;&#039;&#039;Алгоритм быстрой сортировки&#039;&#039;&#039; &lt;br /&gt;
&lt;br /&gt;
== Свойства и структура алгоритмов ==&lt;br /&gt;
&lt;br /&gt;
=== Общее описание алгоритма &amp;lt;ref&amp;gt; https://en.wikipedia.org/wiki/Quicksort — From Wikipedia, the free encyclopedia &amp;lt;/ref&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
Быстрая сортировка, сортировка Хоара —  широко известный алгоритм сортировки, разработанный английским информатиком Чарльзом Хоаром во время его работы в МГУ в 1960 году.&lt;br /&gt;
&lt;br /&gt;
Один из самых быстрых известных универсальных алгоритмов сортировки массивов: в среднем  &amp;lt;math&amp;gt; O (n \log n) &amp;lt;/math&amp;gt; обменов при упорядочении &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; элементов; из-за наличия ряда недостатков на практике обычно используется с некоторыми доработками. Фактически данный алгоритм является улучшением алгоритма сортировки прямого обмена (см. ниже).&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
Алгоритм состоит из трех основных шагов:&lt;br /&gt;
&lt;br /&gt;
1. Выбрать опорный элемент (см. ниже). Пусть это будет элемент &amp;lt;math&amp;gt; a&#039; &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
2. Используя операции сравнения элементов массива с опорным и перестановки элементов массива, привести исходный массив к виду: &amp;lt;math&amp;gt; a_1 ... a_m a&#039; a_{m+2} ... a_n &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt; a_j &amp;lt; a&#039;, j = 1 ... m &amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt; a_i \geq a&#039;, i = (m+1) ... n  &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; — длина массива.&lt;br /&gt;
&lt;br /&gt;
3. Рекурсивно применить алгоритм к каждому из массивов: &amp;lt;math&amp;gt; a_1 ... a_m &amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt; a_{m+1} ... a_n &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Рассмотрим подробнее метод сравнения и перестановки данных в массиве, применяющийся на шаге 2. Для этого часто используют так называемое разбиение Хоара &amp;lt;ref&amp;gt; https://en.wikipedia.org/wiki/Quicksort — From Wikipedia, the free encyclopedia &amp;lt;/ref&amp;gt;. Суть данного метода заключается в следующем: выбираются два указателя, указывающие на первый и последний элементы массива соответственно, пусть для наглядности это будут &amp;lt;math&amp;gt; i = 1 &amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt; j = n &amp;lt;/math&amp;gt;. Далее начинаем сдвигать левый указатель вправо, а правый — влево до тех пор, пока выполнены условия: &amp;lt;math&amp;gt; a_i &amp;lt; a&#039;, a_j \geq a&#039;, i &amp;lt; j &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt; a&#039; &amp;lt;/math&amp;gt; — опорный элемент. Как только найдутся такие &amp;lt;math&amp;gt; i, j &amp;lt;/math&amp;gt;, что &amp;lt;math&amp;gt; a_i \geq a&#039;, a_j &amp;lt; a&#039; &amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt; i &amp;lt; j &amp;lt;/math&amp;gt;, производим перестановку этих двух элементов. Продолжаем этот процесс до тех пор, пока выполнено &amp;lt;math&amp;gt; i &amp;lt; j &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
Вычислительным ядром данного алгоритма являются операции сравнения и перестановки &amp;lt;math&amp;gt; i&amp;lt;/math&amp;gt;-ого и &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;-ого элементов массива на каждой итерации рекурсивного алгоритма.&lt;br /&gt;
&lt;br /&gt;
Сложность операции разделения массива на два подмассива (сравнение и перестановка элементов массива относительно опорного элемента) занимет время &amp;lt;math&amp;gt; O (log_2 n) &amp;lt;/math&amp;gt;. &amp;lt;ref&amp;gt; https://ru.wikipedia.org/wiki/Быстрая_сортировка &amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
Как и написано выше, в разделе &amp;quot;Вычислительное ядро алгоритма&amp;quot;, основную часть данного метода сортировки составляет операция разделения массива относительно опорного элемента, которая в свою очередь состоит из операций сравнения и перестановки.&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма ===&lt;br /&gt;
1. Случайным образом выбрать опорный элемент массива.&lt;br /&gt;
&lt;br /&gt;
2. Сравнить все элементы сортируемого массива с опорным и разделить исходный массив на два подмассива: с элементами меньше опорного и с элементами больше (или равным) опорного. &lt;br /&gt;
&lt;br /&gt;
3. Рекурсивно повторить алгоритм для получившихся подмассивов.&lt;br /&gt;
&lt;br /&gt;
Случайный выбор опорного элемента считается наиболее эффективным, так как при фиксировании позиции опорного элемента (например, в качестве опорного всегда берется элемент, стоящий на первой позиции) может привести к существенному снижению эффективности для массивов определенного вида из-за неравномерного распределения элементов в получившихся подмассивах. Также в качестве опорного элемента можно выбирать медиану массива, но считается, что вычисление медианы на каждой итерации рекурсивного алгоритма — слишком затратная операция.&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
Последовательная сложность данного алгоритма зависит от глубины рекурсии, что в свою очередь зависит от того, насколько удачно были выбраны опорные элементы на каждом витке рекурсии. Рассмотрим несколько возможных случаев.&lt;br /&gt;
&lt;br /&gt;
1. В наилучшем случае выбор опорного элемента на каждом витке рекурсии происходит таким образом, что в результате разбиения исходного массива образуются подмассивы одинаковой длины (с точностью до одного элемента). В таком случае глубина рекурсии составит &amp;lt;math&amp;gt; log_2 n &amp;lt;/math&amp;gt;, следовательно, общая сложность алгоритма равна &amp;lt;math&amp;gt; O(n log_2 n) &amp;lt;/math&amp;gt;. &amp;lt;ref&amp;gt; https://neerc.ifmo.ru/wiki/index.php?title=Быстрая_сортировка &amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
2. В наихудшем случае каждое разбиение приводит к образованию подмассивов длины &amp;lt;math&amp;gt; 1 &amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt; n - 1&amp;lt;/math&amp;gt; соответственно. Общая сложность алгоритма в таком случае равна &amp;lt;math&amp;gt; O(n^2) &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
Так как для проведения вычислений задействовано &amp;lt;math&amp;gt; p = 2^N &amp;lt;/math&amp;gt; процессоров, можно воспользоваться следующим алгоритмом распределения данных между процессорами. Распределим произвольным образом данные между процессорами, далее выбираем некоторым образом ведущий элемент и рассылаем его всем процессорам системы. Т.к. топология системы имеет вид n-мерного куба, номер каждого процессора имеет двоичное представление длины &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, следовательно, можно ввести правило: на каждом процессоре происходит сравнение имеющегося блока данных с текущим ведущим элементом, после чего элементы меньше ведущего отправляются от процессора с номером &amp;lt;math&amp;gt;n_1&amp;lt;/math&amp;gt; процессору номер &amp;lt;math&amp;gt;n_2&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;n_1&amp;lt;/math&amp;gt; отличается от &amp;lt;math&amp;gt;n_2&amp;lt;/math&amp;gt; только в n-том разряде двоичного представления, в двоичном представлении числа &amp;lt;math&amp;gt;n_1&amp;lt;/math&amp;gt; на n-той позиции стоит 1, а &amp;lt;math&amp;gt;n_2&amp;lt;/math&amp;gt; — 0. Таким образом, после данной операции все данные будут разделены между процессорами, образующими n-1-мерные кубы таким образом, что элемент блока данных любого процессора из первого куба больше любого элемента блока данных процессора из второго куба. Повторив аналогичные действия для каждого из n-1-мерных кубов, получим 4 n-2-мерных куба и т.д. &lt;br /&gt;
&lt;br /&gt;
Для наглядности приведем пример: пусть &amp;lt;math&amp;gt; p = 2^3 = 8 &amp;lt;/math&amp;gt;. Ниже приведены графы, иллюстрирующие распределение данных на каждой итерации.&lt;br /&gt;
&lt;br /&gt;
[[file:Gr 1.png|thumb|center|700px|Рисунок 1. Итерация 1.]]&lt;br /&gt;
[[file:Gr 2.png|thumb|center|700px|Рисунок 2. Итерация 2.]]&lt;br /&gt;
[[file:Gr 3.png|thumb|center|700px|Рисунок 3. Итерация 3.]]&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма алгоритма ===&lt;br /&gt;
Основной идеей данного алгоритма является разбиение всего массива данных на блоки меньшего размера таким образом, что между соответствующими блоками после разбиения можно установить отношение упорядоченности. Сортировка производится следующим образом: выбирается некоторым образом ведущий элемент, после чего происходит разделение исходного массива данных на два блока относительно ведущего элемента: в первый блок помещаются элементы, меньшие ведущего, а во второй — большие ведущего. Таким образом, можно утверждать, что наибольший элемент первого блока меньше наименьшего элемента второго блока. Это означает, что повторив эту операцию для каждого из блоков отдельно некоторое количество раз и объединив результаты, получим массив с исходными данными в отсортированном виде. Из описания становится очевидно, что данный алгоритм можно легко обобщить для параллельной вычислительной системы с количеством процессоров &amp;lt;math&amp;gt;p = 2^n&amp;lt;/math&amp;gt;. Для этого алгоритм необходимо лишь дополнить методом выбора процессоров, между которыми будут происходить обмены данными на i-ом шаге. Подробное описание метода распределения данных между вычислительными узлами можно найти в разделе 1.7. Последним этапом работы алгоритма является объединение разрозненных блоков отсортированных данных в единый массив в правильном порядке. Порядок объединения не трудно восстановить исходя из двоичных представлений номеров процессоров.&lt;br /&gt;
&lt;br /&gt;
Очевидно, что наиболее медленной операцией в описанной выше схеме является операция обмена данными между процессорами, следовательно, хотелось бы получить некоторую оценку количества обменов. Такая оценка приведена ниже:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\sum_{i=1}^{n} i = n(n+1)/2 ≈ \log^2 p &amp;lt;/math&amp;gt; &amp;lt;ref&amp;gt; http://ssd.sscc.ru/ru — Supercomputer Software Department &amp;lt;/ref&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt; p &amp;lt;/math&amp;gt; — количество задействованных процессоров.&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные алгоритма ===&lt;br /&gt;
&#039;&#039;&#039;Входные данные:&#039;&#039;&#039; любая числовая последовательность произвольной конечной длины. Так как параллельный алгоритм предполагает выбор разделяющего элемента случайным образом, построение последовательностей специального вида не приводит к увеличению вероятности неравномерного распределения данных между вычислительными узлами. Это значит, что эффективность алгоритма не зависит от вида входной последовательности. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные:&#039;&#039;&#039; последовательность чисел в отсортированном виде.&lt;br /&gt;
&lt;br /&gt;
=== Свойства алгоритма ===&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Особенности реализации последовательного алгоритма ===&lt;br /&gt;
&lt;br /&gt;
=== Локальность данных и вычислений ===&lt;br /&gt;
&lt;br /&gt;
=== Возможные способы и особенности параллельной реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
=== Масштабируемость алгоритма и его реализация ===&lt;br /&gt;
Проведём исследование масштабируемости параллельной реализации алгоритма быстрой сортировки согласно [[Scalability methodology|методике]]. Исследование проводится для числа процессоров [8 : 128] с шагом 8.&lt;br /&gt;
&lt;br /&gt;
[[file:User ashabokov 415 eff.png|thumb|center|700px|Рисунок 4. Изменение эффективности в зависимости от числа процессоров и входных данных.]]&lt;br /&gt;
&lt;br /&gt;
Далее построим оценку масштабируемости:&lt;br /&gt;
&lt;br /&gt;
1. По числу процессоров: 1.0581. Это значит, что с увеличением количества задействованных процессоров эффективность увеличивается. Такое поведение можно объяснить тем, что при увеличении числа процессоров размер сортируемого участка массива для каждого отдельного процессора уменьшается.&lt;br /&gt;
&lt;br /&gt;
2. По числу входных данных: -0.6059. Это значит, что с ростом размеров входных данных эффективность алгоритма падает. Это можно объяснить тем, что при алгоритм предполагает многократный обмен массивами данных, а это значит, что при увеличении размера задачи накладные расходы на обмен данными между процессорами тоже сильно возрастает.&lt;br /&gt;
&lt;br /&gt;
3. По двум направлениям: 0.0386. Это значит, что с ростом числа процессоров и размерами входных данных эффективность все же возрастает, но скорость не слишком велика.&lt;br /&gt;
&lt;br /&gt;
=== Динамические характеристики и эффективность реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
=== Выводы для классов архитектур ===&lt;br /&gt;
&lt;br /&gt;
=== Существующие реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Реализация алгоритма быстрой сортировки имеется во многих стандартных библиотеках. Например, для языков программирования C и C++ этот алгоритм можно найти в стандартных библиотеках stdlib.h и cstdlib соответственно. В языке программирования Python имеется встроенная функция sorted(). Также реализацию этого алгоритма можно найти в пакете LAPACK DLASRT.&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;br /&gt;
&amp;lt;references /&amp;gt;&lt;/div&gt;</summary>
		<author><name>Ashabokov 415</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Ashabokov_415/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%B1%D1%8B%D1%81%D1%82%D1%80%D0%BE%D0%B9_%D1%81%D0%BE%D1%80%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B8&amp;diff=27637</id>
		<title>Участник:Ashabokov 415/Алгоритм быстрой сортировки</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Ashabokov_415/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%B1%D1%8B%D1%81%D1%82%D1%80%D0%BE%D0%B9_%D1%81%D0%BE%D1%80%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B8&amp;diff=27637"/>
		<updated>2019-12-02T14:44:14Z</updated>

		<summary type="html">&lt;p&gt;Ashabokov 415: /* Макроструктура алгоритма */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&#039;&#039;&#039;Алгоритм быстрой сортировки&#039;&#039;&#039; &lt;br /&gt;
&lt;br /&gt;
== Свойства и структура алгоритмов ==&lt;br /&gt;
&lt;br /&gt;
=== Общее описание алгоритма &amp;lt;ref&amp;gt; https://en.wikipedia.org/wiki/Quicksort — From Wikipedia, the free encyclopedia &amp;lt;/ref&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
Быстрая сортировка, сортировка Хоара —  широко известный алгоритм сортировки, разработанный английским информатиком Чарльзом Хоаром во время его работы в МГУ в 1960 году.&lt;br /&gt;
&lt;br /&gt;
Один из самых быстрых известных универсальных алгоритмов сортировки массивов: в среднем  &amp;lt;math&amp;gt; O (n \log n) &amp;lt;/math&amp;gt; обменов при упорядочении &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; элементов; из-за наличия ряда недостатков на практике обычно используется с некоторыми доработками. Фактически данный алгоритм является улучшением алгоритма сортировки прямого обмена (см. ниже).&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
Алгоритм состоит из трех основных шагов:&lt;br /&gt;
&lt;br /&gt;
1. Выбрать опорный элемент (см. ниже). Пусть это будет элемент &amp;lt;math&amp;gt; a&#039; &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
2. Используя операции сравнения элементов массива с опорным и перестановки элементов массива, привести исходный массив к виду: &amp;lt;math&amp;gt; a_1 ... a_m a&#039; a_{m+2} ... a_n &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt; a_j &amp;lt; a&#039;, j = 1 ... m &amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt; a_i \geq a&#039;, i = (m+1) ... n  &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; — длина массива.&lt;br /&gt;
&lt;br /&gt;
3. Рекурсивно применить алгоритм к каждому из массивов: &amp;lt;math&amp;gt; a_1 ... a_m &amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt; a_{m+1} ... a_n &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Рассмотрим подробнее метод сравнения и перестановки данных в массиве, применяющийся на шаге 2. Для этого часто используют так называемое разбиение Хоара &amp;lt;ref&amp;gt; https://en.wikipedia.org/wiki/Quicksort — From Wikipedia, the free encyclopedia &amp;lt;/ref&amp;gt;. Суть данного метода заключается в следующем: выбираются два указателя, указывающие на первый и последний элементы массива соответственно, пусть для наглядности это будут &amp;lt;math&amp;gt; i = 1 &amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt; j = n &amp;lt;/math&amp;gt;. Далее начинаем сдвигать левый указатель вправо, а правый — влево до тех пор, пока выполнены условия: &amp;lt;math&amp;gt; a_i &amp;lt; a&#039;, a_j \geq a&#039;, i &amp;lt; j &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt; a&#039; &amp;lt;/math&amp;gt; — опорный элемент. Как только найдутся такие &amp;lt;math&amp;gt; i, j &amp;lt;/math&amp;gt;, что &amp;lt;math&amp;gt; a_i \geq a&#039;, a_j &amp;lt; a&#039; &amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt; i &amp;lt; j &amp;lt;/math&amp;gt;, производим перестановку этих двух элементов. Продолжаем этот процесс до тех пор, пока выполнено &amp;lt;math&amp;gt; i &amp;lt; j &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
Вычислительным ядром данного алгоритма являются операции сравнения и перестановки &amp;lt;math&amp;gt; i&amp;lt;/math&amp;gt;-ого и &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;-ого элементов массива на каждой итерации рекурсивного алгоритма.&lt;br /&gt;
&lt;br /&gt;
Сложность операции разделения массива на два подмассива (сравнение и перестановка элементов массива относительно опорного элемента) занимет время &amp;lt;math&amp;gt; O (log_2 n) &amp;lt;/math&amp;gt;. &amp;lt;ref&amp;gt; https://ru.wikipedia.org/wiki/Быстрая_сортировка &amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
Как и написано выше, в разделе &amp;quot;Вычислительное ядро алгоритма&amp;quot;, основную часть данного метода сортировки составляет операция разделения массива относительно опорного элемента, которая в свою очередь состоит из операций сравнения и перестановки.&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма ===&lt;br /&gt;
1. Случайным образом выбрать опорный элемент массива.&lt;br /&gt;
&lt;br /&gt;
2. Сравнить все элементы сортируемого массива с опорным и разделить исходный массив на два подмассива: с элементами меньше опорного и с элементами большие (или равные) опорного. &lt;br /&gt;
&lt;br /&gt;
3. Рекурсивно повторить алгоритм для получившихся подмассивов.&lt;br /&gt;
&lt;br /&gt;
Случайный выбор опорного элемента считается наиболее эффективным, так как при фиксировании позиции опорного элемента (например, в качестве опорного всегда берется элемент, стоящий на первой позиции) может привести к существенному снижению эффективности для массивов определенного вида из-за неравномерного распределения элементов в получившихся подмассивах. Также в качестве опорного элемента можно выбирать медиану массива, но считается, что вычисление медианы на каждой итерации рекурсивного алгоритма — слишком затратная операция.&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
Последовательная сложность данного алгоритма зависит от глубины рекурсии, что в свою очередь зависит от того, насколько удачно были выбраны опорные элементы на каждом витке рекурсии. Рассмотрим несколько возможных случаев.&lt;br /&gt;
&lt;br /&gt;
1. В наилучшем случае выбор опорного элемента на каждом витке рекурсии происходит таким образом, что в результате разбиения исходного массива образуются подмассивы одинаковой длины (с точностью до одного элемента). В таком случае глубина рекурсии составит &amp;lt;math&amp;gt; log_2 n &amp;lt;/math&amp;gt;, следовательно, общая сложность алгоритма равна &amp;lt;math&amp;gt; O(n log_2 n) &amp;lt;/math&amp;gt;. &amp;lt;ref&amp;gt; https://neerc.ifmo.ru/wiki/index.php?title=Быстрая_сортировка &amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
2. В наихудшем случае каждое разбиение приводит к образованию подмассивов длины &amp;lt;math&amp;gt; 1 &amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt; n - 1&amp;lt;/math&amp;gt; соответственно. Общая сложность алгоритма в таком случае равна &amp;lt;math&amp;gt; O(n^2) &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
Так как для проведения вычислений задействовано &amp;lt;math&amp;gt; p = 2^N &amp;lt;/math&amp;gt; процессоров, можно воспользоваться следующим алгоритмом распределения данных между процессорами. Распределим произвольным образом данные между процессорами, далее выбираем некоторым образом ведущий элемент и рассылаем его всем процессорам системы. Т.к. топология системы имеет вид n-мерного куба, номер каждого процессора имеет двоичное представление длины &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, следовательно, можно ввести правило: на каждом процессоре происходит сравнение имеющегося блока данных с текущим ведущим элементом, после чего элементы меньше ведущего отправляются от процессора с номером &amp;lt;math&amp;gt;n_1&amp;lt;/math&amp;gt; процессору номер &amp;lt;math&amp;gt;n_2&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;n_1&amp;lt;/math&amp;gt; отличается от &amp;lt;math&amp;gt;n_2&amp;lt;/math&amp;gt; только в n-том разряде двоичного представления, в двоичном представлении числа &amp;lt;math&amp;gt;n_1&amp;lt;/math&amp;gt; на n-той позиции стоит 1, а &amp;lt;math&amp;gt;n_2&amp;lt;/math&amp;gt; — 0. Таким образом, после данной операции все данные будут разделены между процессорами, образующими n-1-мерные кубы таким образом, что элемент блока данных любого процессора из первого куба больше любого элемента блока данных процессора из второго куба. Повторив аналогичные действия для каждого из n-1-мерных кубов, получим 4 n-2-мерных куба и т.д. &lt;br /&gt;
&lt;br /&gt;
Для наглядности приведем пример: пусть &amp;lt;math&amp;gt; p = 2^3 = 8 &amp;lt;/math&amp;gt;. Ниже приведены графы, иллюстрирующие распределение данных на каждой итерации.&lt;br /&gt;
&lt;br /&gt;
[[file:Gr 1.png|thumb|center|700px|Рисунок 1. Итерация 1.]]&lt;br /&gt;
[[file:Gr 2.png|thumb|center|700px|Рисунок 2. Итерация 2.]]&lt;br /&gt;
[[file:Gr 3.png|thumb|center|700px|Рисунок 3. Итерация 3.]]&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма алгоритма ===&lt;br /&gt;
Основной идеей данного алгоритма является разбиение всего массива данных на блоки меньшего размера таким образом, что между соответствующими блоками после разбиения можно установить отношение упорядоченности. Сортировка производится следующим образом: выбирается некоторым образом ведущий элемент, после чего происходит разделение исходного массива данных на два блока относительно ведущего элемента: в первый блок помещаются элементы, меньшие ведущего, а во второй — большие ведущего. Таким образом, можно утверждать, что наибольший элемент первого блока меньше наименьшего элемента второго блока. Это означает, что повторив эту операцию для каждого из блоков отдельно некоторое количество раз и объединив результаты, получим массив с исходными данными в отсортированном виде. Из описания становится очевидно, что данный алгоритм можно легко обобщить для параллельной вычислительной системы с количеством процессоров &amp;lt;math&amp;gt;p = 2^n&amp;lt;/math&amp;gt;. Для этого алгоритм необходимо лишь дополнить методом выбора процессоров, между которыми будут происходить обмены данными на i-ом шаге. Подробное описание метода распределения данных между вычислительными узлами можно найти в разделе 1.7. Последним этапом работы алгоритма является объединение разрозненных блоков отсортированных данных в единый массив в правильном порядке. Порядок объединения не трудно восстановить исходя из двоичных представлений номеров процессоров.&lt;br /&gt;
&lt;br /&gt;
Очевидно, что наиболее медленной операцией в описанной выше схеме является операция обмена данными между процессорами, следовательно, хотелось бы получить некоторую оценку количества обменов. Такая оценка приведена ниже:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\sum_{i=1}^{n} i = n(n+1)/2 ≈ \log^2 p &amp;lt;/math&amp;gt; &amp;lt;ref&amp;gt; http://ssd.sscc.ru/ru — Supercomputer Software Department &amp;lt;/ref&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt; p &amp;lt;/math&amp;gt; — количество задействованных процессоров.&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные алгоритма ===&lt;br /&gt;
&#039;&#039;&#039;Входные данные:&#039;&#039;&#039; любая числовая последовательность произвольной конечной длины. Так как параллельный алгоритм предполагает выбор разделяющего элемента случайным образом, построение последовательностей специального вида не приводит к увеличению вероятности неравномерного распределения данных между вычислительными узлами. Это значит, что эффективность алгоритма не зависит от вида входной последовательности. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные:&#039;&#039;&#039; последовательность чисел в отсортированном виде.&lt;br /&gt;
&lt;br /&gt;
=== Свойства алгоритма ===&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Особенности реализации последовательного алгоритма ===&lt;br /&gt;
&lt;br /&gt;
=== Локальность данных и вычислений ===&lt;br /&gt;
&lt;br /&gt;
=== Возможные способы и особенности параллельной реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
=== Масштабируемость алгоритма и его реализация ===&lt;br /&gt;
Проведём исследование масштабируемости параллельной реализации алгоритма быстрой сортировки согласно [[Scalability methodology|методике]]. Исследование проводится для числа процессоров [8 : 128] с шагом 8.&lt;br /&gt;
&lt;br /&gt;
[[file:User ashabokov 415 eff.png|thumb|center|700px|Рисунок 4. Изменение эффективности в зависимости от числа процессоров и входных данных.]]&lt;br /&gt;
&lt;br /&gt;
Далее построим оценку масштабируемости:&lt;br /&gt;
&lt;br /&gt;
1. По числу процессоров: 1.0581. Это значит, что с увеличением количества задействованных процессоров эффективность увеличивается. Такое поведение можно объяснить тем, что при увеличении числа процессоров размер сортируемого участка массива для каждого отдельного процессора уменьшается.&lt;br /&gt;
&lt;br /&gt;
2. По числу входных данных: -0.6059. Это значит, что с ростом размеров входных данных эффективность алгоритма падает. Это можно объяснить тем, что при алгоритм предполагает многократный обмен массивами данных, а это значит, что при увеличении размера задачи накладные расходы на обмен данными между процессорами тоже сильно возрастает.&lt;br /&gt;
&lt;br /&gt;
3. По двум направлениям: 0.0386. Это значит, что с ростом числа процессоров и размерами входных данных эффективность все же возрастает, но скорость не слишком велика.&lt;br /&gt;
&lt;br /&gt;
=== Динамические характеристики и эффективность реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
=== Выводы для классов архитектур ===&lt;br /&gt;
&lt;br /&gt;
=== Существующие реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Реализация алгоритма быстрой сортировки имеется во многих стандартных библиотеках. Например, для языков программирования C и C++ этот алгоритм можно найти в стандартных библиотеках stdlib.h и cstdlib соответственно. В языке программирования Python имеется встроенная функция sorted(). Также реализацию этого алгоритма можно найти в пакете LAPACK DLASRT.&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;br /&gt;
&amp;lt;references /&amp;gt;&lt;/div&gt;</summary>
		<author><name>Ashabokov 415</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Ashabokov_415/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%B1%D1%8B%D1%81%D1%82%D1%80%D0%BE%D0%B9_%D1%81%D0%BE%D1%80%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B8&amp;diff=27636</id>
		<title>Участник:Ashabokov 415/Алгоритм быстрой сортировки</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Ashabokov_415/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%B1%D1%8B%D1%81%D1%82%D1%80%D0%BE%D0%B9_%D1%81%D0%BE%D1%80%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B8&amp;diff=27636"/>
		<updated>2019-12-02T14:42:21Z</updated>

		<summary type="html">&lt;p&gt;Ashabokov 415: /* Математическое описание алгоритма */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&#039;&#039;&#039;Алгоритм быстрой сортировки&#039;&#039;&#039; &lt;br /&gt;
&lt;br /&gt;
== Свойства и структура алгоритмов ==&lt;br /&gt;
&lt;br /&gt;
=== Общее описание алгоритма &amp;lt;ref&amp;gt; https://en.wikipedia.org/wiki/Quicksort — From Wikipedia, the free encyclopedia &amp;lt;/ref&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
Быстрая сортировка, сортировка Хоара —  широко известный алгоритм сортировки, разработанный английским информатиком Чарльзом Хоаром во время его работы в МГУ в 1960 году.&lt;br /&gt;
&lt;br /&gt;
Один из самых быстрых известных универсальных алгоритмов сортировки массивов: в среднем  &amp;lt;math&amp;gt; O (n \log n) &amp;lt;/math&amp;gt; обменов при упорядочении &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; элементов; из-за наличия ряда недостатков на практике обычно используется с некоторыми доработками. Фактически данный алгоритм является улучшением алгоритма сортировки прямого обмена (см. ниже).&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
Алгоритм состоит из трех основных шагов:&lt;br /&gt;
&lt;br /&gt;
1. Выбрать опорный элемент (см. ниже). Пусть это будет элемент &amp;lt;math&amp;gt; a&#039; &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
2. Используя операции сравнения элементов массива с опорным и перестановки элементов массива, привести исходный массив к виду: &amp;lt;math&amp;gt; a_1 ... a_m a&#039; a_{m+2} ... a_n &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt; a_j &amp;lt; a&#039;, j = 1 ... m &amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt; a_i \geq a&#039;, i = (m+1) ... n  &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; — длина массива.&lt;br /&gt;
&lt;br /&gt;
3. Рекурсивно применить алгоритм к каждому из массивов: &amp;lt;math&amp;gt; a_1 ... a_m &amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt; a_{m+1} ... a_n &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Рассмотрим подробнее метод сравнения и перестановки данных в массиве, применяющийся на шаге 2. Для этого часто используют так называемое разбиение Хоара &amp;lt;ref&amp;gt; https://en.wikipedia.org/wiki/Quicksort — From Wikipedia, the free encyclopedia &amp;lt;/ref&amp;gt;. Суть данного метода заключается в следующем: выбираются два указателя, указывающие на первый и последний элементы массива соответственно, пусть для наглядности это будут &amp;lt;math&amp;gt; i = 1 &amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt; j = n &amp;lt;/math&amp;gt;. Далее начинаем сдвигать левый указатель вправо, а правый — влево до тех пор, пока выполнены условия: &amp;lt;math&amp;gt; a_i &amp;lt; a&#039;, a_j \geq a&#039;, i &amp;lt; j &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt; a&#039; &amp;lt;/math&amp;gt; — опорный элемент. Как только найдутся такие &amp;lt;math&amp;gt; i, j &amp;lt;/math&amp;gt;, что &amp;lt;math&amp;gt; a_i \geq a&#039;, a_j &amp;lt; a&#039; &amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt; i &amp;lt; j &amp;lt;/math&amp;gt;, производим перестановку этих двух элементов. Продолжаем этот процесс до тех пор, пока выполнено &amp;lt;math&amp;gt; i &amp;lt; j &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
Вычислительным ядром данного алгоритма являются операции сравнения и перестановки &amp;lt;math&amp;gt; i&amp;lt;/math&amp;gt;-ого и &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;-ого элементов массива на каждой итерации рекурсивного алгоритма.&lt;br /&gt;
&lt;br /&gt;
Сложность операции разделения массива на два подмассива (сравнение и перестановка элементов массива относительно опорного элемента) занимет время &amp;lt;math&amp;gt; O (log_2 n) &amp;lt;/math&amp;gt;. &amp;lt;ref&amp;gt; https://ru.wikipedia.org/wiki/Быстрая_сортировка &amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
Как и написано выше в разделе &amp;quot;Вычислительное ядро алгоритма&amp;quot;, основную часть данного метода сортировки составляет операция разделения массива относительно опорного элемента, которая в свою очередь состоит из операций сравнения и перестановки.&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма ===&lt;br /&gt;
1. Случайным образом выбрать опорный элемент массива.&lt;br /&gt;
&lt;br /&gt;
2. Сравнить все элементы сортируемого массива с опорным и разделить исходный массив на два подмассива: с элементами меньше опорного и с элементами большие (или равные) опорного. &lt;br /&gt;
&lt;br /&gt;
3. Рекурсивно повторить алгоритм для получившихся подмассивов.&lt;br /&gt;
&lt;br /&gt;
Случайный выбор опорного элемента считается наиболее эффективным, так как при фиксировании позиции опорного элемента (например, в качестве опорного всегда берется элемент, стоящий на первой позиции) может привести к существенному снижению эффективности для массивов определенного вида из-за неравномерного распределения элементов в получившихся подмассивах. Также в качестве опорного элемента можно выбирать медиану массива, но считается, что вычисление медианы на каждой итерации рекурсивного алгоритма — слишком затратная операция.&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
Последовательная сложность данного алгоритма зависит от глубины рекурсии, что в свою очередь зависит от того, насколько удачно были выбраны опорные элементы на каждом витке рекурсии. Рассмотрим несколько возможных случаев.&lt;br /&gt;
&lt;br /&gt;
1. В наилучшем случае выбор опорного элемента на каждом витке рекурсии происходит таким образом, что в результате разбиения исходного массива образуются подмассивы одинаковой длины (с точностью до одного элемента). В таком случае глубина рекурсии составит &amp;lt;math&amp;gt; log_2 n &amp;lt;/math&amp;gt;, следовательно, общая сложность алгоритма равна &amp;lt;math&amp;gt; O(n log_2 n) &amp;lt;/math&amp;gt;. &amp;lt;ref&amp;gt; https://neerc.ifmo.ru/wiki/index.php?title=Быстрая_сортировка &amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
2. В наихудшем случае каждое разбиение приводит к образованию подмассивов длины &amp;lt;math&amp;gt; 1 &amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt; n - 1&amp;lt;/math&amp;gt; соответственно. Общая сложность алгоритма в таком случае равна &amp;lt;math&amp;gt; O(n^2) &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
Так как для проведения вычислений задействовано &amp;lt;math&amp;gt; p = 2^N &amp;lt;/math&amp;gt; процессоров, можно воспользоваться следующим алгоритмом распределения данных между процессорами. Распределим произвольным образом данные между процессорами, далее выбираем некоторым образом ведущий элемент и рассылаем его всем процессорам системы. Т.к. топология системы имеет вид n-мерного куба, номер каждого процессора имеет двоичное представление длины &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, следовательно, можно ввести правило: на каждом процессоре происходит сравнение имеющегося блока данных с текущим ведущим элементом, после чего элементы меньше ведущего отправляются от процессора с номером &amp;lt;math&amp;gt;n_1&amp;lt;/math&amp;gt; процессору номер &amp;lt;math&amp;gt;n_2&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;n_1&amp;lt;/math&amp;gt; отличается от &amp;lt;math&amp;gt;n_2&amp;lt;/math&amp;gt; только в n-том разряде двоичного представления, в двоичном представлении числа &amp;lt;math&amp;gt;n_1&amp;lt;/math&amp;gt; на n-той позиции стоит 1, а &amp;lt;math&amp;gt;n_2&amp;lt;/math&amp;gt; — 0. Таким образом, после данной операции все данные будут разделены между процессорами, образующими n-1-мерные кубы таким образом, что элемент блока данных любого процессора из первого куба больше любого элемента блока данных процессора из второго куба. Повторив аналогичные действия для каждого из n-1-мерных кубов, получим 4 n-2-мерных куба и т.д. &lt;br /&gt;
&lt;br /&gt;
Для наглядности приведем пример: пусть &amp;lt;math&amp;gt; p = 2^3 = 8 &amp;lt;/math&amp;gt;. Ниже приведены графы, иллюстрирующие распределение данных на каждой итерации.&lt;br /&gt;
&lt;br /&gt;
[[file:Gr 1.png|thumb|center|700px|Рисунок 1. Итерация 1.]]&lt;br /&gt;
[[file:Gr 2.png|thumb|center|700px|Рисунок 2. Итерация 2.]]&lt;br /&gt;
[[file:Gr 3.png|thumb|center|700px|Рисунок 3. Итерация 3.]]&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма алгоритма ===&lt;br /&gt;
Основной идеей данного алгоритма является разбиение всего массива данных на блоки меньшего размера таким образом, что между соответствующими блоками после разбиения можно установить отношение упорядоченности. Сортировка производится следующим образом: выбирается некоторым образом ведущий элемент, после чего происходит разделение исходного массива данных на два блока относительно ведущего элемента: в первый блок помещаются элементы, меньшие ведущего, а во второй — большие ведущего. Таким образом, можно утверждать, что наибольший элемент первого блока меньше наименьшего элемента второго блока. Это означает, что повторив эту операцию для каждого из блоков отдельно некоторое количество раз и объединив результаты, получим массив с исходными данными в отсортированном виде. Из описания становится очевидно, что данный алгоритм можно легко обобщить для параллельной вычислительной системы с количеством процессоров &amp;lt;math&amp;gt;p = 2^n&amp;lt;/math&amp;gt;. Для этого алгоритм необходимо лишь дополнить методом выбора процессоров, между которыми будут происходить обмены данными на i-ом шаге. Подробное описание метода распределения данных между вычислительными узлами можно найти в разделе 1.7. Последним этапом работы алгоритма является объединение разрозненных блоков отсортированных данных в единый массив в правильном порядке. Порядок объединения не трудно восстановить исходя из двоичных представлений номеров процессоров.&lt;br /&gt;
&lt;br /&gt;
Очевидно, что наиболее медленной операцией в описанной выше схеме является операция обмена данными между процессорами, следовательно, хотелось бы получить некоторую оценку количества обменов. Такая оценка приведена ниже:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\sum_{i=1}^{n} i = n(n+1)/2 ≈ \log^2 p &amp;lt;/math&amp;gt; &amp;lt;ref&amp;gt; http://ssd.sscc.ru/ru — Supercomputer Software Department &amp;lt;/ref&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt; p &amp;lt;/math&amp;gt; — количество задействованных процессоров.&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные алгоритма ===&lt;br /&gt;
&#039;&#039;&#039;Входные данные:&#039;&#039;&#039; любая числовая последовательность произвольной конечной длины. Так как параллельный алгоритм предполагает выбор разделяющего элемента случайным образом, построение последовательностей специального вида не приводит к увеличению вероятности неравномерного распределения данных между вычислительными узлами. Это значит, что эффективность алгоритма не зависит от вида входной последовательности. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные:&#039;&#039;&#039; последовательность чисел в отсортированном виде.&lt;br /&gt;
&lt;br /&gt;
=== Свойства алгоритма ===&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Особенности реализации последовательного алгоритма ===&lt;br /&gt;
&lt;br /&gt;
=== Локальность данных и вычислений ===&lt;br /&gt;
&lt;br /&gt;
=== Возможные способы и особенности параллельной реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
=== Масштабируемость алгоритма и его реализация ===&lt;br /&gt;
Проведём исследование масштабируемости параллельной реализации алгоритма быстрой сортировки согласно [[Scalability methodology|методике]]. Исследование проводится для числа процессоров [8 : 128] с шагом 8.&lt;br /&gt;
&lt;br /&gt;
[[file:User ashabokov 415 eff.png|thumb|center|700px|Рисунок 4. Изменение эффективности в зависимости от числа процессоров и входных данных.]]&lt;br /&gt;
&lt;br /&gt;
Далее построим оценку масштабируемости:&lt;br /&gt;
&lt;br /&gt;
1. По числу процессоров: 1.0581. Это значит, что с увеличением количества задействованных процессоров эффективность увеличивается. Такое поведение можно объяснить тем, что при увеличении числа процессоров размер сортируемого участка массива для каждого отдельного процессора уменьшается.&lt;br /&gt;
&lt;br /&gt;
2. По числу входных данных: -0.6059. Это значит, что с ростом размеров входных данных эффективность алгоритма падает. Это можно объяснить тем, что при алгоритм предполагает многократный обмен массивами данных, а это значит, что при увеличении размера задачи накладные расходы на обмен данными между процессорами тоже сильно возрастает.&lt;br /&gt;
&lt;br /&gt;
3. По двум направлениям: 0.0386. Это значит, что с ростом числа процессоров и размерами входных данных эффективность все же возрастает, но скорость не слишком велика.&lt;br /&gt;
&lt;br /&gt;
=== Динамические характеристики и эффективность реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
=== Выводы для классов архитектур ===&lt;br /&gt;
&lt;br /&gt;
=== Существующие реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Реализация алгоритма быстрой сортировки имеется во многих стандартных библиотеках. Например, для языков программирования C и C++ этот алгоритм можно найти в стандартных библиотеках stdlib.h и cstdlib соответственно. В языке программирования Python имеется встроенная функция sorted(). Также реализацию этого алгоритма можно найти в пакете LAPACK DLASRT.&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;br /&gt;
&amp;lt;references /&amp;gt;&lt;/div&gt;</summary>
		<author><name>Ashabokov 415</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Ashabokov_415/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%B1%D1%8B%D1%81%D1%82%D1%80%D0%BE%D0%B9_%D1%81%D0%BE%D1%80%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B8&amp;diff=27635</id>
		<title>Участник:Ashabokov 415/Алгоритм быстрой сортировки</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Ashabokov_415/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%B1%D1%8B%D1%81%D1%82%D1%80%D0%BE%D0%B9_%D1%81%D0%BE%D1%80%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B8&amp;diff=27635"/>
		<updated>2019-12-02T14:38:48Z</updated>

		<summary type="html">&lt;p&gt;Ashabokov 415: /* Математическое описание алгоритма */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&#039;&#039;&#039;Алгоритм быстрой сортировки&#039;&#039;&#039; &lt;br /&gt;
&lt;br /&gt;
== Свойства и структура алгоритмов ==&lt;br /&gt;
&lt;br /&gt;
=== Общее описание алгоритма &amp;lt;ref&amp;gt; https://en.wikipedia.org/wiki/Quicksort — From Wikipedia, the free encyclopedia &amp;lt;/ref&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
Быстрая сортировка, сортировка Хоара —  широко известный алгоритм сортировки, разработанный английским информатиком Чарльзом Хоаром во время его работы в МГУ в 1960 году.&lt;br /&gt;
&lt;br /&gt;
Один из самых быстрых известных универсальных алгоритмов сортировки массивов: в среднем  &amp;lt;math&amp;gt; O (n \log n) &amp;lt;/math&amp;gt; обменов при упорядочении &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; элементов; из-за наличия ряда недостатков на практике обычно используется с некоторыми доработками. Фактически данный алгоритм является улучшением алгоритма сортировки прямого обмена (см. ниже).&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
Алгоритм состоит из трех основных шагов:&lt;br /&gt;
&lt;br /&gt;
1. Выбрать опорный элемент (см. ниже). Пусть это будет элемент &amp;lt;math&amp;gt; a&#039; &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
2. Используя операции сравнения элементов массива с опорным и перестановки элементов массива, привести исходный массив к виду: &amp;lt;math&amp;gt; a_1 ... a_m a&#039; a_{m+2} ... a_n &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt; a_j &amp;lt; a&#039;, j = 1 ... m &amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt; a_i \geq a&#039;, i = (m+1) ... n  &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; — длина массива.&lt;br /&gt;
&lt;br /&gt;
3. Рекурсивно применить алгоритм к каждому из массивов: &amp;lt;math&amp;gt; a_1 ... a_m &amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt; a_{m+1} ... a_n &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Рассмотрим подробнее метод сравнения и перестановки данных в массиве, применяющийся на шаге 2. Для этого часто используют так называемое разбиение Хоара &amp;lt;ref&amp;gt; https://en.wikipedia.org/wiki/Quicksort — From Wikipedia, the free encyclopedia &amp;lt;/ref&amp;gt;. Суть данного метода заключается в следующем: выбираются два указателя, указывающие на первый и последний элементы массива соответственно, пусть для наглядности это будут &amp;lt;math&amp;gt; i = 1 &amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt; j = n &amp;lt;/math&amp;gt;. Далее начинаем сдвигать левый указатель вправо, в правый — влево до тех пор, пока выполнены условия: &amp;lt;math&amp;gt; a_i &amp;lt; a&#039;, a_j \geq a&#039;, i &amp;lt; j &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt; a&#039; &amp;lt;/math&amp;gt; — опорный элемент. Как только найдутся такие &amp;lt;math&amp;gt; i, j &amp;lt;/math&amp;gt;, что &amp;lt;math&amp;gt; a_i \geq a&#039;, a_j &amp;lt; a&#039; &amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt; i &amp;lt; j &amp;lt;/math&amp;gt;, производим перестановку этих двух элементов. Продолжаем этот процесс до тех пор, пока выполнено &amp;lt;math&amp;gt; i &amp;lt; j &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
Вычислительным ядром данного алгоритма являются операции сравнения и перестановки &amp;lt;math&amp;gt; i&amp;lt;/math&amp;gt;-ого и &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;-ого элементов массива на каждой итерации рекурсивного алгоритма.&lt;br /&gt;
&lt;br /&gt;
Сложность операции разделения массива на два подмассива (сравнение и перестановка элементов массива относительно опорного элемента) занимет время &amp;lt;math&amp;gt; O (log_2 n) &amp;lt;/math&amp;gt;. &amp;lt;ref&amp;gt; https://ru.wikipedia.org/wiki/Быстрая_сортировка &amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
Как и написано выше в разделе &amp;quot;Вычислительное ядро алгоритма&amp;quot;, основную часть данного метода сортировки составляет операция разделения массива относительно опорного элемента, которая в свою очередь состоит из операций сравнения и перестановки.&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма ===&lt;br /&gt;
1. Случайным образом выбрать опорный элемент массива.&lt;br /&gt;
&lt;br /&gt;
2. Сравнить все элементы сортируемого массива с опорным и разделить исходный массив на два подмассива: с элементами меньше опорного и с элементами большие (или равные) опорного. &lt;br /&gt;
&lt;br /&gt;
3. Рекурсивно повторить алгоритм для получившихся подмассивов.&lt;br /&gt;
&lt;br /&gt;
Случайный выбор опорного элемента считается наиболее эффективным, так как при фиксировании позиции опорного элемента (например, в качестве опорного всегда берется элемент, стоящий на первой позиции) может привести к существенному снижению эффективности для массивов определенного вида из-за неравномерного распределения элементов в получившихся подмассивах. Также в качестве опорного элемента можно выбирать медиану массива, но считается, что вычисление медианы на каждой итерации рекурсивного алгоритма — слишком затратная операция.&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
Последовательная сложность данного алгоритма зависит от глубины рекурсии, что в свою очередь зависит от того, насколько удачно были выбраны опорные элементы на каждом витке рекурсии. Рассмотрим несколько возможных случаев.&lt;br /&gt;
&lt;br /&gt;
1. В наилучшем случае выбор опорного элемента на каждом витке рекурсии происходит таким образом, что в результате разбиения исходного массива образуются подмассивы одинаковой длины (с точностью до одного элемента). В таком случае глубина рекурсии составит &amp;lt;math&amp;gt; log_2 n &amp;lt;/math&amp;gt;, следовательно, общая сложность алгоритма равна &amp;lt;math&amp;gt; O(n log_2 n) &amp;lt;/math&amp;gt;. &amp;lt;ref&amp;gt; https://neerc.ifmo.ru/wiki/index.php?title=Быстрая_сортировка &amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
2. В наихудшем случае каждое разбиение приводит к образованию подмассивов длины &amp;lt;math&amp;gt; 1 &amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt; n - 1&amp;lt;/math&amp;gt; соответственно. Общая сложность алгоритма в таком случае равна &amp;lt;math&amp;gt; O(n^2) &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
Так как для проведения вычислений задействовано &amp;lt;math&amp;gt; p = 2^N &amp;lt;/math&amp;gt; процессоров, можно воспользоваться следующим алгоритмом распределения данных между процессорами. Распределим произвольным образом данные между процессорами, далее выбираем некоторым образом ведущий элемент и рассылаем его всем процессорам системы. Т.к. топология системы имеет вид n-мерного куба, номер каждого процессора имеет двоичное представление длины &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, следовательно, можно ввести правило: на каждом процессоре происходит сравнение имеющегося блока данных с текущим ведущим элементом, после чего элементы меньше ведущего отправляются от процессора с номером &amp;lt;math&amp;gt;n_1&amp;lt;/math&amp;gt; процессору номер &amp;lt;math&amp;gt;n_2&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;n_1&amp;lt;/math&amp;gt; отличается от &amp;lt;math&amp;gt;n_2&amp;lt;/math&amp;gt; только в n-том разряде двоичного представления, в двоичном представлении числа &amp;lt;math&amp;gt;n_1&amp;lt;/math&amp;gt; на n-той позиции стоит 1, а &amp;lt;math&amp;gt;n_2&amp;lt;/math&amp;gt; — 0. Таким образом, после данной операции все данные будут разделены между процессорами, образующими n-1-мерные кубы таким образом, что элемент блока данных любого процессора из первого куба больше любого элемента блока данных процессора из второго куба. Повторив аналогичные действия для каждого из n-1-мерных кубов, получим 4 n-2-мерных куба и т.д. &lt;br /&gt;
&lt;br /&gt;
Для наглядности приведем пример: пусть &amp;lt;math&amp;gt; p = 2^3 = 8 &amp;lt;/math&amp;gt;. Ниже приведены графы, иллюстрирующие распределение данных на каждой итерации.&lt;br /&gt;
&lt;br /&gt;
[[file:Gr 1.png|thumb|center|700px|Рисунок 1. Итерация 1.]]&lt;br /&gt;
[[file:Gr 2.png|thumb|center|700px|Рисунок 2. Итерация 2.]]&lt;br /&gt;
[[file:Gr 3.png|thumb|center|700px|Рисунок 3. Итерация 3.]]&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма алгоритма ===&lt;br /&gt;
Основной идеей данного алгоритма является разбиение всего массива данных на блоки меньшего размера таким образом, что между соответствующими блоками после разбиения можно установить отношение упорядоченности. Сортировка производится следующим образом: выбирается некоторым образом ведущий элемент, после чего происходит разделение исходного массива данных на два блока относительно ведущего элемента: в первый блок помещаются элементы, меньшие ведущего, а во второй — большие ведущего. Таким образом, можно утверждать, что наибольший элемент первого блока меньше наименьшего элемента второго блока. Это означает, что повторив эту операцию для каждого из блоков отдельно некоторое количество раз и объединив результаты, получим массив с исходными данными в отсортированном виде. Из описания становится очевидно, что данный алгоритм можно легко обобщить для параллельной вычислительной системы с количеством процессоров &amp;lt;math&amp;gt;p = 2^n&amp;lt;/math&amp;gt;. Для этого алгоритм необходимо лишь дополнить методом выбора процессоров, между которыми будут происходить обмены данными на i-ом шаге. Подробное описание метода распределения данных между вычислительными узлами можно найти в разделе 1.7. Последним этапом работы алгоритма является объединение разрозненных блоков отсортированных данных в единый массив в правильном порядке. Порядок объединения не трудно восстановить исходя из двоичных представлений номеров процессоров.&lt;br /&gt;
&lt;br /&gt;
Очевидно, что наиболее медленной операцией в описанной выше схеме является операция обмена данными между процессорами, следовательно, хотелось бы получить некоторую оценку количества обменов. Такая оценка приведена ниже:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\sum_{i=1}^{n} i = n(n+1)/2 ≈ \log^2 p &amp;lt;/math&amp;gt; &amp;lt;ref&amp;gt; http://ssd.sscc.ru/ru — Supercomputer Software Department &amp;lt;/ref&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt; p &amp;lt;/math&amp;gt; — количество задействованных процессоров.&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные алгоритма ===&lt;br /&gt;
&#039;&#039;&#039;Входные данные:&#039;&#039;&#039; любая числовая последовательность произвольной конечной длины. Так как параллельный алгоритм предполагает выбор разделяющего элемента случайным образом, построение последовательностей специального вида не приводит к увеличению вероятности неравномерного распределения данных между вычислительными узлами. Это значит, что эффективность алгоритма не зависит от вида входной последовательности. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные:&#039;&#039;&#039; последовательность чисел в отсортированном виде.&lt;br /&gt;
&lt;br /&gt;
=== Свойства алгоритма ===&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Особенности реализации последовательного алгоритма ===&lt;br /&gt;
&lt;br /&gt;
=== Локальность данных и вычислений ===&lt;br /&gt;
&lt;br /&gt;
=== Возможные способы и особенности параллельной реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
=== Масштабируемость алгоритма и его реализация ===&lt;br /&gt;
Проведём исследование масштабируемости параллельной реализации алгоритма быстрой сортировки согласно [[Scalability methodology|методике]]. Исследование проводится для числа процессоров [8 : 128] с шагом 8.&lt;br /&gt;
&lt;br /&gt;
[[file:User ashabokov 415 eff.png|thumb|center|700px|Рисунок 4. Изменение эффективности в зависимости от числа процессоров и входных данных.]]&lt;br /&gt;
&lt;br /&gt;
Далее построим оценку масштабируемости:&lt;br /&gt;
&lt;br /&gt;
1. По числу процессоров: 1.0581. Это значит, что с увеличением количества задействованных процессоров эффективность увеличивается. Такое поведение можно объяснить тем, что при увеличении числа процессоров размер сортируемого участка массива для каждого отдельного процессора уменьшается.&lt;br /&gt;
&lt;br /&gt;
2. По числу входных данных: -0.6059. Это значит, что с ростом размеров входных данных эффективность алгоритма падает. Это можно объяснить тем, что при алгоритм предполагает многократный обмен массивами данных, а это значит, что при увеличении размера задачи накладные расходы на обмен данными между процессорами тоже сильно возрастает.&lt;br /&gt;
&lt;br /&gt;
3. По двум направлениям: 0.0386. Это значит, что с ростом числа процессоров и размерами входных данных эффективность все же возрастает, но скорость не слишком велика.&lt;br /&gt;
&lt;br /&gt;
=== Динамические характеристики и эффективность реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
=== Выводы для классов архитектур ===&lt;br /&gt;
&lt;br /&gt;
=== Существующие реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Реализация алгоритма быстрой сортировки имеется во многих стандартных библиотеках. Например, для языков программирования C и C++ этот алгоритм можно найти в стандартных библиотеках stdlib.h и cstdlib соответственно. В языке программирования Python имеется встроенная функция sorted(). Также реализацию этого алгоритма можно найти в пакете LAPACK DLASRT.&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;br /&gt;
&amp;lt;references /&amp;gt;&lt;/div&gt;</summary>
		<author><name>Ashabokov 415</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Ashabokov_415/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%B1%D1%8B%D1%81%D1%82%D1%80%D0%BE%D0%B9_%D1%81%D0%BE%D1%80%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B8&amp;diff=27634</id>
		<title>Участник:Ashabokov 415/Алгоритм быстрой сортировки</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Ashabokov_415/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%B1%D1%8B%D1%81%D1%82%D1%80%D0%BE%D0%B9_%D1%81%D0%BE%D1%80%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B8&amp;diff=27634"/>
		<updated>2019-12-02T11:46:08Z</updated>

		<summary type="html">&lt;p&gt;Ashabokov 415: /* Масштабируемость алгоритма и его реализация */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&#039;&#039;&#039;Алгоритм быстрой сортировки&#039;&#039;&#039; &lt;br /&gt;
&lt;br /&gt;
== Свойства и структура алгоритмов ==&lt;br /&gt;
&lt;br /&gt;
=== Общее описание алгоритма &amp;lt;ref&amp;gt; https://en.wikipedia.org/wiki/Quicksort — From Wikipedia, the free encyclopedia &amp;lt;/ref&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
Быстрая сортировка, сортировка Хоара —  широко известный алгоритм сортировки, разработанный английским информатиком Чарльзом Хоаром во время его работы в МГУ в 1960 году.&lt;br /&gt;
&lt;br /&gt;
Один из самых быстрых известных универсальных алгоритмов сортировки массивов: в среднем  &amp;lt;math&amp;gt; O (n \log n) &amp;lt;/math&amp;gt; обменов при упорядочении &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; элементов; из-за наличия ряда недостатков на практике обычно используется с некоторыми доработками. Фактически данный алгоритм является улучшением алгоритма сортировки прямого обмена (см. ниже).&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
Алгоритм состоит из трех основных шагов:&lt;br /&gt;
&lt;br /&gt;
1. Выбрать опорный элемент (см. ниже). Пусть это будет элемент &amp;lt;math&amp;gt; a&#039; &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
2. Используя операции сравнения элементов массива с опорным и перестановки элементов массива, привести исходный массив к виду: &amp;lt;math&amp;gt; a_1 ... a_m a&#039; a_{m+2} ... a_n &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt; a_j &amp;lt; a&#039;, j = 1 ... m &amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt; a_i \geq a&#039;, i = (m+1) ... n  &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; — длина массива.&lt;br /&gt;
&lt;br /&gt;
3. Рекурсивно применить алгоритм к каждому из массивов: &amp;lt;math&amp;gt; a_1 ... a_m &amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt; a_{m+1} ... a_n &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Рассмотрим подробнее метод сравнения и перестановки данных в массиве, применяющийся на шаге 2. Для этого часто используют так называемое разбиение Хоара &amp;lt;ref&amp;gt; https://en.wikipedia.org/wiki/Quicksort — From Wikipedia, the free encyclopedia &amp;lt;/ref&amp;gt;. Суть данного метода заключается в следующем: выбираются два указателя, указывающие на первый и последний элементы массива соответственно, пость для наглядности это будут &amp;lt;math&amp;gt; i = 1 &amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt; j = n &amp;lt;/math&amp;gt;. Далее начинаем сдвигать левый указатель вправо, в правый — влево до тех пор, пока выполнены условия: &amp;lt;math&amp;gt; a_i &amp;lt; a&#039;, a_j \geq a&#039;, i &amp;lt; j &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt; a&#039; &amp;lt;/math&amp;gt; — опорный элемент. Как только найдутся такие &amp;lt;math&amp;gt; i, j &amp;lt;/math&amp;gt;, что &amp;lt;math&amp;gt; a_i \geq a&#039;, a_j &amp;lt; a&#039; &amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt; i &amp;lt; j &amp;lt;/math&amp;gt;, производим перестановку этих двух элементов. Продолжаем этот процесс до тех пор, пока выполнено &amp;lt;math&amp;gt; i &amp;lt; j &amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
Вычислительным ядром данного алгоритма являются операции сравнения и перестановки &amp;lt;math&amp;gt; i&amp;lt;/math&amp;gt;-ого и &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;-ого элементов массива на каждой итерации рекурсивного алгоритма.&lt;br /&gt;
&lt;br /&gt;
Сложность операции разделения массива на два подмассива (сравнение и перестановка элементов массива относительно опорного элемента) занимет время &amp;lt;math&amp;gt; O (log_2 n) &amp;lt;/math&amp;gt;. &amp;lt;ref&amp;gt; https://ru.wikipedia.org/wiki/Быстрая_сортировка &amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
Как и написано выше в разделе &amp;quot;Вычислительное ядро алгоритма&amp;quot;, основную часть данного метода сортировки составляет операция разделения массива относительно опорного элемента, которая в свою очередь состоит из операций сравнения и перестановки.&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма ===&lt;br /&gt;
1. Случайным образом выбрать опорный элемент массива.&lt;br /&gt;
&lt;br /&gt;
2. Сравнить все элементы сортируемого массива с опорным и разделить исходный массив на два подмассива: с элементами меньше опорного и с элементами большие (или равные) опорного. &lt;br /&gt;
&lt;br /&gt;
3. Рекурсивно повторить алгоритм для получившихся подмассивов.&lt;br /&gt;
&lt;br /&gt;
Случайный выбор опорного элемента считается наиболее эффективным, так как при фиксировании позиции опорного элемента (например, в качестве опорного всегда берется элемент, стоящий на первой позиции) может привести к существенному снижению эффективности для массивов определенного вида из-за неравномерного распределения элементов в получившихся подмассивах. Также в качестве опорного элемента можно выбирать медиану массива, но считается, что вычисление медианы на каждой итерации рекурсивного алгоритма — слишком затратная операция.&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
Последовательная сложность данного алгоритма зависит от глубины рекурсии, что в свою очередь зависит от того, насколько удачно были выбраны опорные элементы на каждом витке рекурсии. Рассмотрим несколько возможных случаев.&lt;br /&gt;
&lt;br /&gt;
1. В наилучшем случае выбор опорного элемента на каждом витке рекурсии происходит таким образом, что в результате разбиения исходного массива образуются подмассивы одинаковой длины (с точностью до одного элемента). В таком случае глубина рекурсии составит &amp;lt;math&amp;gt; log_2 n &amp;lt;/math&amp;gt;, следовательно, общая сложность алгоритма равна &amp;lt;math&amp;gt; O(n log_2 n) &amp;lt;/math&amp;gt;. &amp;lt;ref&amp;gt; https://neerc.ifmo.ru/wiki/index.php?title=Быстрая_сортировка &amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
2. В наихудшем случае каждое разбиение приводит к образованию подмассивов длины &amp;lt;math&amp;gt; 1 &amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt; n - 1&amp;lt;/math&amp;gt; соответственно. Общая сложность алгоритма в таком случае равна &amp;lt;math&amp;gt; O(n^2) &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
Так как для проведения вычислений задействовано &amp;lt;math&amp;gt; p = 2^N &amp;lt;/math&amp;gt; процессоров, можно воспользоваться следующим алгоритмом распределения данных между процессорами. Распределим произвольным образом данные между процессорами, далее выбираем некоторым образом ведущий элемент и рассылаем его всем процессорам системы. Т.к. топология системы имеет вид n-мерного куба, номер каждого процессора имеет двоичное представление длины &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, следовательно, можно ввести правило: на каждом процессоре происходит сравнение имеющегося блока данных с текущим ведущим элементом, после чего элементы меньше ведущего отправляются от процессора с номером &amp;lt;math&amp;gt;n_1&amp;lt;/math&amp;gt; процессору номер &amp;lt;math&amp;gt;n_2&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;n_1&amp;lt;/math&amp;gt; отличается от &amp;lt;math&amp;gt;n_2&amp;lt;/math&amp;gt; только в n-том разряде двоичного представления, в двоичном представлении числа &amp;lt;math&amp;gt;n_1&amp;lt;/math&amp;gt; на n-той позиции стоит 1, а &amp;lt;math&amp;gt;n_2&amp;lt;/math&amp;gt; — 0. Таким образом, после данной операции все данные будут разделены между процессорами, образующими n-1-мерные кубы таким образом, что элемент блока данных любого процессора из первого куба больше любого элемента блока данных процессора из второго куба. Повторив аналогичные действия для каждого из n-1-мерных кубов, получим 4 n-2-мерных куба и т.д. &lt;br /&gt;
&lt;br /&gt;
Для наглядности приведем пример: пусть &amp;lt;math&amp;gt; p = 2^3 = 8 &amp;lt;/math&amp;gt;. Ниже приведены графы, иллюстрирующие распределение данных на каждой итерации.&lt;br /&gt;
&lt;br /&gt;
[[file:Gr 1.png|thumb|center|700px|Рисунок 1. Итерация 1.]]&lt;br /&gt;
[[file:Gr 2.png|thumb|center|700px|Рисунок 2. Итерация 2.]]&lt;br /&gt;
[[file:Gr 3.png|thumb|center|700px|Рисунок 3. Итерация 3.]]&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма алгоритма ===&lt;br /&gt;
Основной идеей данного алгоритма является разбиение всего массива данных на блоки меньшего размера таким образом, что между соответствующими блоками после разбиения можно установить отношение упорядоченности. Сортировка производится следующим образом: выбирается некоторым образом ведущий элемент, после чего происходит разделение исходного массива данных на два блока относительно ведущего элемента: в первый блок помещаются элементы, меньшие ведущего, а во второй — большие ведущего. Таким образом, можно утверждать, что наибольший элемент первого блока меньше наименьшего элемента второго блока. Это означает, что повторив эту операцию для каждого из блоков отдельно некоторое количество раз и объединив результаты, получим массив с исходными данными в отсортированном виде. Из описания становится очевидно, что данный алгоритм можно легко обобщить для параллельной вычислительной системы с количеством процессоров &amp;lt;math&amp;gt;p = 2^n&amp;lt;/math&amp;gt;. Для этого алгоритм необходимо лишь дополнить методом выбора процессоров, между которыми будут происходить обмены данными на i-ом шаге. Подробное описание метода распределения данных между вычислительными узлами можно найти в разделе 1.7. Последним этапом работы алгоритма является объединение разрозненных блоков отсортированных данных в единый массив в правильном порядке. Порядок объединения не трудно восстановить исходя из двоичных представлений номеров процессоров.&lt;br /&gt;
&lt;br /&gt;
Очевидно, что наиболее медленной операцией в описанной выше схеме является операция обмена данными между процессорами, следовательно, хотелось бы получить некоторую оценку количества обменов. Такая оценка приведена ниже:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\sum_{i=1}^{n} i = n(n+1)/2 ≈ \log^2 p &amp;lt;/math&amp;gt; &amp;lt;ref&amp;gt; http://ssd.sscc.ru/ru — Supercomputer Software Department &amp;lt;/ref&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt; p &amp;lt;/math&amp;gt; — количество задействованных процессоров.&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные алгоритма ===&lt;br /&gt;
&#039;&#039;&#039;Входные данные:&#039;&#039;&#039; любая числовая последовательность произвольной конечной длины. Так как параллельный алгоритм предполагает выбор разделяющего элемента случайным образом, построение последовательностей специального вида не приводит к увеличению вероятности неравномерного распределения данных между вычислительными узлами. Это значит, что эффективность алгоритма не зависит от вида входной последовательности. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные:&#039;&#039;&#039; последовательность чисел в отсортированном виде.&lt;br /&gt;
&lt;br /&gt;
=== Свойства алгоритма ===&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Особенности реализации последовательного алгоритма ===&lt;br /&gt;
&lt;br /&gt;
=== Локальность данных и вычислений ===&lt;br /&gt;
&lt;br /&gt;
=== Возможные способы и особенности параллельной реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
=== Масштабируемость алгоритма и его реализация ===&lt;br /&gt;
Проведём исследование масштабируемости параллельной реализации алгоритма быстрой сортировки согласно [[Scalability methodology|методике]]. Исследование проводится для числа процессоров [8 : 128] с шагом 8.&lt;br /&gt;
&lt;br /&gt;
[[file:User ashabokov 415 eff.png|thumb|center|700px|Рисунок 4. Изменение эффективности в зависимости от числа процессоров и входных данных.]]&lt;br /&gt;
&lt;br /&gt;
Далее построим оценку масштабируемости:&lt;br /&gt;
&lt;br /&gt;
1. По числу процессоров: 1.0581. Это значит, что с увеличением количества задействованных процессоров эффективность увеличивается. Такое поведение можно объяснить тем, что при увеличении числа процессоров размер сортируемого участка массива для каждого отдельного процессора уменьшается.&lt;br /&gt;
&lt;br /&gt;
2. По числу входных данных: -0.6059. Это значит, что с ростом размеров входных данных эффективность алгоритма падает. Это можно объяснить тем, что при алгоритм предполагает многократный обмен массивами данных, а это значит, что при увеличении размера задачи накладные расходы на обмен данными между процессорами тоже сильно возрастает.&lt;br /&gt;
&lt;br /&gt;
3. По двум направлениям: 0.0386. Это значит, что с ростом числа процессоров и размерами входных данных эффективность все же возрастает, но скорость не слишком велика.&lt;br /&gt;
&lt;br /&gt;
=== Динамические характеристики и эффективность реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
=== Выводы для классов архитектур ===&lt;br /&gt;
&lt;br /&gt;
=== Существующие реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Реализация алгоритма быстрой сортировки имеется во многих стандартных библиотеках. Например, для языков программирования C и C++ этот алгоритм можно найти в стандартных библиотеках stdlib.h и cstdlib соответственно. В языке программирования Python имеется встроенная функция sorted(). Также реализацию этого алгоритма можно найти в пакете LAPACK DLASRT.&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;br /&gt;
&amp;lt;references /&amp;gt;&lt;/div&gt;</summary>
		<author><name>Ashabokov 415</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Ashabokov_415/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%B1%D1%8B%D1%81%D1%82%D1%80%D0%BE%D0%B9_%D1%81%D0%BE%D1%80%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B8&amp;diff=27633</id>
		<title>Участник:Ashabokov 415/Алгоритм быстрой сортировки</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Ashabokov_415/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%B1%D1%8B%D1%81%D1%82%D1%80%D0%BE%D0%B9_%D1%81%D0%BE%D1%80%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B8&amp;diff=27633"/>
		<updated>2019-12-02T06:41:23Z</updated>

		<summary type="html">&lt;p&gt;Ashabokov 415: /* Последовательная сложность алгоритма */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&#039;&#039;&#039;Алгоритм быстрой сортировки&#039;&#039;&#039; &lt;br /&gt;
&lt;br /&gt;
== Свойства и структура алгоритмов ==&lt;br /&gt;
&lt;br /&gt;
=== Общее описание алгоритма &amp;lt;ref&amp;gt; https://en.wikipedia.org/wiki/Quicksort — From Wikipedia, the free encyclopedia &amp;lt;/ref&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
Быстрая сортировка, сортировка Хоара —  широко известный алгоритм сортировки, разработанный английским информатиком Чарльзом Хоаром во время его работы в МГУ в 1960 году.&lt;br /&gt;
&lt;br /&gt;
Один из самых быстрых известных универсальных алгоритмов сортировки массивов: в среднем  &amp;lt;math&amp;gt; O (n \log n) &amp;lt;/math&amp;gt; обменов при упорядочении &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; элементов; из-за наличия ряда недостатков на практике обычно используется с некоторыми доработками. Фактически данный алгоритм является улучшением алгоритма сортировки прямого обмена (см. ниже).&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
Алгоритм состоит из трех основных шагов:&lt;br /&gt;
&lt;br /&gt;
1. Выбрать опорный элемент (см. ниже). Пусть это будет элемент &amp;lt;math&amp;gt; a&#039; &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
2. Используя операции сравнения элементов массива с опорным и перестановки элементов массива, привести исходный массив к виду: &amp;lt;math&amp;gt; a_1 ... a_m a&#039; a_{m+2} ... a_n &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt; a_j &amp;lt; a&#039;, j = 1 ... m &amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt; a_i \geq a&#039;, i = (m+1) ... n  &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; — длина массива.&lt;br /&gt;
&lt;br /&gt;
3. Рекурсивно применить алгоритм к каждому из массивов: &amp;lt;math&amp;gt; a_1 ... a_m &amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt; a_{m+1} ... a_n &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Рассмотрим подробнее метод сравнения и перестановки данных в массиве, применяющийся на шаге 2. Для этого часто используют так называемое разбиение Хоара &amp;lt;ref&amp;gt; https://en.wikipedia.org/wiki/Quicksort — From Wikipedia, the free encyclopedia &amp;lt;/ref&amp;gt;. Суть данного метода заключается в следующем: выбираются два указателя, указывающие на первый и последний элементы массива соответственно, пость для наглядности это будут &amp;lt;math&amp;gt; i = 1 &amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt; j = n &amp;lt;/math&amp;gt;. Далее начинаем сдвигать левый указатель вправо, в правый — влево до тех пор, пока выполнены условия: &amp;lt;math&amp;gt; a_i &amp;lt; a&#039;, a_j \geq a&#039;, i &amp;lt; j &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt; a&#039; &amp;lt;/math&amp;gt; — опорный элемент. Как только найдутся такие &amp;lt;math&amp;gt; i, j &amp;lt;/math&amp;gt;, что &amp;lt;math&amp;gt; a_i \geq a&#039;, a_j &amp;lt; a&#039; &amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt; i &amp;lt; j &amp;lt;/math&amp;gt;, производим перестановку этих двух элементов. Продолжаем этот процесс до тех пор, пока выполнено &amp;lt;math&amp;gt; i &amp;lt; j &amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
Вычислительным ядром данного алгоритма являются операции сравнения и перестановки &amp;lt;math&amp;gt; i&amp;lt;/math&amp;gt;-ого и &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;-ого элементов массива на каждой итерации рекурсивного алгоритма.&lt;br /&gt;
&lt;br /&gt;
Сложность операции разделения массива на два подмассива (сравнение и перестановка элементов массива относительно опорного элемента) занимет время &amp;lt;math&amp;gt; O (log_2 n) &amp;lt;/math&amp;gt;. &amp;lt;ref&amp;gt; https://ru.wikipedia.org/wiki/Быстрая_сортировка &amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
Как и написано выше в разделе &amp;quot;Вычислительное ядро алгоритма&amp;quot;, основную часть данного метода сортировки составляет операция разделения массива относительно опорного элемента, которая в свою очередь состоит из операций сравнения и перестановки.&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма ===&lt;br /&gt;
1. Случайным образом выбрать опорный элемент массива.&lt;br /&gt;
&lt;br /&gt;
2. Сравнить все элементы сортируемого массива с опорным и разделить исходный массив на два подмассива: с элементами меньше опорного и с элементами большие (или равные) опорного. &lt;br /&gt;
&lt;br /&gt;
3. Рекурсивно повторить алгоритм для получившихся подмассивов.&lt;br /&gt;
&lt;br /&gt;
Случайный выбор опорного элемента считается наиболее эффективным, так как при фиксировании позиции опорного элемента (например, в качестве опорного всегда берется элемент, стоящий на первой позиции) может привести к существенному снижению эффективности для массивов определенного вида из-за неравномерного распределения элементов в получившихся подмассивах. Также в качестве опорного элемента можно выбирать медиану массива, но считается, что вычисление медианы на каждой итерации рекурсивного алгоритма — слишком затратная операция.&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
Последовательная сложность данного алгоритма зависит от глубины рекурсии, что в свою очередь зависит от того, насколько удачно были выбраны опорные элементы на каждом витке рекурсии. Рассмотрим несколько возможных случаев.&lt;br /&gt;
&lt;br /&gt;
1. В наилучшем случае выбор опорного элемента на каждом витке рекурсии происходит таким образом, что в результате разбиения исходного массива образуются подмассивы одинаковой длины (с точностью до одного элемента). В таком случае глубина рекурсии составит &amp;lt;math&amp;gt; log_2 n &amp;lt;/math&amp;gt;, следовательно, общая сложность алгоритма равна &amp;lt;math&amp;gt; O(n log_2 n) &amp;lt;/math&amp;gt;. &amp;lt;ref&amp;gt; https://neerc.ifmo.ru/wiki/index.php?title=Быстрая_сортировка &amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
2. В наихудшем случае каждое разбиение приводит к образованию подмассивов длины &amp;lt;math&amp;gt; 1 &amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt; n - 1&amp;lt;/math&amp;gt; соответственно. Общая сложность алгоритма в таком случае равна &amp;lt;math&amp;gt; O(n^2) &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
Так как для проведения вычислений задействовано &amp;lt;math&amp;gt; p = 2^N &amp;lt;/math&amp;gt; процессоров, можно воспользоваться следующим алгоритмом распределения данных между процессорами. Распределим произвольным образом данные между процессорами, далее выбираем некоторым образом ведущий элемент и рассылаем его всем процессорам системы. Т.к. топология системы имеет вид n-мерного куба, номер каждого процессора имеет двоичное представление длины &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, следовательно, можно ввести правило: на каждом процессоре происходит сравнение имеющегося блока данных с текущим ведущим элементом, после чего элементы меньше ведущего отправляются от процессора с номером &amp;lt;math&amp;gt;n_1&amp;lt;/math&amp;gt; процессору номер &amp;lt;math&amp;gt;n_2&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;n_1&amp;lt;/math&amp;gt; отличается от &amp;lt;math&amp;gt;n_2&amp;lt;/math&amp;gt; только в n-том разряде двоичного представления, в двоичном представлении числа &amp;lt;math&amp;gt;n_1&amp;lt;/math&amp;gt; на n-той позиции стоит 1, а &amp;lt;math&amp;gt;n_2&amp;lt;/math&amp;gt; — 0. Таким образом, после данной операции все данные будут разделены между процессорами, образующими n-1-мерные кубы таким образом, что элемент блока данных любого процессора из первого куба больше любого элемента блока данных процессора из второго куба. Повторив аналогичные действия для каждого из n-1-мерных кубов, получим 4 n-2-мерных куба и т.д. &lt;br /&gt;
&lt;br /&gt;
Для наглядности приведем пример: пусть &amp;lt;math&amp;gt; p = 2^3 = 8 &amp;lt;/math&amp;gt;. Ниже приведены графы, иллюстрирующие распределение данных на каждой итерации.&lt;br /&gt;
&lt;br /&gt;
[[file:Gr 1.png|thumb|center|700px|Рисунок 1. Итерация 1.]]&lt;br /&gt;
[[file:Gr 2.png|thumb|center|700px|Рисунок 2. Итерация 2.]]&lt;br /&gt;
[[file:Gr 3.png|thumb|center|700px|Рисунок 3. Итерация 3.]]&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма алгоритма ===&lt;br /&gt;
Основной идеей данного алгоритма является разбиение всего массива данных на блоки меньшего размера таким образом, что между соответствующими блоками после разбиения можно установить отношение упорядоченности. Сортировка производится следующим образом: выбирается некоторым образом ведущий элемент, после чего происходит разделение исходного массива данных на два блока относительно ведущего элемента: в первый блок помещаются элементы, меньшие ведущего, а во второй — большие ведущего. Таким образом, можно утверждать, что наибольший элемент первого блока меньше наименьшего элемента второго блока. Это означает, что повторив эту операцию для каждого из блоков отдельно некоторое количество раз и объединив результаты, получим массив с исходными данными в отсортированном виде. Из описания становится очевидно, что данный алгоритм можно легко обобщить для параллельной вычислительной системы с количеством процессоров &amp;lt;math&amp;gt;p = 2^n&amp;lt;/math&amp;gt;. Для этого алгоритм необходимо лишь дополнить методом выбора процессоров, между которыми будут происходить обмены данными на i-ом шаге. Подробное описание метода распределения данных между вычислительными узлами можно найти в разделе 1.7. Последним этапом работы алгоритма является объединение разрозненных блоков отсортированных данных в единый массив в правильном порядке. Порядок объединения не трудно восстановить исходя из двоичных представлений номеров процессоров.&lt;br /&gt;
&lt;br /&gt;
Очевидно, что наиболее медленной операцией в описанной выше схеме является операция обмена данными между процессорами, следовательно, хотелось бы получить некоторую оценку количества обменов. Такая оценка приведена ниже:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\sum_{i=1}^{n} i = n(n+1)/2 ≈ \log^2 p &amp;lt;/math&amp;gt; &amp;lt;ref&amp;gt; http://ssd.sscc.ru/ru — Supercomputer Software Department &amp;lt;/ref&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt; p &amp;lt;/math&amp;gt; — количество задействованных процессоров.&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные алгоритма ===&lt;br /&gt;
&#039;&#039;&#039;Входные данные:&#039;&#039;&#039; любая числовая последовательность произвольной конечной длины. Так как параллельный алгоритм предполагает выбор разделяющего элемента случайным образом, построение последовательностей специального вида не приводит к увеличению вероятности неравномерного распределения данных между вычислительными узлами. Это значит, что эффективность алгоритма не зависит от вида входной последовательности. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные:&#039;&#039;&#039; последовательность чисел в отсортированном виде.&lt;br /&gt;
&lt;br /&gt;
=== Свойства алгоритма ===&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Особенности реализации последовательного алгоритма ===&lt;br /&gt;
&lt;br /&gt;
=== Локальность данных и вычислений ===&lt;br /&gt;
&lt;br /&gt;
=== Возможные способы и особенности параллельной реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
=== Масштабируемость алгоритма и его реализация ===&lt;br /&gt;
Проведём исследование масштабируемости параллельной реализации алгоритма быстрой сортировки согласно [[Scalability methodology|методике]]. Исследование проводится для числа процессоров [8 : 128] с шагом 8.&lt;br /&gt;
&lt;br /&gt;
[[file:User ashabokov 415 eff.png|thumb|center|700px|Рисунок 4. Изменение эффективности в зависимости от числа процессоров и входных данных.]]&lt;br /&gt;
&lt;br /&gt;
Далее построим оценку масштабируемости.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Динамические характеристики и эффективность реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
=== Выводы для классов архитектур ===&lt;br /&gt;
&lt;br /&gt;
=== Существующие реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Реализация алгоритма быстрой сортировки имеется во многих стандартных библиотеках. Например, для языков программирования C и C++ этот алгоритм можно найти в стандартных библиотеках stdlib.h и cstdlib соответственно. В языке программирования Python имеется встроенная функция sorted(). Также реализацию этого алгоритма можно найти в пакете LAPACK DLASRT.&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;br /&gt;
&amp;lt;references /&amp;gt;&lt;/div&gt;</summary>
		<author><name>Ashabokov 415</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Ashabokov_415/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%B1%D1%8B%D1%81%D1%82%D1%80%D0%BE%D0%B9_%D1%81%D0%BE%D1%80%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B8&amp;diff=27632</id>
		<title>Участник:Ashabokov 415/Алгоритм быстрой сортировки</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Ashabokov_415/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%B1%D1%8B%D1%81%D1%82%D1%80%D0%BE%D0%B9_%D1%81%D0%BE%D1%80%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B8&amp;diff=27632"/>
		<updated>2019-12-02T06:39:27Z</updated>

		<summary type="html">&lt;p&gt;Ashabokov 415: /* Программная реализация алгоритма */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&#039;&#039;&#039;Алгоритм быстрой сортировки&#039;&#039;&#039; &lt;br /&gt;
&lt;br /&gt;
== Свойства и структура алгоритмов ==&lt;br /&gt;
&lt;br /&gt;
=== Общее описание алгоритма &amp;lt;ref&amp;gt; https://en.wikipedia.org/wiki/Quicksort — From Wikipedia, the free encyclopedia &amp;lt;/ref&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
Быстрая сортировка, сортировка Хоара —  широко известный алгоритм сортировки, разработанный английским информатиком Чарльзом Хоаром во время его работы в МГУ в 1960 году.&lt;br /&gt;
&lt;br /&gt;
Один из самых быстрых известных универсальных алгоритмов сортировки массивов: в среднем  &amp;lt;math&amp;gt; O (n \log n) &amp;lt;/math&amp;gt; обменов при упорядочении &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; элементов; из-за наличия ряда недостатков на практике обычно используется с некоторыми доработками. Фактически данный алгоритм является улучшением алгоритма сортировки прямого обмена (см. ниже).&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
Алгоритм состоит из трех основных шагов:&lt;br /&gt;
&lt;br /&gt;
1. Выбрать опорный элемент (см. ниже). Пусть это будет элемент &amp;lt;math&amp;gt; a&#039; &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
2. Используя операции сравнения элементов массива с опорным и перестановки элементов массива, привести исходный массив к виду: &amp;lt;math&amp;gt; a_1 ... a_m a&#039; a_{m+2} ... a_n &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt; a_j &amp;lt; a&#039;, j = 1 ... m &amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt; a_i \geq a&#039;, i = (m+1) ... n  &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; — длина массива.&lt;br /&gt;
&lt;br /&gt;
3. Рекурсивно применить алгоритм к каждому из массивов: &amp;lt;math&amp;gt; a_1 ... a_m &amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt; a_{m+1} ... a_n &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Рассмотрим подробнее метод сравнения и перестановки данных в массиве, применяющийся на шаге 2. Для этого часто используют так называемое разбиение Хоара &amp;lt;ref&amp;gt; https://en.wikipedia.org/wiki/Quicksort — From Wikipedia, the free encyclopedia &amp;lt;/ref&amp;gt;. Суть данного метода заключается в следующем: выбираются два указателя, указывающие на первый и последний элементы массива соответственно, пость для наглядности это будут &amp;lt;math&amp;gt; i = 1 &amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt; j = n &amp;lt;/math&amp;gt;. Далее начинаем сдвигать левый указатель вправо, в правый — влево до тех пор, пока выполнены условия: &amp;lt;math&amp;gt; a_i &amp;lt; a&#039;, a_j \geq a&#039;, i &amp;lt; j &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt; a&#039; &amp;lt;/math&amp;gt; — опорный элемент. Как только найдутся такие &amp;lt;math&amp;gt; i, j &amp;lt;/math&amp;gt;, что &amp;lt;math&amp;gt; a_i \geq a&#039;, a_j &amp;lt; a&#039; &amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt; i &amp;lt; j &amp;lt;/math&amp;gt;, производим перестановку этих двух элементов. Продолжаем этот процесс до тех пор, пока выполнено &amp;lt;math&amp;gt; i &amp;lt; j &amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
Вычислительным ядром данного алгоритма являются операции сравнения и перестановки &amp;lt;math&amp;gt; i&amp;lt;/math&amp;gt;-ого и &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;-ого элементов массива на каждой итерации рекурсивного алгоритма.&lt;br /&gt;
&lt;br /&gt;
Сложность операции разделения массива на два подмассива (сравнение и перестановка элементов массива относительно опорного элемента) занимет время &amp;lt;math&amp;gt; O (log_2 n) &amp;lt;/math&amp;gt;. &amp;lt;ref&amp;gt; https://ru.wikipedia.org/wiki/Быстрая_сортировка &amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
Как и написано выше в разделе &amp;quot;Вычислительное ядро алгоритма&amp;quot;, основную часть данного метода сортировки составляет операция разделения массива относительно опорного элемента, которая в свою очередь состоит из операций сравнения и перестановки.&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма ===&lt;br /&gt;
1. Случайным образом выбрать опорный элемент массива.&lt;br /&gt;
&lt;br /&gt;
2. Сравнить все элементы сортируемого массива с опорным и разделить исходный массив на два подмассива: с элементами меньше опорного и с элементами большие (или равные) опорного. &lt;br /&gt;
&lt;br /&gt;
3. Рекурсивно повторить алгоритм для получившихся подмассивов.&lt;br /&gt;
&lt;br /&gt;
Случайный выбор опорного элемента считается наиболее эффективным, так как при фиксировании позиции опорного элемента (например, в качестве опорного всегда берется элемент, стоящий на первой позиции) может привести к существенному снижению эффективности для массивов определенного вида из-за неравномерного распределения элементов в получившихся подмассивах. Также в качестве опорного элемента можно выбирать медиану массива, но считается, что вычисление медианы на каждой итерации рекурсивного алгоритма — слишком затратная операция.&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
Последовательная сложность данного алгоритма зависит от глубины рекурсии, что в свою очередь зависит от того, насколько удачно были выбраны опорные элементы на каждом витке рекурсии. Рассмотрим несколько возможных случаев.&lt;br /&gt;
&lt;br /&gt;
1. В наилучшем случае выбор опорного элемента на каждом витке рекурсии происходит таким образом, что в результате разбиения исходного массива образуются подмассивы одинаковой длины (с точностью до одного элемента). В таком случае глубина рекурсии составит &amp;lt;math&amp;gt; log_2 n &amp;lt;/math&amp;gt;, следовательно, общая сложность алгоритма равна &amp;lt;math&amp;gt; O(n log_2 n) &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
2. В наихудшем случае каждое разбиение приводит к образованию подмассивов длины &amp;lt;math&amp;gt; 1 &amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt; n - 1&amp;lt;/math&amp;gt; соответственно. Общая сложность алгоритма в таком случае равна &amp;lt;math&amp;gt; O(n^2) &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
Так как для проведения вычислений задействовано &amp;lt;math&amp;gt; p = 2^N &amp;lt;/math&amp;gt; процессоров, можно воспользоваться следующим алгоритмом распределения данных между процессорами. Распределим произвольным образом данные между процессорами, далее выбираем некоторым образом ведущий элемент и рассылаем его всем процессорам системы. Т.к. топология системы имеет вид n-мерного куба, номер каждого процессора имеет двоичное представление длины &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, следовательно, можно ввести правило: на каждом процессоре происходит сравнение имеющегося блока данных с текущим ведущим элементом, после чего элементы меньше ведущего отправляются от процессора с номером &amp;lt;math&amp;gt;n_1&amp;lt;/math&amp;gt; процессору номер &amp;lt;math&amp;gt;n_2&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;n_1&amp;lt;/math&amp;gt; отличается от &amp;lt;math&amp;gt;n_2&amp;lt;/math&amp;gt; только в n-том разряде двоичного представления, в двоичном представлении числа &amp;lt;math&amp;gt;n_1&amp;lt;/math&amp;gt; на n-той позиции стоит 1, а &amp;lt;math&amp;gt;n_2&amp;lt;/math&amp;gt; — 0. Таким образом, после данной операции все данные будут разделены между процессорами, образующими n-1-мерные кубы таким образом, что элемент блока данных любого процессора из первого куба больше любого элемента блока данных процессора из второго куба. Повторив аналогичные действия для каждого из n-1-мерных кубов, получим 4 n-2-мерных куба и т.д. &lt;br /&gt;
&lt;br /&gt;
Для наглядности приведем пример: пусть &amp;lt;math&amp;gt; p = 2^3 = 8 &amp;lt;/math&amp;gt;. Ниже приведены графы, иллюстрирующие распределение данных на каждой итерации.&lt;br /&gt;
&lt;br /&gt;
[[file:Gr 1.png|thumb|center|700px|Рисунок 1. Итерация 1.]]&lt;br /&gt;
[[file:Gr 2.png|thumb|center|700px|Рисунок 2. Итерация 2.]]&lt;br /&gt;
[[file:Gr 3.png|thumb|center|700px|Рисунок 3. Итерация 3.]]&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма алгоритма ===&lt;br /&gt;
Основной идеей данного алгоритма является разбиение всего массива данных на блоки меньшего размера таким образом, что между соответствующими блоками после разбиения можно установить отношение упорядоченности. Сортировка производится следующим образом: выбирается некоторым образом ведущий элемент, после чего происходит разделение исходного массива данных на два блока относительно ведущего элемента: в первый блок помещаются элементы, меньшие ведущего, а во второй — большие ведущего. Таким образом, можно утверждать, что наибольший элемент первого блока меньше наименьшего элемента второго блока. Это означает, что повторив эту операцию для каждого из блоков отдельно некоторое количество раз и объединив результаты, получим массив с исходными данными в отсортированном виде. Из описания становится очевидно, что данный алгоритм можно легко обобщить для параллельной вычислительной системы с количеством процессоров &amp;lt;math&amp;gt;p = 2^n&amp;lt;/math&amp;gt;. Для этого алгоритм необходимо лишь дополнить методом выбора процессоров, между которыми будут происходить обмены данными на i-ом шаге. Подробное описание метода распределения данных между вычислительными узлами можно найти в разделе 1.7. Последним этапом работы алгоритма является объединение разрозненных блоков отсортированных данных в единый массив в правильном порядке. Порядок объединения не трудно восстановить исходя из двоичных представлений номеров процессоров.&lt;br /&gt;
&lt;br /&gt;
Очевидно, что наиболее медленной операцией в описанной выше схеме является операция обмена данными между процессорами, следовательно, хотелось бы получить некоторую оценку количества обменов. Такая оценка приведена ниже:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\sum_{i=1}^{n} i = n(n+1)/2 ≈ \log^2 p &amp;lt;/math&amp;gt; &amp;lt;ref&amp;gt; http://ssd.sscc.ru/ru — Supercomputer Software Department &amp;lt;/ref&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt; p &amp;lt;/math&amp;gt; — количество задействованных процессоров.&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные алгоритма ===&lt;br /&gt;
&#039;&#039;&#039;Входные данные:&#039;&#039;&#039; любая числовая последовательность произвольной конечной длины. Так как параллельный алгоритм предполагает выбор разделяющего элемента случайным образом, построение последовательностей специального вида не приводит к увеличению вероятности неравномерного распределения данных между вычислительными узлами. Это значит, что эффективность алгоритма не зависит от вида входной последовательности. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные:&#039;&#039;&#039; последовательность чисел в отсортированном виде.&lt;br /&gt;
&lt;br /&gt;
=== Свойства алгоритма ===&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Особенности реализации последовательного алгоритма ===&lt;br /&gt;
&lt;br /&gt;
=== Локальность данных и вычислений ===&lt;br /&gt;
&lt;br /&gt;
=== Возможные способы и особенности параллельной реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
=== Масштабируемость алгоритма и его реализация ===&lt;br /&gt;
Проведём исследование масштабируемости параллельной реализации алгоритма быстрой сортировки согласно [[Scalability methodology|методике]]. Исследование проводится для числа процессоров [8 : 128] с шагом 8.&lt;br /&gt;
&lt;br /&gt;
[[file:User ashabokov 415 eff.png|thumb|center|700px|Рисунок 4. Изменение эффективности в зависимости от числа процессоров и входных данных.]]&lt;br /&gt;
&lt;br /&gt;
Далее построим оценку масштабируемости.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Динамические характеристики и эффективность реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
=== Выводы для классов архитектур ===&lt;br /&gt;
&lt;br /&gt;
=== Существующие реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Реализация алгоритма быстрой сортировки имеется во многих стандартных библиотеках. Например, для языков программирования C и C++ этот алгоритм можно найти в стандартных библиотеках stdlib.h и cstdlib соответственно. В языке программирования Python имеется встроенная функция sorted(). Также реализацию этого алгоритма можно найти в пакете LAPACK DLASRT.&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;br /&gt;
&amp;lt;references /&amp;gt;&lt;/div&gt;</summary>
		<author><name>Ashabokov 415</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Ashabokov_415/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%B1%D1%8B%D1%81%D1%82%D1%80%D0%BE%D0%B9_%D1%81%D0%BE%D1%80%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B8&amp;diff=27631</id>
		<title>Участник:Ashabokov 415/Алгоритм быстрой сортировки</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Ashabokov_415/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%B1%D1%8B%D1%81%D1%82%D1%80%D0%BE%D0%B9_%D1%81%D0%BE%D1%80%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B8&amp;diff=27631"/>
		<updated>2019-12-02T06:36:33Z</updated>

		<summary type="html">&lt;p&gt;Ashabokov 415: /* Свойства и структура алгоритмов */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&#039;&#039;&#039;Алгоритм быстрой сортировки&#039;&#039;&#039; &lt;br /&gt;
&lt;br /&gt;
== Свойства и структура алгоритмов ==&lt;br /&gt;
&lt;br /&gt;
=== Общее описание алгоритма &amp;lt;ref&amp;gt; https://en.wikipedia.org/wiki/Quicksort — From Wikipedia, the free encyclopedia &amp;lt;/ref&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
Быстрая сортировка, сортировка Хоара —  широко известный алгоритм сортировки, разработанный английским информатиком Чарльзом Хоаром во время его работы в МГУ в 1960 году.&lt;br /&gt;
&lt;br /&gt;
Один из самых быстрых известных универсальных алгоритмов сортировки массивов: в среднем  &amp;lt;math&amp;gt; O (n \log n) &amp;lt;/math&amp;gt; обменов при упорядочении &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; элементов; из-за наличия ряда недостатков на практике обычно используется с некоторыми доработками. Фактически данный алгоритм является улучшением алгоритма сортировки прямого обмена (см. ниже).&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
Алгоритм состоит из трех основных шагов:&lt;br /&gt;
&lt;br /&gt;
1. Выбрать опорный элемент (см. ниже). Пусть это будет элемент &amp;lt;math&amp;gt; a&#039; &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
2. Используя операции сравнения элементов массива с опорным и перестановки элементов массива, привести исходный массив к виду: &amp;lt;math&amp;gt; a_1 ... a_m a&#039; a_{m+2} ... a_n &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt; a_j &amp;lt; a&#039;, j = 1 ... m &amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt; a_i \geq a&#039;, i = (m+1) ... n  &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; — длина массива.&lt;br /&gt;
&lt;br /&gt;
3. Рекурсивно применить алгоритм к каждому из массивов: &amp;lt;math&amp;gt; a_1 ... a_m &amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt; a_{m+1} ... a_n &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Рассмотрим подробнее метод сравнения и перестановки данных в массиве, применяющийся на шаге 2. Для этого часто используют так называемое разбиение Хоара &amp;lt;ref&amp;gt; https://en.wikipedia.org/wiki/Quicksort — From Wikipedia, the free encyclopedia &amp;lt;/ref&amp;gt;. Суть данного метода заключается в следующем: выбираются два указателя, указывающие на первый и последний элементы массива соответственно, пость для наглядности это будут &amp;lt;math&amp;gt; i = 1 &amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt; j = n &amp;lt;/math&amp;gt;. Далее начинаем сдвигать левый указатель вправо, в правый — влево до тех пор, пока выполнены условия: &amp;lt;math&amp;gt; a_i &amp;lt; a&#039;, a_j \geq a&#039;, i &amp;lt; j &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt; a&#039; &amp;lt;/math&amp;gt; — опорный элемент. Как только найдутся такие &amp;lt;math&amp;gt; i, j &amp;lt;/math&amp;gt;, что &amp;lt;math&amp;gt; a_i \geq a&#039;, a_j &amp;lt; a&#039; &amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt; i &amp;lt; j &amp;lt;/math&amp;gt;, производим перестановку этих двух элементов. Продолжаем этот процесс до тех пор, пока выполнено &amp;lt;math&amp;gt; i &amp;lt; j &amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
Вычислительным ядром данного алгоритма являются операции сравнения и перестановки &amp;lt;math&amp;gt; i&amp;lt;/math&amp;gt;-ого и &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;-ого элементов массива на каждой итерации рекурсивного алгоритма.&lt;br /&gt;
&lt;br /&gt;
Сложность операции разделения массива на два подмассива (сравнение и перестановка элементов массива относительно опорного элемента) занимет время &amp;lt;math&amp;gt; O (log_2 n) &amp;lt;/math&amp;gt;. &amp;lt;ref&amp;gt; https://ru.wikipedia.org/wiki/Быстрая_сортировка &amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
Как и написано выше в разделе &amp;quot;Вычислительное ядро алгоритма&amp;quot;, основную часть данного метода сортировки составляет операция разделения массива относительно опорного элемента, которая в свою очередь состоит из операций сравнения и перестановки.&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма ===&lt;br /&gt;
1. Случайным образом выбрать опорный элемент массива.&lt;br /&gt;
&lt;br /&gt;
2. Сравнить все элементы сортируемого массива с опорным и разделить исходный массив на два подмассива: с элементами меньше опорного и с элементами большие (или равные) опорного. &lt;br /&gt;
&lt;br /&gt;
3. Рекурсивно повторить алгоритм для получившихся подмассивов.&lt;br /&gt;
&lt;br /&gt;
Случайный выбор опорного элемента считается наиболее эффективным, так как при фиксировании позиции опорного элемента (например, в качестве опорного всегда берется элемент, стоящий на первой позиции) может привести к существенному снижению эффективности для массивов определенного вида из-за неравномерного распределения элементов в получившихся подмассивах. Также в качестве опорного элемента можно выбирать медиану массива, но считается, что вычисление медианы на каждой итерации рекурсивного алгоритма — слишком затратная операция.&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
Последовательная сложность данного алгоритма зависит от глубины рекурсии, что в свою очередь зависит от того, насколько удачно были выбраны опорные элементы на каждом витке рекурсии. Рассмотрим несколько возможных случаев.&lt;br /&gt;
&lt;br /&gt;
1. В наилучшем случае выбор опорного элемента на каждом витке рекурсии происходит таким образом, что в результате разбиения исходного массива образуются подмассивы одинаковой длины (с точностью до одного элемента). В таком случае глубина рекурсии составит &amp;lt;math&amp;gt; log_2 n &amp;lt;/math&amp;gt;, следовательно, общая сложность алгоритма равна &amp;lt;math&amp;gt; O(n log_2 n) &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
2. В наихудшем случае каждое разбиение приводит к образованию подмассивов длины &amp;lt;math&amp;gt; 1 &amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt; n - 1&amp;lt;/math&amp;gt; соответственно. Общая сложность алгоритма в таком случае равна &amp;lt;math&amp;gt; O(n^2) &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
Так как для проведения вычислений задействовано &amp;lt;math&amp;gt; p = 2^N &amp;lt;/math&amp;gt; процессоров, можно воспользоваться следующим алгоритмом распределения данных между процессорами. Распределим произвольным образом данные между процессорами, далее выбираем некоторым образом ведущий элемент и рассылаем его всем процессорам системы. Т.к. топология системы имеет вид n-мерного куба, номер каждого процессора имеет двоичное представление длины &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, следовательно, можно ввести правило: на каждом процессоре происходит сравнение имеющегося блока данных с текущим ведущим элементом, после чего элементы меньше ведущего отправляются от процессора с номером &amp;lt;math&amp;gt;n_1&amp;lt;/math&amp;gt; процессору номер &amp;lt;math&amp;gt;n_2&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;n_1&amp;lt;/math&amp;gt; отличается от &amp;lt;math&amp;gt;n_2&amp;lt;/math&amp;gt; только в n-том разряде двоичного представления, в двоичном представлении числа &amp;lt;math&amp;gt;n_1&amp;lt;/math&amp;gt; на n-той позиции стоит 1, а &amp;lt;math&amp;gt;n_2&amp;lt;/math&amp;gt; — 0. Таким образом, после данной операции все данные будут разделены между процессорами, образующими n-1-мерные кубы таким образом, что элемент блока данных любого процессора из первого куба больше любого элемента блока данных процессора из второго куба. Повторив аналогичные действия для каждого из n-1-мерных кубов, получим 4 n-2-мерных куба и т.д. &lt;br /&gt;
&lt;br /&gt;
Для наглядности приведем пример: пусть &amp;lt;math&amp;gt; p = 2^3 = 8 &amp;lt;/math&amp;gt;. Ниже приведены графы, иллюстрирующие распределение данных на каждой итерации.&lt;br /&gt;
&lt;br /&gt;
[[file:Gr 1.png|thumb|center|700px|Рисунок 1. Итерация 1.]]&lt;br /&gt;
[[file:Gr 2.png|thumb|center|700px|Рисунок 2. Итерация 2.]]&lt;br /&gt;
[[file:Gr 3.png|thumb|center|700px|Рисунок 3. Итерация 3.]]&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма алгоритма ===&lt;br /&gt;
Основной идеей данного алгоритма является разбиение всего массива данных на блоки меньшего размера таким образом, что между соответствующими блоками после разбиения можно установить отношение упорядоченности. Сортировка производится следующим образом: выбирается некоторым образом ведущий элемент, после чего происходит разделение исходного массива данных на два блока относительно ведущего элемента: в первый блок помещаются элементы, меньшие ведущего, а во второй — большие ведущего. Таким образом, можно утверждать, что наибольший элемент первого блока меньше наименьшего элемента второго блока. Это означает, что повторив эту операцию для каждого из блоков отдельно некоторое количество раз и объединив результаты, получим массив с исходными данными в отсортированном виде. Из описания становится очевидно, что данный алгоритм можно легко обобщить для параллельной вычислительной системы с количеством процессоров &amp;lt;math&amp;gt;p = 2^n&amp;lt;/math&amp;gt;. Для этого алгоритм необходимо лишь дополнить методом выбора процессоров, между которыми будут происходить обмены данными на i-ом шаге. Подробное описание метода распределения данных между вычислительными узлами можно найти в разделе 1.7. Последним этапом работы алгоритма является объединение разрозненных блоков отсортированных данных в единый массив в правильном порядке. Порядок объединения не трудно восстановить исходя из двоичных представлений номеров процессоров.&lt;br /&gt;
&lt;br /&gt;
Очевидно, что наиболее медленной операцией в описанной выше схеме является операция обмена данными между процессорами, следовательно, хотелось бы получить некоторую оценку количества обменов. Такая оценка приведена ниже:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\sum_{i=1}^{n} i = n(n+1)/2 ≈ \log^2 p &amp;lt;/math&amp;gt; &amp;lt;ref&amp;gt; http://ssd.sscc.ru/ru — Supercomputer Software Department &amp;lt;/ref&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt; p &amp;lt;/math&amp;gt; — количество задействованных процессоров.&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные алгоритма ===&lt;br /&gt;
&#039;&#039;&#039;Входные данные:&#039;&#039;&#039; любая числовая последовательность произвольной конечной длины. Так как параллельный алгоритм предполагает выбор разделяющего элемента случайным образом, построение последовательностей специального вида не приводит к увеличению вероятности неравномерного распределения данных между вычислительными узлами. Это значит, что эффективность алгоритма не зависит от вида входной последовательности. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные:&#039;&#039;&#039; последовательность чисел в отсортированном виде.&lt;br /&gt;
&lt;br /&gt;
=== Свойства алгоритма ===&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Масштабируемость алгоритма и его реализация ===&lt;br /&gt;
Проведём исследование масштабируемости параллельной реализации алгоритма быстрой сортировки согласно [[Scalability methodology|методике]]. Исследование проводится для числа процессоров [8 : 128] с шагом 8.&lt;br /&gt;
&lt;br /&gt;
[[file:User ashabokov 415 eff.png|thumb|center|700px|Рисунок 4. Изменение эффективности в зависимости от числа процессоров и входных данных.]]&lt;br /&gt;
&lt;br /&gt;
Далее построим оценку масштабируемости.&lt;br /&gt;
&lt;br /&gt;
=== Существующие реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Реализация алгоритма быстрой сортировки имеется во многих стандартных библиотеках. Например, для языков программирования C и C++ этот алгоритм можно найти в стандартных библиотеках stdlib.h и cstdlib соответственно. В языке программирования Python имеется встроенная функция sorted(). Также реализацию этого алгоритма можно найти в пакете LAPACK DLASRT.&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;br /&gt;
&amp;lt;references /&amp;gt;&lt;/div&gt;</summary>
		<author><name>Ashabokov 415</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Ashabokov_415/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%B1%D1%8B%D1%81%D1%82%D1%80%D0%BE%D0%B9_%D1%81%D0%BE%D1%80%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B8&amp;diff=27630</id>
		<title>Участник:Ashabokov 415/Алгоритм быстрой сортировки</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Ashabokov_415/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%B1%D1%8B%D1%81%D1%82%D1%80%D0%BE%D0%B9_%D1%81%D0%BE%D1%80%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B8&amp;diff=27630"/>
		<updated>2019-12-02T06:35:25Z</updated>

		<summary type="html">&lt;p&gt;Ashabokov 415: /* Существующие реализации алгоритма */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&#039;&#039;&#039;Алгоритм быстрой сортировки&#039;&#039;&#039; &lt;br /&gt;
&lt;br /&gt;
== Свойства и структура алгоритмов ==&lt;br /&gt;
&lt;br /&gt;
=== Общее описание алгоритма &amp;lt;ref&amp;gt; https://en.wikipedia.org/wiki/Quicksort — From Wikipedia, the free encyclopedia &amp;lt;/ref&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
Быстрая сортировка, сортировка Хоара —  широко известный алгоритм сортировки, разработанный английским информатиком Чарльзом Хоаром во время его работы в МГУ в 1960 году.&lt;br /&gt;
&lt;br /&gt;
Один из самых быстрых известных универсальных алгоритмов сортировки массивов: в среднем  &amp;lt;math&amp;gt; O (n \log n) &amp;lt;/math&amp;gt; обменов при упорядочении &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; элементов; из-за наличия ряда недостатков на практике обычно используется с некоторыми доработками. Фактически данный алгоритм является улучшением алгоритма сортировки прямого обмена (см. ниже).&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
Алгоритм состоит из трех основных шагов:&lt;br /&gt;
&lt;br /&gt;
1. Выбрать опорный элемент (см. ниже). Пусть это будет элемент &amp;lt;math&amp;gt; a&#039; &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
2. Используя операции сравнения элементов массива с опорным и перестановки элементов массива, привести исходный массив к виду: &amp;lt;math&amp;gt; a_1 ... a_m a&#039; a_{m+2} ... a_n &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt; a_j &amp;lt; a&#039;, j = 1 ... m &amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt; a_i \geq a&#039;, i = (m+1) ... n  &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; — длина массива.&lt;br /&gt;
&lt;br /&gt;
3. Рекурсивно применить алгоритм к каждому из массивов: &amp;lt;math&amp;gt; a_1 ... a_m &amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt; a_{m+1} ... a_n &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Рассмотрим подробнее метод сравнения и перестановки данных в массиве, применяющийся на шаге 2. Для этого часто используют так называемое разбиение Хоара &amp;lt;ref&amp;gt; https://en.wikipedia.org/wiki/Quicksort — From Wikipedia, the free encyclopedia &amp;lt;/ref&amp;gt;. Суть данного метода заключается в следующем: выбираются два указателя, указывающие на первый и последний элементы массива соответственно, пость для наглядности это будут &amp;lt;math&amp;gt; i = 1 &amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt; j = n &amp;lt;/math&amp;gt;. Далее начинаем сдвигать левый указатель вправо, в правый — влево до тех пор, пока выполнены условия: &amp;lt;math&amp;gt; a_i &amp;lt; a&#039;, a_j \geq a&#039;, i &amp;lt; j &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt; a&#039; &amp;lt;/math&amp;gt; — опорный элемент. Как только найдутся такие &amp;lt;math&amp;gt; i, j &amp;lt;/math&amp;gt;, что &amp;lt;math&amp;gt; a_i \geq a&#039;, a_j &amp;lt; a&#039; &amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt; i &amp;lt; j &amp;lt;/math&amp;gt;, производим перестановку этих двух элементов. Продолжаем этот процесс до тех пор, пока выполнено &amp;lt;math&amp;gt; i &amp;lt; j &amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
Вычислительным ядром данного алгоритма являются операции сравнения и перестановки &amp;lt;math&amp;gt; i&amp;lt;/math&amp;gt;-ого и &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;-ого элементов массива на каждой итерации рекурсивного алгоритма.&lt;br /&gt;
&lt;br /&gt;
Сложность операции разделения массива на два подмассива (сравнение и перестановка элементов массива относительно опорного элемента) занимет время &amp;lt;math&amp;gt; O (log_2 n) &amp;lt;/math&amp;gt;. &amp;lt;ref&amp;gt; https://ru.wikipedia.org/wiki/Быстрая_сортировка &amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
Как и написано выше в разделе &amp;quot;Вычислительное ядро алгоритма&amp;quot;, основную часть данного метода сортировки составляет операция разделения массива относительно опорного элемента, которая в свою очередь состоит из операций сравнения и перестановки.&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма ===&lt;br /&gt;
1. Случайным образом выбрать опорный элемент массива.&lt;br /&gt;
&lt;br /&gt;
2. Сравнить все элементы сортируемого массива с опорным и разделить исходный массив на два подмассива: с элементами меньше опорного и с элементами большие (или равные) опорного. &lt;br /&gt;
&lt;br /&gt;
3. Рекурсивно повторить алгоритм для получившихся подмассивов.&lt;br /&gt;
&lt;br /&gt;
Случайный выбор опорного элемента считается наиболее эффективным, так как при фиксировании позиции опорного элемента (например, в качестве опорного всегда берется элемент, стоящий на первой позиции) может привести к существенному снижению эффективности для массивов определенного вида из-за неравномерного распределения элементов в получившихся подмассивах. Также в качестве опорного элемента можно выбирать медиану массива, но считается, что вычисление медианы на каждой итерации рекурсивного алгоритма — слишком затратная операция.&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
Последовательная сложность данного алгоритма зависит от глубины рекурсии, что в свою очередь зависит от того, насколько удачно были выбраны опорные элементы на каждом витке рекурсии. Рассмотрим несколько возможных случаев.&lt;br /&gt;
&lt;br /&gt;
1. В наилучшем случае выбор опорного элемента на каждом витке рекурсии происходит таким образом, что в результате разбиения исходного массива образуются подмассивы одинаковой длины (с точностью до одного элемента). В таком случае глубина рекурсии составит &amp;lt;math&amp;gt; log_2 n &amp;lt;/math&amp;gt;, следовательно, общая сложность алгоритма равна &amp;lt;math&amp;gt; O(n log_2 n) &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
2. В наихудшем случае каждое разбиение приводит к образованию подмассивов длины &amp;lt;math&amp;gt; 1 &amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt; n - 1&amp;lt;/math&amp;gt; соответственно. Общая сложность алгоритма в таком случае равна &amp;lt;math&amp;gt; O(n^2) &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
Так как для проведения вычислений задействовано &amp;lt;math&amp;gt; p = 2^N &amp;lt;/math&amp;gt; процессоров, можно воспользоваться следующим алгоритмом распределения данных между процессорами. Распределим произвольным образом данные между процессорами, далее выбираем некоторым образом ведущий элемент и рассылаем его всем процессорам системы. Т.к. топология системы имеет вид n-мерного куба, номер каждого процессора имеет двоичное представление длины &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, следовательно, можно ввести правило: на каждом процессоре происходит сравнение имеющегося блока данных с текущим ведущим элементом, после чего элементы меньше ведущего отправляются от процессора с номером &amp;lt;math&amp;gt;n_1&amp;lt;/math&amp;gt; процессору номер &amp;lt;math&amp;gt;n_2&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;n_1&amp;lt;/math&amp;gt; отличается от &amp;lt;math&amp;gt;n_2&amp;lt;/math&amp;gt; только в n-том разряде двоичного представления, в двоичном представлении числа &amp;lt;math&amp;gt;n_1&amp;lt;/math&amp;gt; на n-той позиции стоит 1, а &amp;lt;math&amp;gt;n_2&amp;lt;/math&amp;gt; — 0. Таким образом, после данной операции все данные будут разделены между процессорами, образующими n-1-мерные кубы таким образом, что элемент блока данных любого процессора из первого куба больше любого элемента блока данных процессора из второго куба. Повторив аналогичные действия для каждого из n-1-мерных кубов, получим 4 n-2-мерных куба и т.д. &lt;br /&gt;
&lt;br /&gt;
Для наглядности приведем пример: пусть &amp;lt;math&amp;gt; p = 2^3 = 8 &amp;lt;/math&amp;gt;. Ниже приведены графы, иллюстрирующие распределение данных на каждой итерации.&lt;br /&gt;
&lt;br /&gt;
[[file:Gr 1.png|thumb|center|700px|Рисунок 1. Итерация 1.]]&lt;br /&gt;
[[file:Gr 2.png|thumb|center|700px|Рисунок 2. Итерация 2.]]&lt;br /&gt;
[[file:Gr 3.png|thumb|center|700px|Рисунок 3. Итерация 3.]]&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма алгоритма ===&lt;br /&gt;
Основной идеей данного алгоритма является разбиение всего массива данных на блоки меньшего размера таким образом, что между соответствующими блоками после разбиения можно установить отношение упорядоченности. Сортировка производится следующим образом: выбирается некоторым образом ведущий элемент, после чего происходит разделение исходного массива данных на два блока относительно ведущего элемента: в первый блок помещаются элементы, меньшие ведущего, а во второй — большие ведущего. Таким образом, можно утверждать, что наибольший элемент первого блока меньше наименьшего элемента второго блока. Это означает, что повторив эту операцию для каждого из блоков отдельно некоторое количество раз и объединив результаты, получим массив с исходными данными в отсортированном виде. Из описания становится очевидно, что данный алгоритм можно легко обобщить для параллельной вычислительной системы с количеством процессоров &amp;lt;math&amp;gt;p = 2^n&amp;lt;/math&amp;gt;. Для этого алгоритм необходимо лишь дополнить методом выбора процессоров, между которыми будут происходить обмены данными на i-ом шаге. Подробное описание метода распределения данных между вычислительными узлами можно найти в разделе 1.7. Последним этапом работы алгоритма является объединение разрозненных блоков отсортированных данных в единый массив в правильном порядке. Порядок объединения не трудно восстановить исходя из двоичных представлений номеров процессоров.&lt;br /&gt;
&lt;br /&gt;
Очевидно, что наиболее медленной операцией в описанной выше схеме является операция обмена данными между процессорами, следовательно, хотелось бы получить некоторую оценку количества обменов. Такая оценка приведена ниже:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\sum_{i=1}^{n} i = n(n+1)/2 ≈ \log^2 p &amp;lt;/math&amp;gt; &amp;lt;ref&amp;gt; http://ssd.sscc.ru/ru — Supercomputer Software Department &amp;lt;/ref&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt; p &amp;lt;/math&amp;gt; — количество задействованных процессоров.&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные алгоритма ===&lt;br /&gt;
&#039;&#039;&#039;Входные данные:&#039;&#039;&#039; любая числовая последовательность произвольной конечной длины. Так как параллельный алгоритм предполагает выбор разделяющего элемента случайным образом, построение последовательностей специального вида не приводит к увеличению вероятности неравномерного распределения данных между вычислительными узлами. Это значит, что эффективность алгоритма не зависит от вида входной последовательности. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные:&#039;&#039;&#039; последовательность чисел в отсортированном виде.&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Масштабируемость алгоритма и его реализация ===&lt;br /&gt;
Проведём исследование масштабируемости параллельной реализации алгоритма быстрой сортировки согласно [[Scalability methodology|методике]]. Исследование проводится для числа процессоров [8 : 128] с шагом 8.&lt;br /&gt;
&lt;br /&gt;
[[file:User ashabokov 415 eff.png|thumb|center|700px|Рисунок 4. Изменение эффективности в зависимости от числа процессоров и входных данных.]]&lt;br /&gt;
&lt;br /&gt;
Далее построим оценку масштабируемости.&lt;br /&gt;
&lt;br /&gt;
=== Существующие реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Реализация алгоритма быстрой сортировки имеется во многих стандартных библиотеках. Например, для языков программирования C и C++ этот алгоритм можно найти в стандартных библиотеках stdlib.h и cstdlib соответственно. В языке программирования Python имеется встроенная функция sorted(). Также реализацию этого алгоритма можно найти в пакете LAPACK DLASRT.&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;br /&gt;
&amp;lt;references /&amp;gt;&lt;/div&gt;</summary>
		<author><name>Ashabokov 415</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Ashabokov_415/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%B1%D1%8B%D1%81%D1%82%D1%80%D0%BE%D0%B9_%D1%81%D0%BE%D1%80%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B8&amp;diff=27629</id>
		<title>Участник:Ashabokov 415/Алгоритм быстрой сортировки</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Ashabokov_415/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%B1%D1%8B%D1%81%D1%82%D1%80%D0%BE%D0%B9_%D1%81%D0%BE%D1%80%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B8&amp;diff=27629"/>
		<updated>2019-12-02T03:03:05Z</updated>

		<summary type="html">&lt;p&gt;Ashabokov 415: /* Масштабируемость алгоритма и его реализация */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&#039;&#039;&#039;Алгоритм быстрой сортировки&#039;&#039;&#039; &lt;br /&gt;
&lt;br /&gt;
== Свойства и структура алгоритмов ==&lt;br /&gt;
&lt;br /&gt;
=== Общее описание алгоритма &amp;lt;ref&amp;gt; https://en.wikipedia.org/wiki/Quicksort — From Wikipedia, the free encyclopedia &amp;lt;/ref&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
Быстрая сортировка, сортировка Хоара —  широко известный алгоритм сортировки, разработанный английским информатиком Чарльзом Хоаром во время его работы в МГУ в 1960 году.&lt;br /&gt;
&lt;br /&gt;
Один из самых быстрых известных универсальных алгоритмов сортировки массивов: в среднем  &amp;lt;math&amp;gt; O (n \log n) &amp;lt;/math&amp;gt; обменов при упорядочении &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; элементов; из-за наличия ряда недостатков на практике обычно используется с некоторыми доработками. Фактически данный алгоритм является улучшением алгоритма сортировки прямого обмена (см. ниже).&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
Алгоритм состоит из трех основных шагов:&lt;br /&gt;
&lt;br /&gt;
1. Выбрать опорный элемент (см. ниже). Пусть это будет элемент &amp;lt;math&amp;gt; a&#039; &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
2. Используя операции сравнения элементов массива с опорным и перестановки элементов массива, привести исходный массив к виду: &amp;lt;math&amp;gt; a_1 ... a_m a&#039; a_{m+2} ... a_n &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt; a_j &amp;lt; a&#039;, j = 1 ... m &amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt; a_i \geq a&#039;, i = (m+1) ... n  &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; — длина массива.&lt;br /&gt;
&lt;br /&gt;
3. Рекурсивно применить алгоритм к каждому из массивов: &amp;lt;math&amp;gt; a_1 ... a_m &amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt; a_{m+1} ... a_n &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Рассмотрим подробнее метод сравнения и перестановки данных в массиве, применяющийся на шаге 2. Для этого часто используют так называемое разбиение Хоара &amp;lt;ref&amp;gt; https://en.wikipedia.org/wiki/Quicksort — From Wikipedia, the free encyclopedia &amp;lt;/ref&amp;gt;. Суть данного метода заключается в следующем: выбираются два указателя, указывающие на первый и последний элементы массива соответственно, пость для наглядности это будут &amp;lt;math&amp;gt; i = 1 &amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt; j = n &amp;lt;/math&amp;gt;. Далее начинаем сдвигать левый указатель вправо, в правый — влево до тех пор, пока выполнены условия: &amp;lt;math&amp;gt; a_i &amp;lt; a&#039;, a_j \geq a&#039;, i &amp;lt; j &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt; a&#039; &amp;lt;/math&amp;gt; — опорный элемент. Как только найдутся такие &amp;lt;math&amp;gt; i, j &amp;lt;/math&amp;gt;, что &amp;lt;math&amp;gt; a_i \geq a&#039;, a_j &amp;lt; a&#039; &amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt; i &amp;lt; j &amp;lt;/math&amp;gt;, производим перестановку этих двух элементов. Продолжаем этот процесс до тех пор, пока выполнено &amp;lt;math&amp;gt; i &amp;lt; j &amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
Вычислительным ядром данного алгоритма являются операции сравнения и перестановки &amp;lt;math&amp;gt; i&amp;lt;/math&amp;gt;-ого и &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;-ого элементов массива на каждой итерации рекурсивного алгоритма.&lt;br /&gt;
&lt;br /&gt;
Сложность операции разделения массива на два подмассива (сравнение и перестановка элементов массива относительно опорного элемента) занимет время &amp;lt;math&amp;gt; O (log_2 n) &amp;lt;/math&amp;gt;. &amp;lt;ref&amp;gt; https://ru.wikipedia.org/wiki/Быстрая_сортировка &amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
Как и написано выше в разделе &amp;quot;Вычислительное ядро алгоритма&amp;quot;, основную часть данного метода сортировки составляет операция разделения массива относительно опорного элемента, которая в свою очередь состоит из операций сравнения и перестановки.&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма ===&lt;br /&gt;
1. Случайным образом выбрать опорный элемент массива.&lt;br /&gt;
&lt;br /&gt;
2. Сравнить все элементы сортируемого массива с опорным и разделить исходный массив на два подмассива: с элементами меньше опорного и с элементами большие (или равные) опорного. &lt;br /&gt;
&lt;br /&gt;
3. Рекурсивно повторить алгоритм для получившихся подмассивов.&lt;br /&gt;
&lt;br /&gt;
Случайный выбор опорного элемента считается наиболее эффективным, так как при фиксировании позиции опорного элемента (например, в качестве опорного всегда берется элемент, стоящий на первой позиции) может привести к существенному снижению эффективности для массивов определенного вида из-за неравномерного распределения элементов в получившихся подмассивах. Также в качестве опорного элемента можно выбирать медиану массива, но считается, что вычисление медианы на каждой итерации рекурсивного алгоритма — слишком затратная операция.&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
Последовательная сложность данного алгоритма зависит от глубины рекурсии, что в свою очередь зависит от того, насколько удачно были выбраны опорные элементы на каждом витке рекурсии. Рассмотрим несколько возможных случаев.&lt;br /&gt;
&lt;br /&gt;
1. В наилучшем случае выбор опорного элемента на каждом витке рекурсии происходит таким образом, что в результате разбиения исходного массива образуются подмассивы одинаковой длины (с точностью до одного элемента). В таком случае глубина рекурсии составит &amp;lt;math&amp;gt; log_2 n &amp;lt;/math&amp;gt;, следовательно, общая сложность алгоритма равна &amp;lt;math&amp;gt; O(n log_2 n) &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
2. В наихудшем случае каждое разбиение приводит к образованию подмассивов длины &amp;lt;math&amp;gt; 1 &amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt; n - 1&amp;lt;/math&amp;gt; соответственно. Общая сложность алгоритма в таком случае равна &amp;lt;math&amp;gt; O(n^2) &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
Так как для проведения вычислений задействовано &amp;lt;math&amp;gt; p = 2^N &amp;lt;/math&amp;gt; процессоров, можно воспользоваться следующим алгоритмом распределения данных между процессорами. Распределим произвольным образом данные между процессорами, далее выбираем некоторым образом ведущий элемент и рассылаем его всем процессорам системы. Т.к. топология системы имеет вид n-мерного куба, номер каждого процессора имеет двоичное представление длины &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, следовательно, можно ввести правило: на каждом процессоре происходит сравнение имеющегося блока данных с текущим ведущим элементом, после чего элементы меньше ведущего отправляются от процессора с номером &amp;lt;math&amp;gt;n_1&amp;lt;/math&amp;gt; процессору номер &amp;lt;math&amp;gt;n_2&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;n_1&amp;lt;/math&amp;gt; отличается от &amp;lt;math&amp;gt;n_2&amp;lt;/math&amp;gt; только в n-том разряде двоичного представления, в двоичном представлении числа &amp;lt;math&amp;gt;n_1&amp;lt;/math&amp;gt; на n-той позиции стоит 1, а &amp;lt;math&amp;gt;n_2&amp;lt;/math&amp;gt; — 0. Таким образом, после данной операции все данные будут разделены между процессорами, образующими n-1-мерные кубы таким образом, что элемент блока данных любого процессора из первого куба больше любого элемента блока данных процессора из второго куба. Повторив аналогичные действия для каждого из n-1-мерных кубов, получим 4 n-2-мерных куба и т.д. &lt;br /&gt;
&lt;br /&gt;
Для наглядности приведем пример: пусть &amp;lt;math&amp;gt; p = 2^3 = 8 &amp;lt;/math&amp;gt;. Ниже приведены графы, иллюстрирующие распределение данных на каждой итерации.&lt;br /&gt;
&lt;br /&gt;
[[file:Gr 1.png|thumb|center|700px|Рисунок 1. Итерация 1.]]&lt;br /&gt;
[[file:Gr 2.png|thumb|center|700px|Рисунок 2. Итерация 2.]]&lt;br /&gt;
[[file:Gr 3.png|thumb|center|700px|Рисунок 3. Итерация 3.]]&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма алгоритма ===&lt;br /&gt;
Основной идеей данного алгоритма является разбиение всего массива данных на блоки меньшего размера таким образом, что между соответствующими блоками после разбиения можно установить отношение упорядоченности. Сортировка производится следующим образом: выбирается некоторым образом ведущий элемент, после чего происходит разделение исходного массива данных на два блока относительно ведущего элемента: в первый блок помещаются элементы, меньшие ведущего, а во второй — большие ведущего. Таким образом, можно утверждать, что наибольший элемент первого блока меньше наименьшего элемента второго блока. Это означает, что повторив эту операцию для каждого из блоков отдельно некоторое количество раз и объединив результаты, получим массив с исходными данными в отсортированном виде. Из описания становится очевидно, что данный алгоритм можно легко обобщить для параллельной вычислительной системы с количеством процессоров &amp;lt;math&amp;gt;p = 2^n&amp;lt;/math&amp;gt;. Для этого алгоритм необходимо лишь дополнить методом выбора процессоров, между которыми будут происходить обмены данными на i-ом шаге. Подробное описание метода распределения данных между вычислительными узлами можно найти в разделе 1.7. Последним этапом работы алгоритма является объединение разрозненных блоков отсортированных данных в единый массив в правильном порядке. Порядок объединения не трудно восстановить исходя из двоичных представлений номеров процессоров.&lt;br /&gt;
&lt;br /&gt;
Очевидно, что наиболее медленной операцией в описанной выше схеме является операция обмена данными между процессорами, следовательно, хотелось бы получить некоторую оценку количества обменов. Такая оценка приведена ниже:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\sum_{i=1}^{n} i = n(n+1)/2 ≈ \log^2 p &amp;lt;/math&amp;gt; &amp;lt;ref&amp;gt; http://ssd.sscc.ru/ru — Supercomputer Software Department &amp;lt;/ref&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt; p &amp;lt;/math&amp;gt; — количество задействованных процессоров.&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные алгоритма ===&lt;br /&gt;
&#039;&#039;&#039;Входные данные:&#039;&#039;&#039; любая числовая последовательность произвольной конечной длины. Так как параллельный алгоритм предполагает выбор разделяющего элемента случайным образом, построение последовательностей специального вида не приводит к увеличению вероятности неравномерного распределения данных между вычислительными узлами. Это значит, что эффективность алгоритма не зависит от вида входной последовательности. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные:&#039;&#039;&#039; последовательность чисел в отсортированном виде.&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Масштабируемость алгоритма и его реализация ===&lt;br /&gt;
Проведём исследование масштабируемости параллельной реализации алгоритма быстрой сортировки согласно [[Scalability methodology|методике]]. Исследование проводится для числа процессоров [8 : 128] с шагом 8.&lt;br /&gt;
&lt;br /&gt;
[[file:User ashabokov 415 eff.png|thumb|center|700px|Рисунок 4. Изменение эффективности в зависимости от числа процессоров и входных данных.]]&lt;br /&gt;
&lt;br /&gt;
Далее построим оценку масштабируемости.&lt;br /&gt;
&lt;br /&gt;
=== Существующие реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;br /&gt;
&amp;lt;references /&amp;gt;&lt;/div&gt;</summary>
		<author><name>Ashabokov 415</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Ashabokov_415/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%B1%D1%8B%D1%81%D1%82%D1%80%D0%BE%D0%B9_%D1%81%D0%BE%D1%80%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B8&amp;diff=27625</id>
		<title>Участник:Ashabokov 415/Алгоритм быстрой сортировки</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Ashabokov_415/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%B1%D1%8B%D1%81%D1%82%D1%80%D0%BE%D0%B9_%D1%81%D0%BE%D1%80%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B8&amp;diff=27625"/>
		<updated>2019-11-30T22:45:09Z</updated>

		<summary type="html">&lt;p&gt;Ashabokov 415: /* Свойства и структура алгоритмов */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&#039;&#039;&#039;Алгоритм быстрой сортировки&#039;&#039;&#039; &lt;br /&gt;
&lt;br /&gt;
== Свойства и структура алгоритмов ==&lt;br /&gt;
&lt;br /&gt;
=== Общее описание алгоритма &amp;lt;ref&amp;gt; https://en.wikipedia.org/wiki/Quicksort — From Wikipedia, the free encyclopedia &amp;lt;/ref&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
Быстрая сортировка, сортировка Хоара —  широко известный алгоритм сортировки, разработанный английским информатиком Чарльзом Хоаром во время его работы в МГУ в 1960 году.&lt;br /&gt;
&lt;br /&gt;
Один из самых быстрых известных универсальных алгоритмов сортировки массивов: в среднем  &amp;lt;math&amp;gt; O (n \log n) &amp;lt;/math&amp;gt; обменов при упорядочении &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; элементов; из-за наличия ряда недостатков на практике обычно используется с некоторыми доработками. Фактически данный алгоритм является улучшением алгоритма сортировки прямого обмена (см. ниже).&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
Алгоритм состоит из трех основных шагов:&lt;br /&gt;
&lt;br /&gt;
1. Выбрать опорный элемент (см. ниже). Пусть это будет элемент &amp;lt;math&amp;gt; a&#039; &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
2. Используя операции сравнения элементов массива с опорным и перестановки элементов массива, привести исходный массив к виду: &amp;lt;math&amp;gt; a_1 ... a_m a&#039; a_{m+2} ... a_n &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt; a_j &amp;lt; a&#039;, j = 1 ... m &amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt; a_i \geq a&#039;, i = (m+1) ... n  &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; — длина массива.&lt;br /&gt;
&lt;br /&gt;
3. Рекурсивно применить алгоритм к каждому из массивов: &amp;lt;math&amp;gt; a_1 ... a_m &amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt; a_{m+1} ... a_n &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Рассмотрим подробнее метод сравнения и перестановки данных в массиве, применяющийся на шаге 2. Для этого часто используют так называемое разбиение Хоара &amp;lt;ref&amp;gt; https://en.wikipedia.org/wiki/Quicksort — From Wikipedia, the free encyclopedia &amp;lt;/ref&amp;gt;. Суть данного метода заключается в следующем: выбираются два указателя, указывающие на первый и последний элементы массива соответственно, пость для наглядности это будут &amp;lt;math&amp;gt; i = 1 &amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt; j = n &amp;lt;/math&amp;gt;. Далее начинаем сдвигать левый указатель вправо, в правый — влево до тех пор, пока выполнены условия: &amp;lt;math&amp;gt; a_i &amp;lt; a&#039;, a_j \geq a&#039;, i &amp;lt; j &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt; a&#039; &amp;lt;/math&amp;gt; — опорный элемент. Как только найдутся такие &amp;lt;math&amp;gt; i, j &amp;lt;/math&amp;gt;, что &amp;lt;math&amp;gt; a_i \geq a&#039;, a_j &amp;lt; a&#039; &amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt; i &amp;lt; j &amp;lt;/math&amp;gt;, производим перестановку этих двух элементов. Продолжаем этот процесс до тех пор, пока выполнено &amp;lt;math&amp;gt; i &amp;lt; j &amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
Вычислительным ядром данного алгоритма являются операции сравнения и перестановки &amp;lt;math&amp;gt; i&amp;lt;/math&amp;gt;-ого и &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;-ого элементов массива на каждой итерации рекурсивного алгоритма.&lt;br /&gt;
&lt;br /&gt;
Сложность операции разделения массива на два подмассива (сравнение и перестановка элементов массива относительно опорного элемента) занимет время &amp;lt;math&amp;gt; O (log_2 n) &amp;lt;/math&amp;gt;. &amp;lt;ref&amp;gt; https://ru.wikipedia.org/wiki/Быстрая_сортировка &amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
Как и написано выше в разделе &amp;quot;Вычислительное ядро алгоритма&amp;quot;, основную часть данного метода сортировки составляет операция разделения массива относительно опорного элемента, которая в свою очередь состоит из операций сравнения и перестановки.&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма ===&lt;br /&gt;
1. Случайным образом выбрать опорный элемент массива.&lt;br /&gt;
&lt;br /&gt;
2. Сравнить все элементы сортируемого массива с опорным и разделить исходный массив на два подмассива: с элементами меньше опорного и с элементами большие (или равные) опорного. &lt;br /&gt;
&lt;br /&gt;
3. Рекурсивно повторить алгоритм для получившихся подмассивов.&lt;br /&gt;
&lt;br /&gt;
Случайный выбор опорного элемента считается наиболее эффективным, так как при фиксировании позиции опорного элемента (например, в качестве опорного всегда берется элемент, стоящий на первой позиции) может привести к существенному снижению эффективности для массивов определенного вида из-за неравномерного распределения элементов в получившихся подмассивах. Также в качестве опорного элемента можно выбирать медиану массива, но считается, что вычисление медианы на каждой итерации рекурсивного алгоритма — слишком затратная операция.&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
Последовательная сложность данного алгоритма зависит от глубины рекурсии, что в свою очередь зависит от того, насколько удачно были выбраны опорные элементы на каждом витке рекурсии. Рассмотрим несколько возможных случаев.&lt;br /&gt;
&lt;br /&gt;
1. В наилучшем случае выбор опорного элемента на каждом витке рекурсии происходит таким образом, что в результате разбиения исходного массива образуются подмассивы одинаковой длины (с точностью до одного элемента). В таком случае глубина рекурсии составит &amp;lt;math&amp;gt; log_2 n &amp;lt;/math&amp;gt;, следовательно, общая сложность алгоритма равна &amp;lt;math&amp;gt; O(n log_2 n) &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
2. В наихудшем случае каждое разбиение приводит к образованию подмассивов длины &amp;lt;math&amp;gt; 1 &amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt; n - 1&amp;lt;/math&amp;gt; соответственно. Общая сложность алгоритма в таком случае равна &amp;lt;math&amp;gt; O(n^2) &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
Так как для проведения вычислений задействовано &amp;lt;math&amp;gt; p = 2^N &amp;lt;/math&amp;gt; процессоров, можно воспользоваться следующим алгоритмом распределения данных между процессорами. Распределим произвольным образом данные между процессорами, далее выбираем некоторым образом ведущий элемент и рассылаем его всем процессорам системы. Т.к. топология системы имеет вид n-мерного куба, номер каждого процессора имеет двоичное представление длины &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, следовательно, можно ввести правило: на каждом процессоре происходит сравнение имеющегося блока данных с текущим ведущим элементом, после чего элементы меньше ведущего отправляются от процессора с номером &amp;lt;math&amp;gt;n_1&amp;lt;/math&amp;gt; процессору номер &amp;lt;math&amp;gt;n_2&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;n_1&amp;lt;/math&amp;gt; отличается от &amp;lt;math&amp;gt;n_2&amp;lt;/math&amp;gt; только в n-том разряде двоичного представления, в двоичном представлении числа &amp;lt;math&amp;gt;n_1&amp;lt;/math&amp;gt; на n-той позиции стоит 1, а &amp;lt;math&amp;gt;n_2&amp;lt;/math&amp;gt; — 0. Таким образом, после данной операции все данные будут разделены между процессорами, образующими n-1-мерные кубы таким образом, что элемент блока данных любого процессора из первого куба больше любого элемента блока данных процессора из второго куба. Повторив аналогичные действия для каждого из n-1-мерных кубов, получим 4 n-2-мерных куба и т.д. &lt;br /&gt;
&lt;br /&gt;
Для наглядности приведем пример: пусть &amp;lt;math&amp;gt; p = 2^3 = 8 &amp;lt;/math&amp;gt;. Ниже приведены графы, иллюстрирующие распределение данных на каждой итерации.&lt;br /&gt;
&lt;br /&gt;
[[file:Gr 1.png|thumb|center|700px|Рисунок 1. Итерация 1.]]&lt;br /&gt;
[[file:Gr 2.png|thumb|center|700px|Рисунок 2. Итерация 2.]]&lt;br /&gt;
[[file:Gr 3.png|thumb|center|700px|Рисунок 3. Итерация 3.]]&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма алгоритма ===&lt;br /&gt;
Основной идеей данного алгоритма является разбиение всего массива данных на блоки меньшего размера таким образом, что между соответствующими блоками после разбиения можно установить отношение упорядоченности. Сортировка производится следующим образом: выбирается некоторым образом ведущий элемент, после чего происходит разделение исходного массива данных на два блока относительно ведущего элемента: в первый блок помещаются элементы, меньшие ведущего, а во второй — большие ведущего. Таким образом, можно утверждать, что наибольший элемент первого блока меньше наименьшего элемента второго блока. Это означает, что повторив эту операцию для каждого из блоков отдельно некоторое количество раз и объединив результаты, получим массив с исходными данными в отсортированном виде. Из описания становится очевидно, что данный алгоритм можно легко обобщить для параллельной вычислительной системы с количеством процессоров &amp;lt;math&amp;gt;p = 2^n&amp;lt;/math&amp;gt;. Для этого алгоритм необходимо лишь дополнить методом выбора процессоров, между которыми будут происходить обмены данными на i-ом шаге. Подробное описание метода распределения данных между вычислительными узлами можно найти в разделе 1.7. Последним этапом работы алгоритма является объединение разрозненных блоков отсортированных данных в единый массив в правильном порядке. Порядок объединения не трудно восстановить исходя из двоичных представлений номеров процессоров.&lt;br /&gt;
&lt;br /&gt;
Очевидно, что наиболее медленной операцией в описанной выше схеме является операция обмена данными между процессорами, следовательно, хотелось бы получить некоторую оценку количества обменов. Такая оценка приведена ниже:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\sum_{i=1}^{n} i = n(n+1)/2 ≈ \log^2 p &amp;lt;/math&amp;gt; &amp;lt;ref&amp;gt; http://ssd.sscc.ru/ru — Supercomputer Software Department &amp;lt;/ref&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt; p &amp;lt;/math&amp;gt; — количество задействованных процессоров.&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные алгоритма ===&lt;br /&gt;
&#039;&#039;&#039;Входные данные:&#039;&#039;&#039; любая числовая последовательность произвольной конечной длины. Так как параллельный алгоритм предполагает выбор разделяющего элемента случайным образом, построение последовательностей специального вида не приводит к увеличению вероятности неравномерного распределения данных между вычислительными узлами. Это значит, что эффективность алгоритма не зависит от вида входной последовательности. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные:&#039;&#039;&#039; последовательность чисел в отсортированном виде.&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&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;references /&amp;gt;&lt;/div&gt;</summary>
		<author><name>Ashabokov 415</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Ashabokov_415/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%B1%D1%8B%D1%81%D1%82%D1%80%D0%BE%D0%B9_%D1%81%D0%BE%D1%80%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B8&amp;diff=27624</id>
		<title>Участник:Ashabokov 415/Алгоритм быстрой сортировки</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Ashabokov_415/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%B1%D1%8B%D1%81%D1%82%D1%80%D0%BE%D0%B9_%D1%81%D0%BE%D1%80%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B8&amp;diff=27624"/>
		<updated>2019-11-30T22:42:08Z</updated>

		<summary type="html">&lt;p&gt;Ashabokov 415: /* Информационный граф */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&#039;&#039;&#039;Алгоритм быстрой сортировки&#039;&#039;&#039; &lt;br /&gt;
&lt;br /&gt;
== Свойства и структура алгоритмов ==&lt;br /&gt;
&lt;br /&gt;
=== Общее описание алгоритма &amp;lt;ref&amp;gt; https://en.wikipedia.org/wiki/Quicksort — From Wikipedia, the free encyclopedia &amp;lt;/ref&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
Быстрая сортировка, сортировка Хоара —  широко известный алгоритм сортировки, разработанный английским информатиком Чарльзом Хоаром во время его работы в МГУ в 1960 году.&lt;br /&gt;
&lt;br /&gt;
Один из самых быстрых известных универсальных алгоритмов сортировки массивов: в среднем  &amp;lt;math&amp;gt; O (n \log n) &amp;lt;/math&amp;gt; обменов при упорядочении &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; элементов; из-за наличия ряда недостатков на практике обычно используется с некоторыми доработками. Фактически данный алгоритм является улучшением алгоритма сортировки прямого обмена (см. ниже).&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
Алгоритм состоит из трех основных шагов:&lt;br /&gt;
&lt;br /&gt;
1. Выбрать опорный элемент (см. ниже). Пусть это будет элемент &amp;lt;math&amp;gt; a&#039; &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
2. Используя операции сравнения элементов массива с опорным и перестановки элементов массива, привести исходный массив к виду: &amp;lt;math&amp;gt; a_1 ... a_m a&#039; a_{m+2} ... a_n &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt; a_j &amp;lt; a&#039;, j = 1 ... m &amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt; a_i \geq a&#039;, i = (m+1) ... n  &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; — длина массива.&lt;br /&gt;
&lt;br /&gt;
3. Рекурсивно применить алгоритм к каждому из массивов: &amp;lt;math&amp;gt; a_1 ... a_m &amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt; a_{m+1} ... a_n &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Рассмотрим подробнее метод сравнения и перестановки данных в массиве, применяющийся на шаге 2. Для этого часто используют так называемое разбиение Хоара &amp;lt;ref&amp;gt; https://en.wikipedia.org/wiki/Quicksort — From Wikipedia, the free encyclopedia &amp;lt;/ref&amp;gt;. Суть данного метода заключается в следующем: выбираются два указателя, указывающие на первый и последний элементы массива соответственно, пость для наглядности это будут &amp;lt;math&amp;gt; i = 1 &amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt; j = n &amp;lt;/math&amp;gt;. Далее начинаем сдвигать левый указатель вправо, в правый — влево до тех пор, пока выполнены условия: &amp;lt;math&amp;gt; a_i &amp;lt; a&#039;, a_j \geq a&#039;, i &amp;lt; j &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt; a&#039; &amp;lt;/math&amp;gt; — опорный элемент. Как только найдутся такие &amp;lt;math&amp;gt; i, j &amp;lt;/math&amp;gt;, что &amp;lt;math&amp;gt; a_i \geq a&#039;, a_j &amp;lt; a&#039; &amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt; i &amp;lt; j &amp;lt;/math&amp;gt;, производим перестановку этих двух элементов. Продолжаем этот процесс до тех пор, пока выполнено &amp;lt;math&amp;gt; i &amp;lt; j &amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
Вычислительным ядром данного алгоритма являются операции сравнения и перестановки &amp;lt;math&amp;gt; i&amp;lt;/math&amp;gt;-ого и &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;-ого элементов массива на каждой итерации рекурсивного алгоритма.&lt;br /&gt;
&lt;br /&gt;
Сложность операции разделения массива на два подмассива (сравнение и перестановка элементов массива относительно опорного элемента) занимет время &amp;lt;math&amp;gt; O (log_2 n) &amp;lt;/math&amp;gt;. &amp;lt;ref&amp;gt; https://ru.wikipedia.org/wiki/Быстрая_сортировка &amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
Как и написано выше в разделе &amp;quot;Вычислительное ядро алгоритма&amp;quot;, основную часть данного метода сортировки составляет операция разделения массива относительно опорного элемента, которая в свою очередь состоит из операций сравнения и перестановки.&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма ===&lt;br /&gt;
1. Случайным образом выбрать опорный элемент массива.&lt;br /&gt;
&lt;br /&gt;
2. Сравнить все элементы сортируемого массива с опорным и разделить исходный массив на два подмассива: с элементами меньше опорного и с элементами большие (или равные) опорного. &lt;br /&gt;
&lt;br /&gt;
3. Рекурсивно повторить алгоритм для получившихся подмассивов.&lt;br /&gt;
&lt;br /&gt;
Случайный выбор опорного элемента считается наиболее эффективным, так как при фиксировании позиции опорного элемента (например, в качестве опорного всегда берется элемент, стоящий на первой позиции) может привести к существенному снижению эффективности для массивов определенного вида из-за неравномерного распределения элементов в получившихся подмассивах. Также в качестве опорного элемента можно выбирать медиану массива, но считается, что вычисление медианы на каждой итерации рекурсивного алгоритма — слишком затратная операция.&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
Последовательная сложность данного алгоритма зависит от глубины рекурсии, что в свою очередь зависит от того, насколько удачно были выбраны опорные элементы на каждом витке рекурсии. Рассмотрим несколько возможных случаев.&lt;br /&gt;
&lt;br /&gt;
1. В наилучшем случае выбор опорного элемента на каждом витке рекурсии происходит таким образом, что в результате разбиения исходного массива образуются подмассивы одинаковой длины (с точностью до одного элемента). В таком случае глубина рекурсии составит &amp;lt;math&amp;gt; log_2 n &amp;lt;/math&amp;gt;, следовательно, общая сложность алгоритма равна &amp;lt;math&amp;gt; O(n log_2 n) &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
2. В наихудшем случае каждое разбиение приводит к образованию подмассивов длины &amp;lt;math&amp;gt; 1 &amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt; n - 1&amp;lt;/math&amp;gt; соответственно. Общая сложность алгоритма в таком случае равна &amp;lt;math&amp;gt; O(n^2) &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
Так как для проведения вычислений задействовано &amp;lt;math&amp;gt; p = 2^N &amp;lt;/math&amp;gt; процессоров, можно воспользоваться следующим алгоритмом распределения данных между процессорами. Распределим произвольным образом данные между процессорами, далее выбираем некоторым образом ведущий элемент и рассылаем его всем процессорам системы. Т.к. топология системы имеет вид n-мерного куба, номер каждого процессора имеет двоичное представление длины &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, следовательно, можно ввести правило: на каждом процессоре происходит сравнение имеющегося блока данных с текущим ведущим элементом, после чего элементы меньше ведущего отправляются от процессора с номером &amp;lt;math&amp;gt;n_1&amp;lt;/math&amp;gt; процессору номер &amp;lt;math&amp;gt;n_2&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;n_1&amp;lt;/math&amp;gt; отличается от &amp;lt;math&amp;gt;n_2&amp;lt;/math&amp;gt; только в n-том разряде двоичного представления, в двоичном представлении числа &amp;lt;math&amp;gt;n_1&amp;lt;/math&amp;gt; на n-той позиции стоит 1, а &amp;lt;math&amp;gt;n_2&amp;lt;/math&amp;gt; — 0. Таким образом, после данной операции все данные будут разделены между процессорами, образующими n-1-мерные кубы таким образом, что элемент блока данных любого процессора из первого куба больше любого элемента блока данных процессора из второго куба. Повторив аналогичные действия для каждого из n-1-мерных кубов, получим 4 n-2-мерных куба и т.д. &lt;br /&gt;
&lt;br /&gt;
Для наглядности приведем пример: пусть &amp;lt;math&amp;gt; p = 2^3 = 8 &amp;lt;/math&amp;gt;. Ниже приведены графы, иллюстрирующие распределение данных на каждой итерации.&lt;br /&gt;
&lt;br /&gt;
[[file:Gr 1.png|thumb|center|700px|Рисунок 1. Итерация 1.]]&lt;br /&gt;
[[file:Gr 2.png|thumb|center|700px|Рисунок 2. Итерация 2.]]&lt;br /&gt;
[[file:Gr 3.png|thumb|center|700px|Рисунок 3. Итерация 3.]]&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма алгоритма ===&lt;br /&gt;
Основной идеей данного алгоритма является разбиение всего массива данных на блоки меньшего размера таким образом, что между соответствующими блоками после разбиения можно установить отношение упорядоченности. Сортировка производится следующим образом: выбирается некоторым образом ведущий элемент, после чего происходит разделение исходного массива данных на два блока относительно ведущего элемента: в первый блок помещаются элементы, меньшие ведущего, а во второй — большие ведущего. Таким образом, можно утверждать, что наибольший элемент первого блока меньше наименьшего элемента второго блока. Это означает, что повторив эту операцию для каждого из блоков отдельно некоторое количество раз и объединив результаты, получим массив с исходными данными в отсортированном виде. Из описания становится очевидно, что данный алгоритм можно легко обобщить для параллельной вычислительной системы с количеством процессоров &amp;lt;math&amp;gt;p = 2^n&amp;lt;/math&amp;gt;. Для этого алгоритм необходимо лишь дополнить методом выбора процессоров, между которыми будут происходить обмены данными на i-ом шаге. Подробное описание метода распределения данных между вычислительными узлами можно найти в разделе 1.7. Последним этапом работы алгоритма является объединение разрозненных блоков отсортированных данных в единый массив в правильном порядке. Порядок объединения не трудно восстановить исходя из двоичных представлений номеров процессоров.&lt;br /&gt;
&lt;br /&gt;
Очевидно, что наиболее медленной операцией в описанной выше схеме является операция обмена данными между процессорами, следовательно, хотелось бы получить некоторую оценку количества обменов. Такая оценка приведена ниже:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\sum_{i=1}^{n} i = n(n+1)/2 ≈ \log^2 p &amp;lt;/math&amp;gt; &amp;lt;ref&amp;gt; http://ssd.sscc.ru/ru — Supercomputer Software Department &amp;lt;/ref&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt; p &amp;lt;/math&amp;gt; — количество задействованных процессоров.&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные алгоритма ===&lt;br /&gt;
&#039;&#039;&#039;Входные данные:&#039;&#039;&#039; любая числовая последовательность произвольной конечной длины. Так как параллельный алгоритм предполагает выбор разделяющего элемента случайным образом, построение последовательностей специального вида не приводит к увеличению вероятности неравномерного распределения данных между вычислительными узлами. Это значит, что эффективность алгоритма не зависит от вида входной последовательности. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные:&#039;&#039;&#039; последовательность чисел в отсортированном виде.&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;br /&gt;
&amp;lt;references /&amp;gt;&lt;/div&gt;</summary>
		<author><name>Ashabokov 415</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Ashabokov_415/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%B1%D1%8B%D1%81%D1%82%D1%80%D0%BE%D0%B9_%D1%81%D0%BE%D1%80%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B8&amp;diff=27623</id>
		<title>Участник:Ashabokov 415/Алгоритм быстрой сортировки</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Ashabokov_415/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%B1%D1%8B%D1%81%D1%82%D1%80%D0%BE%D0%B9_%D1%81%D0%BE%D1%80%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B8&amp;diff=27623"/>
		<updated>2019-11-30T22:36:39Z</updated>

		<summary type="html">&lt;p&gt;Ashabokov 415: /* Информационный граф */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&#039;&#039;&#039;Алгоритм быстрой сортировки&#039;&#039;&#039; &lt;br /&gt;
&lt;br /&gt;
== Свойства и структура алгоритмов ==&lt;br /&gt;
&lt;br /&gt;
=== Общее описание алгоритма &amp;lt;ref&amp;gt; https://en.wikipedia.org/wiki/Quicksort — From Wikipedia, the free encyclopedia &amp;lt;/ref&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
Быстрая сортировка, сортировка Хоара —  широко известный алгоритм сортировки, разработанный английским информатиком Чарльзом Хоаром во время его работы в МГУ в 1960 году.&lt;br /&gt;
&lt;br /&gt;
Один из самых быстрых известных универсальных алгоритмов сортировки массивов: в среднем  &amp;lt;math&amp;gt; O (n \log n) &amp;lt;/math&amp;gt; обменов при упорядочении &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; элементов; из-за наличия ряда недостатков на практике обычно используется с некоторыми доработками. Фактически данный алгоритм является улучшением алгоритма сортировки прямого обмена (см. ниже).&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
Алгоритм состоит из трех основных шагов:&lt;br /&gt;
&lt;br /&gt;
1. Выбрать опорный элемент (см. ниже). Пусть это будет элемент &amp;lt;math&amp;gt; a&#039; &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
2. Используя операции сравнения элементов массива с опорным и перестановки элементов массива, привести исходный массив к виду: &amp;lt;math&amp;gt; a_1 ... a_m a&#039; a_{m+2} ... a_n &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt; a_j &amp;lt; a&#039;, j = 1 ... m &amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt; a_i \geq a&#039;, i = (m+1) ... n  &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; — длина массива.&lt;br /&gt;
&lt;br /&gt;
3. Рекурсивно применить алгоритм к каждому из массивов: &amp;lt;math&amp;gt; a_1 ... a_m &amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt; a_{m+1} ... a_n &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Рассмотрим подробнее метод сравнения и перестановки данных в массиве, применяющийся на шаге 2. Для этого часто используют так называемое разбиение Хоара &amp;lt;ref&amp;gt; https://en.wikipedia.org/wiki/Quicksort — From Wikipedia, the free encyclopedia &amp;lt;/ref&amp;gt;. Суть данного метода заключается в следующем: выбираются два указателя, указывающие на первый и последний элементы массива соответственно, пость для наглядности это будут &amp;lt;math&amp;gt; i = 1 &amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt; j = n &amp;lt;/math&amp;gt;. Далее начинаем сдвигать левый указатель вправо, в правый — влево до тех пор, пока выполнены условия: &amp;lt;math&amp;gt; a_i &amp;lt; a&#039;, a_j \geq a&#039;, i &amp;lt; j &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt; a&#039; &amp;lt;/math&amp;gt; — опорный элемент. Как только найдутся такие &amp;lt;math&amp;gt; i, j &amp;lt;/math&amp;gt;, что &amp;lt;math&amp;gt; a_i \geq a&#039;, a_j &amp;lt; a&#039; &amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt; i &amp;lt; j &amp;lt;/math&amp;gt;, производим перестановку этих двух элементов. Продолжаем этот процесс до тех пор, пока выполнено &amp;lt;math&amp;gt; i &amp;lt; j &amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
Вычислительным ядром данного алгоритма являются операции сравнения и перестановки &amp;lt;math&amp;gt; i&amp;lt;/math&amp;gt;-ого и &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;-ого элементов массива на каждой итерации рекурсивного алгоритма.&lt;br /&gt;
&lt;br /&gt;
Сложность операции разделения массива на два подмассива (сравнение и перестановка элементов массива относительно опорного элемента) занимет время &amp;lt;math&amp;gt; O (log_2 n) &amp;lt;/math&amp;gt;. &amp;lt;ref&amp;gt; https://ru.wikipedia.org/wiki/Быстрая_сортировка &amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
Как и написано выше в разделе &amp;quot;Вычислительное ядро алгоритма&amp;quot;, основную часть данного метода сортировки составляет операция разделения массива относительно опорного элемента, которая в свою очередь состоит из операций сравнения и перестановки.&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма ===&lt;br /&gt;
1. Случайным образом выбрать опорный элемент массива.&lt;br /&gt;
&lt;br /&gt;
2. Сравнить все элементы сортируемого массива с опорным и разделить исходный массив на два подмассива: с элементами меньше опорного и с элементами большие (или равные) опорного. &lt;br /&gt;
&lt;br /&gt;
3. Рекурсивно повторить алгоритм для получившихся подмассивов.&lt;br /&gt;
&lt;br /&gt;
Случайный выбор опорного элемента считается наиболее эффективным, так как при фиксировании позиции опорного элемента (например, в качестве опорного всегда берется элемент, стоящий на первой позиции) может привести к существенному снижению эффективности для массивов определенного вида из-за неравномерного распределения элементов в получившихся подмассивах. Также в качестве опорного элемента можно выбирать медиану массива, но считается, что вычисление медианы на каждой итерации рекурсивного алгоритма — слишком затратная операция.&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
Последовательная сложность данного алгоритма зависит от глубины рекурсии, что в свою очередь зависит от того, насколько удачно были выбраны опорные элементы на каждом витке рекурсии. Рассмотрим несколько возможных случаев.&lt;br /&gt;
&lt;br /&gt;
1. В наилучшем случае выбор опорного элемента на каждом витке рекурсии происходит таким образом, что в результате разбиения исходного массива образуются подмассивы одинаковой длины (с точностью до одного элемента). В таком случае глубина рекурсии составит &amp;lt;math&amp;gt; log_2 n &amp;lt;/math&amp;gt;, следовательно, общая сложность алгоритма равна &amp;lt;math&amp;gt; O(n log_2 n) &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
2. В наихудшем случае каждое разбиение приводит к образованию подмассивов длины &amp;lt;math&amp;gt; 1 &amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt; n - 1&amp;lt;/math&amp;gt; соответственно. Общая сложность алгоритма в таком случае равна &amp;lt;math&amp;gt; O(n^2) &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
Так как для проведения вычислений задействовано &amp;lt;math&amp;gt; p = 2^N &amp;lt;/math&amp;gt; процессоров, можно воспользоваться следующим алгоритмом распределения данных между процессорами. Распределим произвольным образом данные между процессорами, далее выбираем некоторым образом ведущий элемент и рассылаем его всем процессорам системы. Т.к. топология системы имеет вид n-мерного куба, номер каждого процессора имеет двоичное представление длины &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, следовательно, можно ввести правило: на каждом процессоре происходит сравнение имеющегося блока данных с текущим ведущим элементом, после чего элементы меньше ведущего отправляются от процессора с номером &amp;lt;math&amp;gt;n_1&amp;lt;/math&amp;gt; процессору номер &amp;lt;math&amp;gt;n_2&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;n_1&amp;lt;/math&amp;gt; отличается от &amp;lt;math&amp;gt;n_2&amp;lt;/math&amp;gt; только в n-том разряде двоичного представления, в двоичном представлении числа &amp;lt;math&amp;gt;n_1&amp;lt;/math&amp;gt; на n-той позиции стоит 1, а &amp;lt;math&amp;gt;n_2&amp;lt;/math&amp;gt; — 0. Таким образом, после данной операции все данные будут разделены между процессорами, образующими n-1-мерные кубы таким образом, что элемент блока данных любого процессора из первого куба больше любого элемента блока данных процессора из второго куба. Повторив аналогичные действия для каждого из n-1-мерных кубов, получим 4 n-2-мерных куба и т.д. &lt;br /&gt;
&lt;br /&gt;
Для наглядности приведем пример: пусть &amp;lt;math&amp;gt; p = 2^3 = 8 &amp;lt;/math&amp;gt;. Ниже приведены графы, иллюстрирующие распределение данных на каждой итерации.&lt;br /&gt;
&lt;br /&gt;
[[file:Scalability vector scalar mult.png|thumb|center|100px|Рисунок 1. ]]&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма алгоритма ===&lt;br /&gt;
Основной идеей данного алгоритма является разбиение всего массива данных на блоки меньшего размера таким образом, что между соответствующими блоками после разбиения можно установить отношение упорядоченности. Сортировка производится следующим образом: выбирается некоторым образом ведущий элемент, после чего происходит разделение исходного массива данных на два блока относительно ведущего элемента: в первый блок помещаются элементы, меньшие ведущего, а во второй — большие ведущего. Таким образом, можно утверждать, что наибольший элемент первого блока меньше наименьшего элемента второго блока. Это означает, что повторив эту операцию для каждого из блоков отдельно некоторое количество раз и объединив результаты, получим массив с исходными данными в отсортированном виде. Из описания становится очевидно, что данный алгоритм можно легко обобщить для параллельной вычислительной системы с количеством процессоров &amp;lt;math&amp;gt;p = 2^n&amp;lt;/math&amp;gt;. Для этого алгоритм необходимо лишь дополнить методом выбора процессоров, между которыми будут происходить обмены данными на i-ом шаге. Подробное описание метода распределения данных между вычислительными узлами можно найти в разделе 1.7. Последним этапом работы алгоритма является объединение разрозненных блоков отсортированных данных в единый массив в правильном порядке. Порядок объединения не трудно восстановить исходя из двоичных представлений номеров процессоров.&lt;br /&gt;
&lt;br /&gt;
Очевидно, что наиболее медленной операцией в описанной выше схеме является операция обмена данными между процессорами, следовательно, хотелось бы получить некоторую оценку количества обменов. Такая оценка приведена ниже:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\sum_{i=1}^{n} i = n(n+1)/2 ≈ \log^2 p &amp;lt;/math&amp;gt; &amp;lt;ref&amp;gt; http://ssd.sscc.ru/ru — Supercomputer Software Department &amp;lt;/ref&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt; p &amp;lt;/math&amp;gt; — количество задействованных процессоров.&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные алгоритма ===&lt;br /&gt;
&#039;&#039;&#039;Входные данные:&#039;&#039;&#039; любая числовая последовательность произвольной конечной длины. Так как параллельный алгоритм предполагает выбор разделяющего элемента случайным образом, построение последовательностей специального вида не приводит к увеличению вероятности неравномерного распределения данных между вычислительными узлами. Это значит, что эффективность алгоритма не зависит от вида входной последовательности. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные:&#039;&#039;&#039; последовательность чисел в отсортированном виде.&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;br /&gt;
&amp;lt;references /&amp;gt;&lt;/div&gt;</summary>
		<author><name>Ashabokov 415</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Ashabokov_415/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%B1%D1%8B%D1%81%D1%82%D1%80%D0%BE%D0%B9_%D1%81%D0%BE%D1%80%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B8&amp;diff=27622</id>
		<title>Участник:Ashabokov 415/Алгоритм быстрой сортировки</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Ashabokov_415/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%B1%D1%8B%D1%81%D1%82%D1%80%D0%BE%D0%B9_%D1%81%D0%BE%D1%80%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B8&amp;diff=27622"/>
		<updated>2019-11-30T22:34:12Z</updated>

		<summary type="html">&lt;p&gt;Ashabokov 415: /* Информационный граф */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&#039;&#039;&#039;Алгоритм быстрой сортировки&#039;&#039;&#039; &lt;br /&gt;
&lt;br /&gt;
== Свойства и структура алгоритмов ==&lt;br /&gt;
&lt;br /&gt;
=== Общее описание алгоритма &amp;lt;ref&amp;gt; https://en.wikipedia.org/wiki/Quicksort — From Wikipedia, the free encyclopedia &amp;lt;/ref&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
Быстрая сортировка, сортировка Хоара —  широко известный алгоритм сортировки, разработанный английским информатиком Чарльзом Хоаром во время его работы в МГУ в 1960 году.&lt;br /&gt;
&lt;br /&gt;
Один из самых быстрых известных универсальных алгоритмов сортировки массивов: в среднем  &amp;lt;math&amp;gt; O (n \log n) &amp;lt;/math&amp;gt; обменов при упорядочении &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; элементов; из-за наличия ряда недостатков на практике обычно используется с некоторыми доработками. Фактически данный алгоритм является улучшением алгоритма сортировки прямого обмена (см. ниже).&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
Алгоритм состоит из трех основных шагов:&lt;br /&gt;
&lt;br /&gt;
1. Выбрать опорный элемент (см. ниже). Пусть это будет элемент &amp;lt;math&amp;gt; a&#039; &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
2. Используя операции сравнения элементов массива с опорным и перестановки элементов массива, привести исходный массив к виду: &amp;lt;math&amp;gt; a_1 ... a_m a&#039; a_{m+2} ... a_n &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt; a_j &amp;lt; a&#039;, j = 1 ... m &amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt; a_i \geq a&#039;, i = (m+1) ... n  &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; — длина массива.&lt;br /&gt;
&lt;br /&gt;
3. Рекурсивно применить алгоритм к каждому из массивов: &amp;lt;math&amp;gt; a_1 ... a_m &amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt; a_{m+1} ... a_n &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Рассмотрим подробнее метод сравнения и перестановки данных в массиве, применяющийся на шаге 2. Для этого часто используют так называемое разбиение Хоара &amp;lt;ref&amp;gt; https://en.wikipedia.org/wiki/Quicksort — From Wikipedia, the free encyclopedia &amp;lt;/ref&amp;gt;. Суть данного метода заключается в следующем: выбираются два указателя, указывающие на первый и последний элементы массива соответственно, пость для наглядности это будут &amp;lt;math&amp;gt; i = 1 &amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt; j = n &amp;lt;/math&amp;gt;. Далее начинаем сдвигать левый указатель вправо, в правый — влево до тех пор, пока выполнены условия: &amp;lt;math&amp;gt; a_i &amp;lt; a&#039;, a_j \geq a&#039;, i &amp;lt; j &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt; a&#039; &amp;lt;/math&amp;gt; — опорный элемент. Как только найдутся такие &amp;lt;math&amp;gt; i, j &amp;lt;/math&amp;gt;, что &amp;lt;math&amp;gt; a_i \geq a&#039;, a_j &amp;lt; a&#039; &amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt; i &amp;lt; j &amp;lt;/math&amp;gt;, производим перестановку этих двух элементов. Продолжаем этот процесс до тех пор, пока выполнено &amp;lt;math&amp;gt; i &amp;lt; j &amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
Вычислительным ядром данного алгоритма являются операции сравнения и перестановки &amp;lt;math&amp;gt; i&amp;lt;/math&amp;gt;-ого и &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;-ого элементов массива на каждой итерации рекурсивного алгоритма.&lt;br /&gt;
&lt;br /&gt;
Сложность операции разделения массива на два подмассива (сравнение и перестановка элементов массива относительно опорного элемента) занимет время &amp;lt;math&amp;gt; O (log_2 n) &amp;lt;/math&amp;gt;. &amp;lt;ref&amp;gt; https://ru.wikipedia.org/wiki/Быстрая_сортировка &amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
Как и написано выше в разделе &amp;quot;Вычислительное ядро алгоритма&amp;quot;, основную часть данного метода сортировки составляет операция разделения массива относительно опорного элемента, которая в свою очередь состоит из операций сравнения и перестановки.&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма ===&lt;br /&gt;
1. Случайным образом выбрать опорный элемент массива.&lt;br /&gt;
&lt;br /&gt;
2. Сравнить все элементы сортируемого массива с опорным и разделить исходный массив на два подмассива: с элементами меньше опорного и с элементами большие (или равные) опорного. &lt;br /&gt;
&lt;br /&gt;
3. Рекурсивно повторить алгоритм для получившихся подмассивов.&lt;br /&gt;
&lt;br /&gt;
Случайный выбор опорного элемента считается наиболее эффективным, так как при фиксировании позиции опорного элемента (например, в качестве опорного всегда берется элемент, стоящий на первой позиции) может привести к существенному снижению эффективности для массивов определенного вида из-за неравномерного распределения элементов в получившихся подмассивах. Также в качестве опорного элемента можно выбирать медиану массива, но считается, что вычисление медианы на каждой итерации рекурсивного алгоритма — слишком затратная операция.&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
Последовательная сложность данного алгоритма зависит от глубины рекурсии, что в свою очередь зависит от того, насколько удачно были выбраны опорные элементы на каждом витке рекурсии. Рассмотрим несколько возможных случаев.&lt;br /&gt;
&lt;br /&gt;
1. В наилучшем случае выбор опорного элемента на каждом витке рекурсии происходит таким образом, что в результате разбиения исходного массива образуются подмассивы одинаковой длины (с точностью до одного элемента). В таком случае глубина рекурсии составит &amp;lt;math&amp;gt; log_2 n &amp;lt;/math&amp;gt;, следовательно, общая сложность алгоритма равна &amp;lt;math&amp;gt; O(n log_2 n) &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
2. В наихудшем случае каждое разбиение приводит к образованию подмассивов длины &amp;lt;math&amp;gt; 1 &amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt; n - 1&amp;lt;/math&amp;gt; соответственно. Общая сложность алгоритма в таком случае равна &amp;lt;math&amp;gt; O(n^2) &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
Так как для проведения вычислений задействовано &amp;lt;math&amp;gt; p = 2^N &amp;lt;/math&amp;gt; процессоров, можно воспользоваться следующим алгоритмом распределения данных между процессорами. Распределим произвольным образом данные между процессорами, далее выбираем некоторым образом ведущий элемент и рассылаем его всем процессорам системы. Т.к. топология системы имеет вид n-мерного куба, номер каждого процессора имеет двоичное представление длины &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, следовательно, можно ввести правило: на каждом процессоре происходит сравнение имеющегося блока данных с текущим ведущим элементом, после чего элементы меньше ведущего отправляются от процессора с номером &amp;lt;math&amp;gt;n_1&amp;lt;/math&amp;gt; процессору номер &amp;lt;math&amp;gt;n_2&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;n_1&amp;lt;/math&amp;gt; отличается от &amp;lt;math&amp;gt;n_2&amp;lt;/math&amp;gt; только в n-том разряде двоичного представления, в двоичном представлении числа &amp;lt;math&amp;gt;n_1&amp;lt;/math&amp;gt; на n-той позиции стоит 1, а &amp;lt;math&amp;gt;n_2&amp;lt;/math&amp;gt; — 0. Таким образом, после данной операции все данные будут разделены между процессорами, образующими n-1-мерные кубы таким образом, что элемент блока данных любого процессора из первого куба больше любого элемента блока данных процессора из второго куба. Повторив аналогичные действия для каждого из n-1-мерных кубов, получим 4 n-2-мерных куба и т.д. &lt;br /&gt;
&lt;br /&gt;
Для наглядности приведем пример: пусть &amp;lt;math&amp;gt; p = 2^3 = 8 &amp;lt;/math&amp;gt;. Ниже приведены графы, иллюстрирующие распределение данных на каждой итерации.&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма алгоритма ===&lt;br /&gt;
Основной идеей данного алгоритма является разбиение всего массива данных на блоки меньшего размера таким образом, что между соответствующими блоками после разбиения можно установить отношение упорядоченности. Сортировка производится следующим образом: выбирается некоторым образом ведущий элемент, после чего происходит разделение исходного массива данных на два блока относительно ведущего элемента: в первый блок помещаются элементы, меньшие ведущего, а во второй — большие ведущего. Таким образом, можно утверждать, что наибольший элемент первого блока меньше наименьшего элемента второго блока. Это означает, что повторив эту операцию для каждого из блоков отдельно некоторое количество раз и объединив результаты, получим массив с исходными данными в отсортированном виде. Из описания становится очевидно, что данный алгоритм можно легко обобщить для параллельной вычислительной системы с количеством процессоров &amp;lt;math&amp;gt;p = 2^n&amp;lt;/math&amp;gt;. Для этого алгоритм необходимо лишь дополнить методом выбора процессоров, между которыми будут происходить обмены данными на i-ом шаге. Подробное описание метода распределения данных между вычислительными узлами можно найти в разделе 1.7. Последним этапом работы алгоритма является объединение разрозненных блоков отсортированных данных в единый массив в правильном порядке. Порядок объединения не трудно восстановить исходя из двоичных представлений номеров процессоров.&lt;br /&gt;
&lt;br /&gt;
Очевидно, что наиболее медленной операцией в описанной выше схеме является операция обмена данными между процессорами, следовательно, хотелось бы получить некоторую оценку количества обменов. Такая оценка приведена ниже:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\sum_{i=1}^{n} i = n(n+1)/2 ≈ \log^2 p &amp;lt;/math&amp;gt; &amp;lt;ref&amp;gt; http://ssd.sscc.ru/ru — Supercomputer Software Department &amp;lt;/ref&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt; p &amp;lt;/math&amp;gt; — количество задействованных процессоров.&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные алгоритма ===&lt;br /&gt;
&#039;&#039;&#039;Входные данные:&#039;&#039;&#039; любая числовая последовательность произвольной конечной длины. Так как параллельный алгоритм предполагает выбор разделяющего элемента случайным образом, построение последовательностей специального вида не приводит к увеличению вероятности неравномерного распределения данных между вычислительными узлами. Это значит, что эффективность алгоритма не зависит от вида входной последовательности. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные:&#039;&#039;&#039; последовательность чисел в отсортированном виде.&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;br /&gt;
&amp;lt;references /&amp;gt;&lt;/div&gt;</summary>
		<author><name>Ashabokov 415</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Ashabokov_415/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%B1%D1%8B%D1%81%D1%82%D1%80%D0%BE%D0%B9_%D1%81%D0%BE%D1%80%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B8&amp;diff=27621</id>
		<title>Участник:Ashabokov 415/Алгоритм быстрой сортировки</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Ashabokov_415/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%B1%D1%8B%D1%81%D1%82%D1%80%D0%BE%D0%B9_%D1%81%D0%BE%D1%80%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B8&amp;diff=27621"/>
		<updated>2019-11-30T22:02:50Z</updated>

		<summary type="html">&lt;p&gt;Ashabokov 415: /* Свойства и структура алгоритмов */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&#039;&#039;&#039;Алгоритм быстрой сортировки&#039;&#039;&#039; &lt;br /&gt;
&lt;br /&gt;
== Свойства и структура алгоритмов ==&lt;br /&gt;
&lt;br /&gt;
=== Общее описание алгоритма &amp;lt;ref&amp;gt; https://en.wikipedia.org/wiki/Quicksort — From Wikipedia, the free encyclopedia &amp;lt;/ref&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
Быстрая сортировка, сортировка Хоара —  широко известный алгоритм сортировки, разработанный английским информатиком Чарльзом Хоаром во время его работы в МГУ в 1960 году.&lt;br /&gt;
&lt;br /&gt;
Один из самых быстрых известных универсальных алгоритмов сортировки массивов: в среднем  &amp;lt;math&amp;gt; O (n \log n) &amp;lt;/math&amp;gt; обменов при упорядочении &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; элементов; из-за наличия ряда недостатков на практике обычно используется с некоторыми доработками. Фактически данный алгоритм является улучшением алгоритма сортировки прямого обмена (см. ниже).&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
Алгоритм состоит из трех основных шагов:&lt;br /&gt;
&lt;br /&gt;
1. Выбрать опорный элемент (см. ниже). Пусть это будет элемент &amp;lt;math&amp;gt; a&#039; &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
2. Используя операции сравнения элементов массива с опорным и перестановки элементов массива, привести исходный массив к виду: &amp;lt;math&amp;gt; a_1 ... a_m a&#039; a_{m+2} ... a_n &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt; a_j &amp;lt; a&#039;, j = 1 ... m &amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt; a_i \geq a&#039;, i = (m+1) ... n  &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; — длина массива.&lt;br /&gt;
&lt;br /&gt;
3. Рекурсивно применить алгоритм к каждому из массивов: &amp;lt;math&amp;gt; a_1 ... a_m &amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt; a_{m+1} ... a_n &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Рассмотрим подробнее метод сравнения и перестановки данных в массиве, применяющийся на шаге 2. Для этого часто используют так называемое разбиение Хоара &amp;lt;ref&amp;gt; https://en.wikipedia.org/wiki/Quicksort — From Wikipedia, the free encyclopedia &amp;lt;/ref&amp;gt;. Суть данного метода заключается в следующем: выбираются два указателя, указывающие на первый и последний элементы массива соответственно, пость для наглядности это будут &amp;lt;math&amp;gt; i = 1 &amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt; j = n &amp;lt;/math&amp;gt;. Далее начинаем сдвигать левый указатель вправо, в правый — влево до тех пор, пока выполнены условия: &amp;lt;math&amp;gt; a_i &amp;lt; a&#039;, a_j \geq a&#039;, i &amp;lt; j &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt; a&#039; &amp;lt;/math&amp;gt; — опорный элемент. Как только найдутся такие &amp;lt;math&amp;gt; i, j &amp;lt;/math&amp;gt;, что &amp;lt;math&amp;gt; a_i \geq a&#039;, a_j &amp;lt; a&#039; &amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt; i &amp;lt; j &amp;lt;/math&amp;gt;, производим перестановку этих двух элементов. Продолжаем этот процесс до тех пор, пока выполнено &amp;lt;math&amp;gt; i &amp;lt; j &amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
Вычислительным ядром данного алгоритма являются операции сравнения и перестановки &amp;lt;math&amp;gt; i&amp;lt;/math&amp;gt;-ого и &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;-ого элементов массива на каждой итерации рекурсивного алгоритма.&lt;br /&gt;
&lt;br /&gt;
Сложность операции разделения массива на два подмассива (сравнение и перестановка элементов массива относительно опорного элемента) занимет время &amp;lt;math&amp;gt; O (log_2 n) &amp;lt;/math&amp;gt;. &amp;lt;ref&amp;gt; https://ru.wikipedia.org/wiki/Быстрая_сортировка &amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
Как и написано выше в разделе &amp;quot;Вычислительное ядро алгоритма&amp;quot;, основную часть данного метода сортировки составляет операция разделения массива относительно опорного элемента, которая в свою очередь состоит из операций сравнения и перестановки.&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма ===&lt;br /&gt;
1. Случайным образом выбрать опорный элемент массива.&lt;br /&gt;
&lt;br /&gt;
2. Сравнить все элементы сортируемого массива с опорным и разделить исходный массив на два подмассива: с элементами меньше опорного и с элементами большие (или равные) опорного. &lt;br /&gt;
&lt;br /&gt;
3. Рекурсивно повторить алгоритм для получившихся подмассивов.&lt;br /&gt;
&lt;br /&gt;
Случайный выбор опорного элемента считается наиболее эффективным, так как при фиксировании позиции опорного элемента (например, в качестве опорного всегда берется элемент, стоящий на первой позиции) может привести к существенному снижению эффективности для массивов определенного вида из-за неравномерного распределения элементов в получившихся подмассивах. Также в качестве опорного элемента можно выбирать медиану массива, но считается, что вычисление медианы на каждой итерации рекурсивного алгоритма — слишком затратная операция.&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
Последовательная сложность данного алгоритма зависит от глубины рекурсии, что в свою очередь зависит от того, насколько удачно были выбраны опорные элементы на каждом витке рекурсии. Рассмотрим несколько возможных случаев.&lt;br /&gt;
&lt;br /&gt;
1. В наилучшем случае выбор опорного элемента на каждом витке рекурсии происходит таким образом, что в результате разбиения исходного массива образуются подмассивы одинаковой длины (с точностью до одного элемента). В таком случае глубина рекурсии составит &amp;lt;math&amp;gt; log_2 n &amp;lt;/math&amp;gt;, следовательно, общая сложность алгоритма равна &amp;lt;math&amp;gt; O(n log_2 n) &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
2. В наихудшем случае каждое разбиение приводит к образованию подмассивов длины &amp;lt;math&amp;gt; 1 &amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt; n - 1&amp;lt;/math&amp;gt; соответственно. Общая сложность алгоритма в таком случае равна &amp;lt;math&amp;gt; O(n^2) &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
Так как для проведения вычислений задействовано &amp;lt;math&amp;gt; p = 2^N &amp;lt;/math&amp;gt; процессоров, можно воспользоваться следующим алгоритмом распределения данных между процессорами. Распределим произвольным образом данные между процессорами, далее выбираем некоторым образом ведущий элемент и рассылаем его всем процессорам системы. Т.к. топология системы имеет вид n-мерного куба, номер каждого процессора имеет двоичное представление длины &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, следовательно, можно ввести правило: на каждом процессоре происходит сравнение имеющегося блока данных с текущим ведущим элементом, после чего элементы меньше ведущего отправляются от процессора с номером &amp;lt;math&amp;gt;n_1&amp;lt;/math&amp;gt; процессору номер &amp;lt;math&amp;gt;n_2&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;n_1&amp;lt;/math&amp;gt; отличается от &amp;lt;math&amp;gt;n_2&amp;lt;/math&amp;gt; только в n-том разряде двоичного представления, в двоичном представлении числа &amp;lt;math&amp;gt;n_1&amp;lt;/math&amp;gt; на n-той позиции стоит 1, а &amp;lt;math&amp;gt;n_2&amp;lt;/math&amp;gt; — 0. Таким образом, после данной операции все данные будут разделены между процессорами, образующими n-1-мерные кубы таким образом, что элемент блока данных любого процессора из первого куба больше любого элемента блока данных процессора из второго куба. Повторив аналогичные действия для каждого из n-1-мерных кубов, получим 4 n-2-мерных куба и т.д. &lt;br /&gt;
&lt;br /&gt;
Для наглядности приведем пример: пусть &amp;lt;math&amp;gt; p = 2^3 = 8 &amp;lt;/math&amp;gt;. Ниже приведены графы, иллюстрирующие распределение данных на каждой итерации.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма алгоритма ===&lt;br /&gt;
Основной идеей данного алгоритма является разбиение всего массива данных на блоки меньшего размера таким образом, что между соответствующими блоками после разбиения можно установить отношение упорядоченности. Сортировка производится следующим образом: выбирается некоторым образом ведущий элемент, после чего происходит разделение исходного массива данных на два блока относительно ведущего элемента: в первый блок помещаются элементы, меньшие ведущего, а во второй — большие ведущего. Таким образом, можно утверждать, что наибольший элемент первого блока меньше наименьшего элемента второго блока. Это означает, что повторив эту операцию для каждого из блоков отдельно некоторое количество раз и объединив результаты, получим массив с исходными данными в отсортированном виде. Из описания становится очевидно, что данный алгоритм можно легко обобщить для параллельной вычислительной системы с количеством процессоров &amp;lt;math&amp;gt;p = 2^n&amp;lt;/math&amp;gt;. Для этого алгоритм необходимо лишь дополнить методом выбора процессоров, между которыми будут происходить обмены данными на i-ом шаге. Подробное описание метода распределения данных между вычислительными узлами можно найти в разделе 1.7. Последним этапом работы алгоритма является объединение разрозненных блоков отсортированных данных в единый массив в правильном порядке. Порядок объединения не трудно восстановить исходя из двоичных представлений номеров процессоров.&lt;br /&gt;
&lt;br /&gt;
Очевидно, что наиболее медленной операцией в описанной выше схеме является операция обмена данными между процессорами, следовательно, хотелось бы получить некоторую оценку количества обменов. Такая оценка приведена ниже:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\sum_{i=1}^{n} i = n(n+1)/2 ≈ \log^2 p &amp;lt;/math&amp;gt; &amp;lt;ref&amp;gt; http://ssd.sscc.ru/ru — Supercomputer Software Department &amp;lt;/ref&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt; p &amp;lt;/math&amp;gt; — количество задействованных процессоров.&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные алгоритма ===&lt;br /&gt;
&#039;&#039;&#039;Входные данные:&#039;&#039;&#039; любая числовая последовательность произвольной конечной длины. Так как параллельный алгоритм предполагает выбор разделяющего элемента случайным образом, построение последовательностей специального вида не приводит к увеличению вероятности неравномерного распределения данных между вычислительными узлами. Это значит, что эффективность алгоритма не зависит от вида входной последовательности. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные:&#039;&#039;&#039; последовательность чисел в отсортированном виде.&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;br /&gt;
&amp;lt;references /&amp;gt;&lt;/div&gt;</summary>
		<author><name>Ashabokov 415</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Ashabokov_415/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%B1%D1%8B%D1%81%D1%82%D1%80%D0%BE%D0%B9_%D1%81%D0%BE%D1%80%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B8&amp;diff=27620</id>
		<title>Участник:Ashabokov 415/Алгоритм быстрой сортировки</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Ashabokov_415/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%B1%D1%8B%D1%81%D1%82%D1%80%D0%BE%D0%B9_%D1%81%D0%BE%D1%80%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B8&amp;diff=27620"/>
		<updated>2019-11-30T21:49:53Z</updated>

		<summary type="html">&lt;p&gt;Ashabokov 415: /* Информационный граф */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&#039;&#039;&#039;Алгоритм быстрой сортировки&#039;&#039;&#039; &lt;br /&gt;
&lt;br /&gt;
== Свойства и структура алгоритмов ==&lt;br /&gt;
&lt;br /&gt;
=== Общее описание алгоритма &amp;lt;ref&amp;gt; https://en.wikipedia.org/wiki/Quicksort — From Wikipedia, the free encyclopedia &amp;lt;/ref&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
Быстрая сортировка, сортировка Хоара —  широко известный алгоритм сортировки, разработанный английским информатиком Чарльзом Хоаром во время его работы в МГУ в 1960 году.&lt;br /&gt;
&lt;br /&gt;
Один из самых быстрых известных универсальных алгоритмов сортировки массивов: в среднем  &amp;lt;math&amp;gt; O (n \log n) &amp;lt;/math&amp;gt; обменов при упорядочении &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; элементов; из-за наличия ряда недостатков на практике обычно используется с некоторыми доработками. Фактически данный алгоритм является улучшением алгоритма сортировки прямого обмена (см. ниже).&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
Алгоритм состоит из трех основных шагов:&lt;br /&gt;
&lt;br /&gt;
1. Выбрать опорный элемент (см. ниже). Пусть это будет элемент &amp;lt;math&amp;gt; a&#039; &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
2. Используя операции сравнения элементов массива с опорным и перестановки элементов массива, привести исходный массив к виду: &amp;lt;math&amp;gt; a_1 ... a_m a&#039; a_{m+2} ... a_n &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt; a_j &amp;lt; a&#039;, j = 1 ... m &amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt; a_i \geq a&#039;, i = (m+1) ... n  &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; — длина массива.&lt;br /&gt;
&lt;br /&gt;
3. Рекурсивно применить алгоритм к каждому из массивов: &amp;lt;math&amp;gt; a_1 ... a_m &amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt; a_{m+1} ... a_n &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Рассмотрим подробнее метод сравнения и перестановки данных в массиве, применяющийся на шаге 2. Для этого часто используют так называемое разбиение Хоара &amp;lt;ref&amp;gt; https://en.wikipedia.org/wiki/Quicksort — From Wikipedia, the free encyclopedia &amp;lt;/ref&amp;gt;. Суть данного метода заключается в следующем: выбираются два указателя, указывающие на первый и последний элементы массива соответственно, пость для наглядности это будут &amp;lt;math&amp;gt; i = 1 &amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt; j = n &amp;lt;/math&amp;gt;. Далее начинаем сдвигать левый указатель вправо, в правый — влево до тех пор, пока выполнены условия: &amp;lt;math&amp;gt; a_i &amp;lt; a&#039;, a_j \geq a&#039;, i &amp;lt; j &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt; a&#039; &amp;lt;/math&amp;gt; — опорный элемент. Как только найдутся такие &amp;lt;math&amp;gt; i, j &amp;lt;/math&amp;gt;, что &amp;lt;math&amp;gt; a_i \geq a&#039;, a_j &amp;lt; a&#039; &amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt; i &amp;lt; j &amp;lt;/math&amp;gt;, производим перестановку этих двух элементов. Продолжаем этот процесс до тех пор, пока выполнено &amp;lt;math&amp;gt; i &amp;lt; j &amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
Вычислительным ядром данного алгоритма являются операции сравнения и перестановки &amp;lt;math&amp;gt; i&amp;lt;/math&amp;gt;-ого и &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;-ого элементов массива на каждой итерации рекурсивного алгоритма.&lt;br /&gt;
&lt;br /&gt;
Сложность операции разделения массива на два подмассива (сравнение и перестановка элементов массива относительно опорного элемента) занимет время &amp;lt;math&amp;gt; O (log_2 n) &amp;lt;/math&amp;gt;. &amp;lt;ref&amp;gt; https://ru.wikipedia.org/wiki/Быстрая_сортировка &amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
Как и написано выше в разделе &amp;quot;Вычислительное ядро алгоритма&amp;quot;, основную часть данного метода сортировки составляет операция разделения массива относительно опорного элемента, которая в свою очередь состоит из операций сравнения и перестановки.&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма ===&lt;br /&gt;
1. Случайным образом выбрать опорный элемент массива.&lt;br /&gt;
&lt;br /&gt;
2. Сравнить все элементы сортируемого массива с опорным и разделить исходный массив на два подмассива: с элементами меньше опорного и с элементами большие (или равные) опорного. &lt;br /&gt;
&lt;br /&gt;
3. Рекурсивно повторить алгоритм для получившихся подмассивов.&lt;br /&gt;
&lt;br /&gt;
Случайный выбор опорного элемента считается наиболее эффективным, так как при фиксировании позиции опорного элемента (например, в качестве опорного всегда берется элемент, стоящий на первой позиции) может привести к существенному снижению эффективности для массивов определенного вида из-за неравномерного распределения элементов в получившихся подмассивах. Также в качестве опорного элемента можно выбирать медиану массива, но считается, что вычисление медианы на каждой итерации рекурсивного алгоритма — слишком затратная операция.&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
Последовательная сложность данного алгоритма зависит от глубины рекурсии, что в свою очередь зависит от того, насколько удачно были выбраны опорные элементы на каждом витке рекурсии. Рассмотрим несколько возможных случаев.&lt;br /&gt;
&lt;br /&gt;
1. В наилучшем случае выбор опорного элемента на каждом витке рекурсии происходит таким образом, что в результате разбиения исходного массива образуются подмассивы одинаковой длины (с точностью до одного элемента). В таком случае глубина рекурсии составит &amp;lt;math&amp;gt; log_2 n &amp;lt;/math&amp;gt;, следовательно, общая сложность алгоритма равна &amp;lt;math&amp;gt; O(n log_2 n) &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
2. В наихудшем случае каждое разбиение приводит к образованию подмассивов длины &amp;lt;math&amp;gt; 1 &amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt; n - 1&amp;lt;/math&amp;gt; соответственно. Общая сложность алгоритма в таком случае равна &amp;lt;math&amp;gt; O(n^2) &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма алгоритма ===&lt;br /&gt;
Основной идеей данного алгоритма является разбиение всего массива данных на блоки меньшего размера таким образом, что между соответствующими блоками после разбиения можно установить отношение упорядоченности. Сортировка производится следующим образом: выбирается некоторым образом ведущий элемент, после чего происходит разделение исходного массива данных на два блока относительно ведущего элемента: в первый блок помещаются элементы, меньшие ведущего, а во второй — большие ведущего. Таким образом, можно утверждать, что наибольший элемент первого блока меньше наименьшего элемента второго блока. Это означает, что повторив эту операцию для каждого из блоков отдельно некоторое количество раз и объединив результаты, получим массив с исходными данными в отсортированном виде. Из описания становится очевидно, что данный алгоритм можно легко обобщить для параллельной вычислительной системы с количеством процессоров &amp;lt;math&amp;gt;p = 2^n&amp;lt;/math&amp;gt;. Для этого алгоритм необходимо лишь дополнить методом выбора процессоров, между которыми будут происходить обмены данными на i-ом шаге. Распределим произвольным образом данные между процессорами, далее выбираем некоторым образом ведущий элемент и рассылаем его всем процессорам системы. Т.к. топология системы имеет вид n-мерного куба, номер каждого процессора имеет двоичное представление длины &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, следовательно, можно ввести правило: на каждом процессоре происходит сравнение имеющегося блока данных с текущим ведущим элементом, после чего элементы меньше ведущего отправляются от процессора с номером &amp;lt;math&amp;gt;n_1&amp;lt;/math&amp;gt; процессору номер &amp;lt;math&amp;gt;n_2&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;n_1&amp;lt;/math&amp;gt; отличается от &amp;lt;math&amp;gt;n_2&amp;lt;/math&amp;gt; только в n-том разряде двоичного представления, в двоичном представлении числа &amp;lt;math&amp;gt;n_1&amp;lt;/math&amp;gt; на n-той позиции стоит 1, а &amp;lt;math&amp;gt;n_2&amp;lt;/math&amp;gt; — 0. Таким образом, после данной операции все данные будут разделены между процессорами, образующими n-1-мерные кубы таким образом, что элемент блока данных любого процессора из первого куба больше любого элемента блока данных процессора из второго куба. Повторив аналогичные действия для каждого из n-1-мерных кубов, получим 4 n-2-мерных куба и т.д. Последним этапом работы алгоритма является объединение разрозненных блоков отсортированных данных в единый массив в правильном порядке. Порядок объединения не трудно восстановить исходя из двоичных представлений номеров процессоров.&lt;br /&gt;
&lt;br /&gt;
Очевидно, что наиболее медленной операцией в описанной выше схеме является операция обмена данными между процессорами, следовательно, хотелось бы получить некоторую оценку количества обменов. Такая оценка приведена ниже:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\sum_{i=1}^{n} i = n(n+1)/2 ≈ \log^2 p &amp;lt;/math&amp;gt; &amp;lt;ref&amp;gt; http://ssd.sscc.ru/ru — Supercomputer Software Department &amp;lt;/ref&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt; p &amp;lt;/math&amp;gt; — количество задействованных процессоров.&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные алгоритма ===&lt;br /&gt;
&#039;&#039;&#039;Входные данные:&#039;&#039;&#039; любая числовая последовательность произвольной конечной длины. Так как параллельный алгоритм предполагает выбор разделяющего элемента случайным образом, построение последовательностей специального вида не приводит к увеличению вероятности неравномерного распределения данных между вычислительными узлами. Это значит, что эффективность алгоритма не зависит от вида входной последовательности. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные:&#039;&#039;&#039; последовательность чисел в отсортированном виде.&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;br /&gt;
&amp;lt;references /&amp;gt;&lt;/div&gt;</summary>
		<author><name>Ashabokov 415</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Ashabokov_415/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%B1%D1%8B%D1%81%D1%82%D1%80%D0%BE%D0%B9_%D1%81%D0%BE%D1%80%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B8&amp;diff=27619</id>
		<title>Участник:Ashabokov 415/Алгоритм быстрой сортировки</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Ashabokov_415/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%B1%D1%8B%D1%81%D1%82%D1%80%D0%BE%D0%B9_%D1%81%D0%BE%D1%80%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B8&amp;diff=27619"/>
		<updated>2019-11-30T21:45:56Z</updated>

		<summary type="html">&lt;p&gt;Ashabokov 415: /* Последовательная сложность алгоритма */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&#039;&#039;&#039;Алгоритм быстрой сортировки&#039;&#039;&#039; &lt;br /&gt;
&lt;br /&gt;
== Свойства и структура алгоритмов ==&lt;br /&gt;
&lt;br /&gt;
=== Общее описание алгоритма &amp;lt;ref&amp;gt; https://en.wikipedia.org/wiki/Quicksort — From Wikipedia, the free encyclopedia &amp;lt;/ref&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
Быстрая сортировка, сортировка Хоара —  широко известный алгоритм сортировки, разработанный английским информатиком Чарльзом Хоаром во время его работы в МГУ в 1960 году.&lt;br /&gt;
&lt;br /&gt;
Один из самых быстрых известных универсальных алгоритмов сортировки массивов: в среднем  &amp;lt;math&amp;gt; O (n \log n) &amp;lt;/math&amp;gt; обменов при упорядочении &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; элементов; из-за наличия ряда недостатков на практике обычно используется с некоторыми доработками. Фактически данный алгоритм является улучшением алгоритма сортировки прямого обмена (см. ниже).&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
Алгоритм состоит из трех основных шагов:&lt;br /&gt;
&lt;br /&gt;
1. Выбрать опорный элемент (см. ниже). Пусть это будет элемент &amp;lt;math&amp;gt; a&#039; &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
2. Используя операции сравнения элементов массива с опорным и перестановки элементов массива, привести исходный массив к виду: &amp;lt;math&amp;gt; a_1 ... a_m a&#039; a_{m+2} ... a_n &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt; a_j &amp;lt; a&#039;, j = 1 ... m &amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt; a_i \geq a&#039;, i = (m+1) ... n  &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; — длина массива.&lt;br /&gt;
&lt;br /&gt;
3. Рекурсивно применить алгоритм к каждому из массивов: &amp;lt;math&amp;gt; a_1 ... a_m &amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt; a_{m+1} ... a_n &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Рассмотрим подробнее метод сравнения и перестановки данных в массиве, применяющийся на шаге 2. Для этого часто используют так называемое разбиение Хоара &amp;lt;ref&amp;gt; https://en.wikipedia.org/wiki/Quicksort — From Wikipedia, the free encyclopedia &amp;lt;/ref&amp;gt;. Суть данного метода заключается в следующем: выбираются два указателя, указывающие на первый и последний элементы массива соответственно, пость для наглядности это будут &amp;lt;math&amp;gt; i = 1 &amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt; j = n &amp;lt;/math&amp;gt;. Далее начинаем сдвигать левый указатель вправо, в правый — влево до тех пор, пока выполнены условия: &amp;lt;math&amp;gt; a_i &amp;lt; a&#039;, a_j \geq a&#039;, i &amp;lt; j &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt; a&#039; &amp;lt;/math&amp;gt; — опорный элемент. Как только найдутся такие &amp;lt;math&amp;gt; i, j &amp;lt;/math&amp;gt;, что &amp;lt;math&amp;gt; a_i \geq a&#039;, a_j &amp;lt; a&#039; &amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt; i &amp;lt; j &amp;lt;/math&amp;gt;, производим перестановку этих двух элементов. Продолжаем этот процесс до тех пор, пока выполнено &amp;lt;math&amp;gt; i &amp;lt; j &amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
Вычислительным ядром данного алгоритма являются операции сравнения и перестановки &amp;lt;math&amp;gt; i&amp;lt;/math&amp;gt;-ого и &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;-ого элементов массива на каждой итерации рекурсивного алгоритма.&lt;br /&gt;
&lt;br /&gt;
Сложность операции разделения массива на два подмассива (сравнение и перестановка элементов массива относительно опорного элемента) занимет время &amp;lt;math&amp;gt; O (log_2 n) &amp;lt;/math&amp;gt;. &amp;lt;ref&amp;gt; https://ru.wikipedia.org/wiki/Быстрая_сортировка &amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
Как и написано выше в разделе &amp;quot;Вычислительное ядро алгоритма&amp;quot;, основную часть данного метода сортировки составляет операция разделения массива относительно опорного элемента, которая в свою очередь состоит из операций сравнения и перестановки.&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма ===&lt;br /&gt;
1. Случайным образом выбрать опорный элемент массива.&lt;br /&gt;
&lt;br /&gt;
2. Сравнить все элементы сортируемого массива с опорным и разделить исходный массив на два подмассива: с элементами меньше опорного и с элементами большие (или равные) опорного. &lt;br /&gt;
&lt;br /&gt;
3. Рекурсивно повторить алгоритм для получившихся подмассивов.&lt;br /&gt;
&lt;br /&gt;
Случайный выбор опорного элемента считается наиболее эффективным, так как при фиксировании позиции опорного элемента (например, в качестве опорного всегда берется элемент, стоящий на первой позиции) может привести к существенному снижению эффективности для массивов определенного вида из-за неравномерного распределения элементов в получившихся подмассивах. Также в качестве опорного элемента можно выбирать медиану массива, но считается, что вычисление медианы на каждой итерации рекурсивного алгоритма — слишком затратная операция.&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
Последовательная сложность данного алгоритма зависит от глубины рекурсии, что в свою очередь зависит от того, насколько удачно были выбраны опорные элементы на каждом витке рекурсии. Рассмотрим несколько возможных случаев.&lt;br /&gt;
&lt;br /&gt;
1. В наилучшем случае выбор опорного элемента на каждом витке рекурсии происходит таким образом, что в результате разбиения исходного массива образуются подмассивы одинаковой длины (с точностью до одного элемента). В таком случае глубина рекурсии составит &amp;lt;math&amp;gt; log_2 n &amp;lt;/math&amp;gt;, следовательно, общая сложность алгоритма равна &amp;lt;math&amp;gt; O(n log_2 n) &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
2. В наихудшем случае каждое разбиение приводит к образованию подмассивов длины &amp;lt;math&amp;gt; 1 &amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt; n - 1&amp;lt;/math&amp;gt; соответственно. Общая сложность алгоритма в таком случае равна &amp;lt;math&amp;gt; O(n^2) &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма алгоритма ===&lt;br /&gt;
Основной идеей данного алгоритма является разбиение всего массива данных на блоки меньшего размера таким образом, что между соответствующими блоками после разбиения можно установить отношение упорядоченности. Сортировка производится следующим образом: выбирается некоторым образом ведущий элемент, после чего происходит разделение исходного массива данных на два блока относительно ведущего элемента: в первый блок помещаются элементы, меньшие ведущего, а во второй — большие ведущего. Таким образом, можно утверждать, что наибольший элемент первого блока меньше наименьшего элемента второго блока. Это означает, что повторив эту операцию для каждого из блоков отдельно некоторое количество раз и объединив результаты, получим массив с исходными данными в отсортированном виде. Из описания становится очевидно, что данный алгоритм можно легко обобщить для параллельной вычислительной системы с количеством процессоров &amp;lt;math&amp;gt;p = 2^n&amp;lt;/math&amp;gt;. Для этого алгоритм необходимо лишь дополнить методом выбора процессоров, между которыми будут происходить обмены данными на i-ом шаге. Распределим произвольным образом данные между процессорами, далее выбираем некоторым образом ведущий элемент и рассылаем его всем процессорам системы. Т.к. топология системы имеет вид n-мерного куба, номер каждого процессора имеет двоичное представление длины &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, следовательно, можно ввести правило: на каждом процессоре происходит сравнение имеющегося блока данных с текущим ведущим элементом, после чего элементы меньше ведущего отправляются от процессора с номером &amp;lt;math&amp;gt;n_1&amp;lt;/math&amp;gt; процессору номер &amp;lt;math&amp;gt;n_2&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;n_1&amp;lt;/math&amp;gt; отличается от &amp;lt;math&amp;gt;n_2&amp;lt;/math&amp;gt; только в n-том разряде двоичного представления, в двоичном представлении числа &amp;lt;math&amp;gt;n_1&amp;lt;/math&amp;gt; на n-той позиции стоит 1, а &amp;lt;math&amp;gt;n_2&amp;lt;/math&amp;gt; — 0. Таким образом, после данной операции все данные будут разделены между процессорами, образующими n-1-мерные кубы таким образом, что элемент блока данных любого процессора из первого куба больше любого элемента блока данных процессора из второго куба. Повторив аналогичные действия для каждого из n-1-мерных кубов, получим 4 n-2-мерных куба и т.д. Последним этапом работы алгоритма является объединение разрозненных блоков отсортированных данных в единый массив в правильном порядке. Порядок объединения не трудно восстановить исходя из двоичных представлений номеров процессоров.&lt;br /&gt;
&lt;br /&gt;
Очевидно, что наиболее медленной операцией в описанной выше схеме является операция обмена данными между процессорами, следовательно, хотелось бы получить некоторую оценку количества обменов. Такая оценка приведена ниже:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\sum_{i=1}^{n} i = n(n+1)/2 ≈ \log^2 p &amp;lt;/math&amp;gt; &amp;lt;ref&amp;gt; http://ssd.sscc.ru/ru — Supercomputer Software Department &amp;lt;/ref&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt; p &amp;lt;/math&amp;gt; — количество задействованных процессоров.&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные алгоритма ===&lt;br /&gt;
&#039;&#039;&#039;Входные данные:&#039;&#039;&#039; любая числовая последовательность произвольной конечной длины. Так как параллельный алгоритм предполагает выбор разделяющего элемента случайным образом, построение последовательностей специального вида не приводит к увеличению вероятности неравномерного распределения данных между вычислительными узлами. Это значит, что эффективность алгоритма не зависит от вида входной последовательности. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные:&#039;&#039;&#039; последовательность чисел в отсортированном виде.&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;br /&gt;
&amp;lt;references /&amp;gt;&lt;/div&gt;</summary>
		<author><name>Ashabokov 415</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Ashabokov_415/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%B1%D1%8B%D1%81%D1%82%D1%80%D0%BE%D0%B9_%D1%81%D0%BE%D1%80%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B8&amp;diff=27617</id>
		<title>Участник:Ashabokov 415/Алгоритм быстрой сортировки</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Ashabokov_415/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%B1%D1%8B%D1%81%D1%82%D1%80%D0%BE%D0%B9_%D1%81%D0%BE%D1%80%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B8&amp;diff=27617"/>
		<updated>2019-11-30T01:22:13Z</updated>

		<summary type="html">&lt;p&gt;Ashabokov 415: /* Вычислительное ядро алгоритма */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&#039;&#039;&#039;Алгоритм быстрой сортировки&#039;&#039;&#039; &lt;br /&gt;
&lt;br /&gt;
== Свойства и структура алгоритмов ==&lt;br /&gt;
&lt;br /&gt;
=== Общее описание алгоритма &amp;lt;ref&amp;gt; https://en.wikipedia.org/wiki/Quicksort — From Wikipedia, the free encyclopedia &amp;lt;/ref&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
Быстрая сортировка, сортировка Хоара —  широко известный алгоритм сортировки, разработанный английским информатиком Чарльзом Хоаром во время его работы в МГУ в 1960 году.&lt;br /&gt;
&lt;br /&gt;
Один из самых быстрых известных универсальных алгоритмов сортировки массивов: в среднем  &amp;lt;math&amp;gt; O (n \log n) &amp;lt;/math&amp;gt; обменов при упорядочении &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; элементов; из-за наличия ряда недостатков на практике обычно используется с некоторыми доработками. Фактически данный алгоритм является улучшением алгоритма сортировки прямого обмена (см. ниже).&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
Алгоритм состоит из трех основных шагов:&lt;br /&gt;
&lt;br /&gt;
1. Выбрать опорный элемент (см. ниже). Пусть это будет элемент &amp;lt;math&amp;gt; a&#039; &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
2. Используя операции сравнения элементов массива с опорным и перестановки элементов массива, привести исходный массив к виду: &amp;lt;math&amp;gt; a_1 ... a_m a&#039; a_{m+2} ... a_n &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt; a_j &amp;lt; a&#039;, j = 1 ... m &amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt; a_i \geq a&#039;, i = (m+1) ... n  &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; — длина массива.&lt;br /&gt;
&lt;br /&gt;
3. Рекурсивно применить алгоритм к каждому из массивов: &amp;lt;math&amp;gt; a_1 ... a_m &amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt; a_{m+1} ... a_n &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Рассмотрим подробнее метод сравнения и перестановки данных в массиве, применяющийся на шаге 2. Для этого часто используют так называемое разбиение Хоара &amp;lt;ref&amp;gt; https://en.wikipedia.org/wiki/Quicksort — From Wikipedia, the free encyclopedia &amp;lt;/ref&amp;gt;. Суть данного метода заключается в следующем: выбираются два указателя, указывающие на первый и последний элементы массива соответственно, пость для наглядности это будут &amp;lt;math&amp;gt; i = 1 &amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt; j = n &amp;lt;/math&amp;gt;. Далее начинаем сдвигать левый указатель вправо, в правый — влево до тех пор, пока выполнены условия: &amp;lt;math&amp;gt; a_i &amp;lt; a&#039;, a_j \geq a&#039;, i &amp;lt; j &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt; a&#039; &amp;lt;/math&amp;gt; — опорный элемент. Как только найдутся такие &amp;lt;math&amp;gt; i, j &amp;lt;/math&amp;gt;, что &amp;lt;math&amp;gt; a_i \geq a&#039;, a_j &amp;lt; a&#039; &amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt; i &amp;lt; j &amp;lt;/math&amp;gt;, производим перестановку этих двух элементов. Продолжаем этот процесс до тех пор, пока выполнено &amp;lt;math&amp;gt; i &amp;lt; j &amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
Вычислительным ядром данного алгоритма являются операции сравнения и перестановки &amp;lt;math&amp;gt; i&amp;lt;/math&amp;gt;-ого и &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;-ого элементов массива на каждой итерации рекурсивного алгоритма.&lt;br /&gt;
&lt;br /&gt;
Сложность операции разделения массива на два подмассива (сравнение и перестановка элементов массива относительно опорного элемента) занимет время &amp;lt;math&amp;gt; O (log_2 n) &amp;lt;/math&amp;gt;. &amp;lt;ref&amp;gt; https://ru.wikipedia.org/wiki/Быстрая_сортировка &amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
Как и написано выше в разделе &amp;quot;Вычислительное ядро алгоритма&amp;quot;, основную часть данного метода сортировки составляет операция разделения массива относительно опорного элемента, которая в свою очередь состоит из операций сравнения и перестановки.&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма ===&lt;br /&gt;
1. Случайным образом выбрать опорный элемент массива.&lt;br /&gt;
&lt;br /&gt;
2. Сравнить все элементы сортируемого массива с опорным и разделить исходный массив на два подмассива: с элементами меньше опорного и с элементами большие (или равные) опорного. &lt;br /&gt;
&lt;br /&gt;
3. Рекурсивно повторить алгоритм для получившихся подмассивов.&lt;br /&gt;
&lt;br /&gt;
Случайный выбор опорного элемента считается наиболее эффективным, так как при фиксировании позиции опорного элемента (например, в качестве опорного всегда берется элемент, стоящий на первой позиции) может привести к существенному снижению эффективности для массивов определенного вида из-за неравномерного распределения элементов в получившихся подмассивах. Также в качестве опорного элемента можно выбирать медиану массива, но считается, что вычисление медианы на каждой итерации рекурсивного алгоритма — слишком затратная операция.&lt;br /&gt;
&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;math&amp;gt;p = 2^n&amp;lt;/math&amp;gt;. Для этого алгоритм необходимо лишь дополнить методом выбора процессоров, между которыми будут происходить обмены данными на i-ом шаге. Распределим произвольным образом данные между процессорами, далее выбираем некоторым образом ведущий элемент и рассылаем его всем процессорам системы. Т.к. топология системы имеет вид n-мерного куба, номер каждого процессора имеет двоичное представление длины &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, следовательно, можно ввести правило: на каждом процессоре происходит сравнение имеющегося блока данных с текущим ведущим элементом, после чего элементы меньше ведущего отправляются от процессора с номером &amp;lt;math&amp;gt;n_1&amp;lt;/math&amp;gt; процессору номер &amp;lt;math&amp;gt;n_2&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;n_1&amp;lt;/math&amp;gt; отличается от &amp;lt;math&amp;gt;n_2&amp;lt;/math&amp;gt; только в n-том разряде двоичного представления, в двоичном представлении числа &amp;lt;math&amp;gt;n_1&amp;lt;/math&amp;gt; на n-той позиции стоит 1, а &amp;lt;math&amp;gt;n_2&amp;lt;/math&amp;gt; — 0. Таким образом, после данной операции все данные будут разделены между процессорами, образующими n-1-мерные кубы таким образом, что элемент блока данных любого процессора из первого куба больше любого элемента блока данных процессора из второго куба. Повторив аналогичные действия для каждого из n-1-мерных кубов, получим 4 n-2-мерных куба и т.д. Последним этапом работы алгоритма является объединение разрозненных блоков отсортированных данных в единый массив в правильном порядке. Порядок объединения не трудно восстановить исходя из двоичных представлений номеров процессоров.&lt;br /&gt;
&lt;br /&gt;
Очевидно, что наиболее медленной операцией в описанной выше схеме является операция обмена данными между процессорами, следовательно, хотелось бы получить некоторую оценку количества обменов. Такая оценка приведена ниже:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\sum_{i=1}^{n} i = n(n+1)/2 ≈ \log^2 p &amp;lt;/math&amp;gt; &amp;lt;ref&amp;gt; http://ssd.sscc.ru/ru — Supercomputer Software Department &amp;lt;/ref&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt; p &amp;lt;/math&amp;gt; — количество задействованных процессоров.&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные алгоритма ===&lt;br /&gt;
&#039;&#039;&#039;Входные данные:&#039;&#039;&#039; любая числовая последовательность произвольной конечной длины. Так как параллельный алгоритм предполагает выбор разделяющего элемента случайным образом, построение последовательностей специального вида не приводит к увеличению вероятности неравномерного распределения данных между вычислительными узлами. Это значит, что эффективность алгоритма не зависит от вида входной последовательности. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные:&#039;&#039;&#039; последовательность чисел в отсортированном виде.&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;br /&gt;
&amp;lt;references /&amp;gt;&lt;/div&gt;</summary>
		<author><name>Ashabokov 415</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Ashabokov_415/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%B1%D1%8B%D1%81%D1%82%D1%80%D0%BE%D0%B9_%D1%81%D0%BE%D1%80%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B8&amp;diff=27616</id>
		<title>Участник:Ashabokov 415/Алгоритм быстрой сортировки</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Ashabokov_415/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%B1%D1%8B%D1%81%D1%82%D1%80%D0%BE%D0%B9_%D1%81%D0%BE%D1%80%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B8&amp;diff=27616"/>
		<updated>2019-11-30T01:21:43Z</updated>

		<summary type="html">&lt;p&gt;Ashabokov 415: /* Макроструктура алгоритма */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&#039;&#039;&#039;Алгоритм быстрой сортировки&#039;&#039;&#039; &lt;br /&gt;
&lt;br /&gt;
== Свойства и структура алгоритмов ==&lt;br /&gt;
&lt;br /&gt;
=== Общее описание алгоритма &amp;lt;ref&amp;gt; https://en.wikipedia.org/wiki/Quicksort — From Wikipedia, the free encyclopedia &amp;lt;/ref&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
Быстрая сортировка, сортировка Хоара —  широко известный алгоритм сортировки, разработанный английским информатиком Чарльзом Хоаром во время его работы в МГУ в 1960 году.&lt;br /&gt;
&lt;br /&gt;
Один из самых быстрых известных универсальных алгоритмов сортировки массивов: в среднем  &amp;lt;math&amp;gt; O (n \log n) &amp;lt;/math&amp;gt; обменов при упорядочении &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; элементов; из-за наличия ряда недостатков на практике обычно используется с некоторыми доработками. Фактически данный алгоритм является улучшением алгоритма сортировки прямого обмена (см. ниже).&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
Алгоритм состоит из трех основных шагов:&lt;br /&gt;
&lt;br /&gt;
1. Выбрать опорный элемент (см. ниже). Пусть это будет элемент &amp;lt;math&amp;gt; a&#039; &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
2. Используя операции сравнения элементов массива с опорным и перестановки элементов массива, привести исходный массив к виду: &amp;lt;math&amp;gt; a_1 ... a_m a&#039; a_{m+2} ... a_n &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt; a_j &amp;lt; a&#039;, j = 1 ... m &amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt; a_i \geq a&#039;, i = (m+1) ... n  &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; — длина массива.&lt;br /&gt;
&lt;br /&gt;
3. Рекурсивно применить алгоритм к каждому из массивов: &amp;lt;math&amp;gt; a_1 ... a_m &amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt; a_{m+1} ... a_n &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Рассмотрим подробнее метод сравнения и перестановки данных в массиве, применяющийся на шаге 2. Для этого часто используют так называемое разбиение Хоара &amp;lt;ref&amp;gt; https://en.wikipedia.org/wiki/Quicksort — From Wikipedia, the free encyclopedia &amp;lt;/ref&amp;gt;. Суть данного метода заключается в следующем: выбираются два указателя, указывающие на первый и последний элементы массива соответственно, пость для наглядности это будут &amp;lt;math&amp;gt; i = 1 &amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt; j = n &amp;lt;/math&amp;gt;. Далее начинаем сдвигать левый указатель вправо, в правый — влево до тех пор, пока выполнены условия: &amp;lt;math&amp;gt; a_i &amp;lt; a&#039;, a_j \geq a&#039;, i &amp;lt; j &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt; a&#039; &amp;lt;/math&amp;gt; — опорный элемент. Как только найдутся такие &amp;lt;math&amp;gt; i, j &amp;lt;/math&amp;gt;, что &amp;lt;math&amp;gt; a_i \geq a&#039;, a_j &amp;lt; a&#039; &amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt; i &amp;lt; j &amp;lt;/math&amp;gt;, производим перестановку этих двух элементов. Продолжаем этот процесс до тех пор, пока выполнено &amp;lt;math&amp;gt; i &amp;lt; j &amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
Вычислительным ядром данного алгоритма являются операции сравнения и перестановки &amp;lt;math&amp;gt; i&amp;lt;/math&amp;gt;-ого и &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;-ого элементов массива на каждой итерации рекурсивного алгоритма.&lt;br /&gt;
&lt;br /&gt;
Сложность операции разделения массива на два подмассива (сравнение и перестановка элементов массива относительно опорного элемента) занимет время &amp;lt;math&amp;gt; O (log_2 n) &amp;lt;/math&amp;gt; &amp;lt;ref&amp;gt; https://ru.wikipedia.org/wiki/Быстрая_сортировка &amp;lt;/ref&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
Как и написано выше в разделе &amp;quot;Вычислительное ядро алгоритма&amp;quot;, основную часть данного метода сортировки составляет операция разделения массива относительно опорного элемента, которая в свою очередь состоит из операций сравнения и перестановки.&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма ===&lt;br /&gt;
1. Случайным образом выбрать опорный элемент массива.&lt;br /&gt;
&lt;br /&gt;
2. Сравнить все элементы сортируемого массива с опорным и разделить исходный массив на два подмассива: с элементами меньше опорного и с элементами большие (или равные) опорного. &lt;br /&gt;
&lt;br /&gt;
3. Рекурсивно повторить алгоритм для получившихся подмассивов.&lt;br /&gt;
&lt;br /&gt;
Случайный выбор опорного элемента считается наиболее эффективным, так как при фиксировании позиции опорного элемента (например, в качестве опорного всегда берется элемент, стоящий на первой позиции) может привести к существенному снижению эффективности для массивов определенного вида из-за неравномерного распределения элементов в получившихся подмассивах. Также в качестве опорного элемента можно выбирать медиану массива, но считается, что вычисление медианы на каждой итерации рекурсивного алгоритма — слишком затратная операция.&lt;br /&gt;
&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;math&amp;gt;p = 2^n&amp;lt;/math&amp;gt;. Для этого алгоритм необходимо лишь дополнить методом выбора процессоров, между которыми будут происходить обмены данными на i-ом шаге. Распределим произвольным образом данные между процессорами, далее выбираем некоторым образом ведущий элемент и рассылаем его всем процессорам системы. Т.к. топология системы имеет вид n-мерного куба, номер каждого процессора имеет двоичное представление длины &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, следовательно, можно ввести правило: на каждом процессоре происходит сравнение имеющегося блока данных с текущим ведущим элементом, после чего элементы меньше ведущего отправляются от процессора с номером &amp;lt;math&amp;gt;n_1&amp;lt;/math&amp;gt; процессору номер &amp;lt;math&amp;gt;n_2&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;n_1&amp;lt;/math&amp;gt; отличается от &amp;lt;math&amp;gt;n_2&amp;lt;/math&amp;gt; только в n-том разряде двоичного представления, в двоичном представлении числа &amp;lt;math&amp;gt;n_1&amp;lt;/math&amp;gt; на n-той позиции стоит 1, а &amp;lt;math&amp;gt;n_2&amp;lt;/math&amp;gt; — 0. Таким образом, после данной операции все данные будут разделены между процессорами, образующими n-1-мерные кубы таким образом, что элемент блока данных любого процессора из первого куба больше любого элемента блока данных процессора из второго куба. Повторив аналогичные действия для каждого из n-1-мерных кубов, получим 4 n-2-мерных куба и т.д. Последним этапом работы алгоритма является объединение разрозненных блоков отсортированных данных в единый массив в правильном порядке. Порядок объединения не трудно восстановить исходя из двоичных представлений номеров процессоров.&lt;br /&gt;
&lt;br /&gt;
Очевидно, что наиболее медленной операцией в описанной выше схеме является операция обмена данными между процессорами, следовательно, хотелось бы получить некоторую оценку количества обменов. Такая оценка приведена ниже:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\sum_{i=1}^{n} i = n(n+1)/2 ≈ \log^2 p &amp;lt;/math&amp;gt; &amp;lt;ref&amp;gt; http://ssd.sscc.ru/ru — Supercomputer Software Department &amp;lt;/ref&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt; p &amp;lt;/math&amp;gt; — количество задействованных процессоров.&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные алгоритма ===&lt;br /&gt;
&#039;&#039;&#039;Входные данные:&#039;&#039;&#039; любая числовая последовательность произвольной конечной длины. Так как параллельный алгоритм предполагает выбор разделяющего элемента случайным образом, построение последовательностей специального вида не приводит к увеличению вероятности неравномерного распределения данных между вычислительными узлами. Это значит, что эффективность алгоритма не зависит от вида входной последовательности. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные:&#039;&#039;&#039; последовательность чисел в отсортированном виде.&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;br /&gt;
&amp;lt;references /&amp;gt;&lt;/div&gt;</summary>
		<author><name>Ashabokov 415</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Ashabokov_415/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%B1%D1%8B%D1%81%D1%82%D1%80%D0%BE%D0%B9_%D1%81%D0%BE%D1%80%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B8&amp;diff=27615</id>
		<title>Участник:Ashabokov 415/Алгоритм быстрой сортировки</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Ashabokov_415/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%B1%D1%8B%D1%81%D1%82%D1%80%D0%BE%D0%B9_%D1%81%D0%BE%D1%80%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B8&amp;diff=27615"/>
		<updated>2019-11-30T01:15:50Z</updated>

		<summary type="html">&lt;p&gt;Ashabokov 415: /* Свойства и структура алгоритмов */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&#039;&#039;&#039;Алгоритм быстрой сортировки&#039;&#039;&#039; &lt;br /&gt;
&lt;br /&gt;
== Свойства и структура алгоритмов ==&lt;br /&gt;
&lt;br /&gt;
=== Общее описание алгоритма &amp;lt;ref&amp;gt; https://en.wikipedia.org/wiki/Quicksort — From Wikipedia, the free encyclopedia &amp;lt;/ref&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
Быстрая сортировка, сортировка Хоара —  широко известный алгоритм сортировки, разработанный английским информатиком Чарльзом Хоаром во время его работы в МГУ в 1960 году.&lt;br /&gt;
&lt;br /&gt;
Один из самых быстрых известных универсальных алгоритмов сортировки массивов: в среднем  &amp;lt;math&amp;gt; O (n \log n) &amp;lt;/math&amp;gt; обменов при упорядочении &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; элементов; из-за наличия ряда недостатков на практике обычно используется с некоторыми доработками. Фактически данный алгоритм является улучшением алгоритма сортировки прямого обмена (см. ниже).&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
Алгоритм состоит из трех основных шагов:&lt;br /&gt;
&lt;br /&gt;
1. Выбрать опорный элемент (см. ниже). Пусть это будет элемент &amp;lt;math&amp;gt; a&#039; &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
2. Используя операции сравнения элементов массива с опорным и перестановки элементов массива, привести исходный массив к виду: &amp;lt;math&amp;gt; a_1 ... a_m a&#039; a_{m+2} ... a_n &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt; a_j &amp;lt; a&#039;, j = 1 ... m &amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt; a_i \geq a&#039;, i = (m+1) ... n  &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; — длина массива.&lt;br /&gt;
&lt;br /&gt;
3. Рекурсивно применить алгоритм к каждому из массивов: &amp;lt;math&amp;gt; a_1 ... a_m &amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt; a_{m+1} ... a_n &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Рассмотрим подробнее метод сравнения и перестановки данных в массиве, применяющийся на шаге 2. Для этого часто используют так называемое разбиение Хоара &amp;lt;ref&amp;gt; https://en.wikipedia.org/wiki/Quicksort — From Wikipedia, the free encyclopedia &amp;lt;/ref&amp;gt;. Суть данного метода заключается в следующем: выбираются два указателя, указывающие на первый и последний элементы массива соответственно, пость для наглядности это будут &amp;lt;math&amp;gt; i = 1 &amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt; j = n &amp;lt;/math&amp;gt;. Далее начинаем сдвигать левый указатель вправо, в правый — влево до тех пор, пока выполнены условия: &amp;lt;math&amp;gt; a_i &amp;lt; a&#039;, a_j \geq a&#039;, i &amp;lt; j &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt; a&#039; &amp;lt;/math&amp;gt; — опорный элемент. Как только найдутся такие &amp;lt;math&amp;gt; i, j &amp;lt;/math&amp;gt;, что &amp;lt;math&amp;gt; a_i \geq a&#039;, a_j &amp;lt; a&#039; &amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt; i &amp;lt; j &amp;lt;/math&amp;gt;, производим перестановку этих двух элементов. Продолжаем этот процесс до тех пор, пока выполнено &amp;lt;math&amp;gt; i &amp;lt; j &amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
Вычислительным ядром данного алгоритма являются операции сравнения и перестановки &amp;lt;math&amp;gt; i&amp;lt;/math&amp;gt;-ого и &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;-ого элементов массива на каждой итерации рекурсивного алгоритма.&lt;br /&gt;
&lt;br /&gt;
Сложность операции разделения массива на два подмассива (сравнение и перестановка элементов массива относительно опорного элемента) занимет время &amp;lt;math&amp;gt; O (log_2 n) &amp;lt;/math&amp;gt; &amp;lt;ref&amp;gt; https://ru.wikipedia.org/wiki/Быстрая_сортировка &amp;lt;/ref&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма ===&lt;br /&gt;
1. Случайным образом выбрать опорный элемент массива.&lt;br /&gt;
&lt;br /&gt;
2. Сравнить все элементы сортируемого массива с опорным и разделить исходный массив на два подмассива: с элементами меньше опорного и с элементами большие (или равные) опорного. &lt;br /&gt;
&lt;br /&gt;
3. Рекурсивно повторить алгоритм для получившихся подмассивов.&lt;br /&gt;
&lt;br /&gt;
Случайный выбор опорного элемента считается наиболее эффективным, так как при фиксировании позиции опорного элемента (например, в качестве опорного всегда берется элемент, стоящий на первой позиции) может привести к существенному снижению эффективности для массивов определенного вида из-за неравномерного распределения элементов в получившихся подмассивах. Также в качестве опорного элемента можно выбирать медиану массива, но считается, что вычисление медианы на каждой итерации рекурсивного алгоритма — слишком затратная операция.&lt;br /&gt;
&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;math&amp;gt;p = 2^n&amp;lt;/math&amp;gt;. Для этого алгоритм необходимо лишь дополнить методом выбора процессоров, между которыми будут происходить обмены данными на i-ом шаге. Распределим произвольным образом данные между процессорами, далее выбираем некоторым образом ведущий элемент и рассылаем его всем процессорам системы. Т.к. топология системы имеет вид n-мерного куба, номер каждого процессора имеет двоичное представление длины &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, следовательно, можно ввести правило: на каждом процессоре происходит сравнение имеющегося блока данных с текущим ведущим элементом, после чего элементы меньше ведущего отправляются от процессора с номером &amp;lt;math&amp;gt;n_1&amp;lt;/math&amp;gt; процессору номер &amp;lt;math&amp;gt;n_2&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;n_1&amp;lt;/math&amp;gt; отличается от &amp;lt;math&amp;gt;n_2&amp;lt;/math&amp;gt; только в n-том разряде двоичного представления, в двоичном представлении числа &amp;lt;math&amp;gt;n_1&amp;lt;/math&amp;gt; на n-той позиции стоит 1, а &amp;lt;math&amp;gt;n_2&amp;lt;/math&amp;gt; — 0. Таким образом, после данной операции все данные будут разделены между процессорами, образующими n-1-мерные кубы таким образом, что элемент блока данных любого процессора из первого куба больше любого элемента блока данных процессора из второго куба. Повторив аналогичные действия для каждого из n-1-мерных кубов, получим 4 n-2-мерных куба и т.д. Последним этапом работы алгоритма является объединение разрозненных блоков отсортированных данных в единый массив в правильном порядке. Порядок объединения не трудно восстановить исходя из двоичных представлений номеров процессоров.&lt;br /&gt;
&lt;br /&gt;
Очевидно, что наиболее медленной операцией в описанной выше схеме является операция обмена данными между процессорами, следовательно, хотелось бы получить некоторую оценку количества обменов. Такая оценка приведена ниже:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\sum_{i=1}^{n} i = n(n+1)/2 ≈ \log^2 p &amp;lt;/math&amp;gt; &amp;lt;ref&amp;gt; http://ssd.sscc.ru/ru — Supercomputer Software Department &amp;lt;/ref&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt; p &amp;lt;/math&amp;gt; — количество задействованных процессоров.&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные алгоритма ===&lt;br /&gt;
&#039;&#039;&#039;Входные данные:&#039;&#039;&#039; любая числовая последовательность произвольной конечной длины. Так как параллельный алгоритм предполагает выбор разделяющего элемента случайным образом, построение последовательностей специального вида не приводит к увеличению вероятности неравномерного распределения данных между вычислительными узлами. Это значит, что эффективность алгоритма не зависит от вида входной последовательности. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные:&#039;&#039;&#039; последовательность чисел в отсортированном виде.&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;br /&gt;
&amp;lt;references /&amp;gt;&lt;/div&gt;</summary>
		<author><name>Ashabokov 415</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Ashabokov_415/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%B1%D1%8B%D1%81%D1%82%D1%80%D0%BE%D0%B9_%D1%81%D0%BE%D1%80%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B8&amp;diff=27614</id>
		<title>Участник:Ashabokov 415/Алгоритм быстрой сортировки</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Ashabokov_415/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%B1%D1%8B%D1%81%D1%82%D1%80%D0%BE%D0%B9_%D1%81%D0%BE%D1%80%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B8&amp;diff=27614"/>
		<updated>2019-11-29T23:53:25Z</updated>

		<summary type="html">&lt;p&gt;Ashabokov 415: /* Свойства и структура алгоритмов */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&#039;&#039;&#039;Алгоритм быстрой сортировки&#039;&#039;&#039; &lt;br /&gt;
&lt;br /&gt;
== Свойства и структура алгоритмов ==&lt;br /&gt;
&lt;br /&gt;
=== Общее описание алгоритма &amp;lt;ref&amp;gt; https://en.wikipedia.org/wiki/Quicksort — From Wikipedia, the free encyclopedia &amp;lt;/ref&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма алгоритма ===&lt;br /&gt;
Основной идеей данного алгоритма является разбиение всего массива данных на блоки меньшего размера таким образом, что между соответствующими блоками после разбиения можно установить отношение упорядоченности. Сортировка производится следующим образом: выбирается некоторым образом ведущий элемент, после чего происходит разделение исходного массива данных на два блока относительно ведущего элемента: в первый блок помещаются элементы, меньшие ведущего, а во второй — большие ведущего. Таким образом, можно утверждать, что наибольший элемент первого блока меньше наименьшего элемента второго блока. Это означает, что повторив эту операцию для каждого из блоков отдельно некоторое количество раз и объединив результаты, получим массив с исходными данными в отсортированном виде. Из описания становится очевидно, что данный алгоритм можно легко обобщить для параллельной вычислительной системы с количеством процессоров &amp;lt;math&amp;gt;p = 2^n&amp;lt;/math&amp;gt;. Для этого алгоритм необходимо лишь дополнить методом выбора процессоров, между которыми будут происходить обмены данными на i-ом шаге. Распределим произвольным образом данные между процессорами, далее выбираем некоторым образом ведущий элемент и рассылаем его всем процессорам системы. Т.к. топология системы имеет вид n-мерного куба, номер каждого процессора имеет двоичное представление длины &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, следовательно, можно ввести правило: на каждом процессоре происходит сравнение имеющегося блока данных с текущим ведущим элементом, после чего элементы меньше ведущего отправляются от процессора с номером &amp;lt;math&amp;gt;n_1&amp;lt;/math&amp;gt; процессору номер &amp;lt;math&amp;gt;n_2&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;n_1&amp;lt;/math&amp;gt; отличается от &amp;lt;math&amp;gt;n_2&amp;lt;/math&amp;gt; только в n-том разряде двоичного представления, в двоичном представлении числа &amp;lt;math&amp;gt;n_1&amp;lt;/math&amp;gt; на n-той позиции стоит 1, а &amp;lt;math&amp;gt;n_2&amp;lt;/math&amp;gt; — 0. Таким образом, после данной операции все данные будут разделены между процессорами, образующими n-1-мерные кубы таким образом, что элемент блока данных любого процессора из первого куба больше любого элемента блока данных процессора из второго куба. Повторив аналогичные действия для каждого из n-1-мерных кубов, получим 4 n-2-мерных куба и т.д. Последним этапом работы алгоритма является объединение разрозненных блоков отсортированных данных в единый массив в правильном порядке. Порядок объединения не трудно восстановить исходя из двоичных представлений номеров процессоров.&lt;br /&gt;
&lt;br /&gt;
Очевидно, что наиболее медленной операцией в описанной выше схеме является операция обмена данными между процессорами, следовательно, хотелось бы получить некоторую оценку количества обменов. Такая оценка приведена ниже:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\sum_{i=1}^{n} i = n(n+1)/2 ≈ \log^2 p &amp;lt;/math&amp;gt; &amp;lt;ref&amp;gt; http://ssd.sscc.ru/ru — Supercomputer Software Department &amp;lt;/ref&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt; p &amp;lt;/math&amp;gt; — количество задействованных процессоров.&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные алгоритма ===&lt;br /&gt;
&#039;&#039;&#039;Входные данные:&#039;&#039;&#039; любая числовая последовательность произвольной конечной длины. Так как параллельный алгоритм предполагает поиск разделяющего элемента случайным образом, построение последовательностей специальных видов не приводит к увеличению вероятности неравномерного распределения данных между вычислительными узлами.&lt;br /&gt;
&#039;&#039;&#039;Выходные данные:&#039;&#039;&#039; последовательность чисел в отсортированном виде.&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;br /&gt;
&amp;lt;references /&amp;gt;&lt;/div&gt;</summary>
		<author><name>Ashabokov 415</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Ashabokov_415/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%B1%D1%8B%D1%81%D1%82%D1%80%D0%BE%D0%B9_%D1%81%D0%BE%D1%80%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B8&amp;diff=27471</id>
		<title>Участник:Ashabokov 415/Алгоритм быстрой сортировки</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Ashabokov_415/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%B1%D1%8B%D1%81%D1%82%D1%80%D0%BE%D0%B9_%D1%81%D0%BE%D1%80%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B8&amp;diff=27471"/>
		<updated>2019-10-20T23:26:42Z</updated>

		<summary type="html">&lt;p&gt;Ashabokov 415: /* Общее описание алгоритма  https://en.wikipedia.org/wiki/Quicksort — From Wikipedia, the free encyclopedia  */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&#039;&#039;&#039;Алгоритм быстрой сортировки&#039;&#039;&#039; &lt;br /&gt;
&lt;br /&gt;
== Свойства и структура алгоритмов ==&lt;br /&gt;
&lt;br /&gt;
=== Общее описание алгоритма &amp;lt;ref&amp;gt; https://en.wikipedia.org/wiki/Quicksort — From Wikipedia, the free encyclopedia &amp;lt;/ref&amp;gt; ===&lt;br /&gt;
Основной идеей данного алгоритма является разбиение всего массива данных на блоки меньшего размера таким образом, что между соответствующими блоками после разбиения можно установить отношение упорядоченности. Сортировка производится следующим образом: выбирается некоторым образом ведущий элемент, после чего происходит разделение исходного массива данных на два блока относительно ведущего элемента: в первый блок помещаются элементы, меньшие ведущего, а во второй — большие ведущего. Таким образом, можно утверждать, что наибольший элемент первого блока меньше наименьшего элемента второго блока. Это означает, что повторив эту операцию для каждого из блоков отдельно некоторое количество раз и объединив результаты, получим массив с исходными данными в отсортированном виде. Из описания становится очевидно, что данный алгоритм можно легко обобщить для параллельной вычислительной системы с количеством процессоров &amp;lt;math&amp;gt;p = 2^n&amp;lt;/math&amp;gt;. Для этого алгоритм необходимо лишь дополнить методом выбора процессоров, между которыми будут происходить обмены данными на i-ом шаге. Распределим произвольным образом данные между процессорами, далее выбираем некоторым образом ведущий элемент и рассылаем его всем процессорам системы. Т.к. топология системы имеет вид n-мерного куба, номер каждого процессора имеет двоичное представление длины &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, следовательно, можно ввести правило: на каждом процессоре происходит сравнение имеющегося блока данных с текущим ведущим элементом, после чего элементы меньше ведущего отправляются от процессора с номером &amp;lt;math&amp;gt;n_1&amp;lt;/math&amp;gt; процессору номер &amp;lt;math&amp;gt;n_2&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;n_1&amp;lt;/math&amp;gt; отличается от &amp;lt;math&amp;gt;n_2&amp;lt;/math&amp;gt; только в n-том разряде двоичного представления, в двоичном представлении числа &amp;lt;math&amp;gt;n_1&amp;lt;/math&amp;gt; на n-той позиции стоит 1, а &amp;lt;math&amp;gt;n_2&amp;lt;/math&amp;gt; — 0. Таким образом, после данной операции все данные будут разделены между процессорами, образующими n-1-мерные кубы таким образом, что элемент блока данных любого процессора из первого куба больше любого элемента блока данных процессора из второго куба. Повторив аналогичные действия для каждого из n-1-мерных кубов, получим 4 n-2-мерных куба и т.д. Последним этапом работы алгоритма является объединение разрозненных блоков отсортированных данных в единый массив в правильном порядке. Порядок объединения не трудно восстановить исходя из двоичных представлений номеров процессоров.&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Очевидно, что наиболее медленной операцией в описанной выше схеме является операция обмена данными между процессорами, следовательно, хотелось бы получить некоторую оценку количества обменов. Такая оценка приведена ниже:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\sum_{i=1}^{n} i = n(n+1)/2 ≈ \log^2 p &amp;lt;/math&amp;gt; &amp;lt;ref&amp;gt; http://ssd.sscc.ru/ru — Supercomputer Software Department &amp;lt;/ref&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt; p &amp;lt;/math&amp;gt; — количество задействованных процессоров.&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;br /&gt;
&amp;lt;references /&amp;gt;&lt;/div&gt;</summary>
		<author><name>Ashabokov 415</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Ashabokov_415/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%B1%D1%8B%D1%81%D1%82%D1%80%D0%BE%D0%B9_%D1%81%D0%BE%D1%80%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B8&amp;diff=27470</id>
		<title>Участник:Ashabokov 415/Алгоритм быстрой сортировки</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Ashabokov_415/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%B1%D1%8B%D1%81%D1%82%D1%80%D0%BE%D0%B9_%D1%81%D0%BE%D1%80%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B8&amp;diff=27470"/>
		<updated>2019-10-20T23:26:07Z</updated>

		<summary type="html">&lt;p&gt;Ashabokov 415: Новая страница: «&amp;#039;&amp;#039;&amp;#039;Алгоритм быстрой сортировки&amp;#039;&amp;#039;&amp;#039;   == Свойства и структура алгоритмов ==  === Общее описание а…»&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&#039;&#039;&#039;Алгоритм быстрой сортировки&#039;&#039;&#039; &lt;br /&gt;
&lt;br /&gt;
== Свойства и структура алгоритмов ==&lt;br /&gt;
&lt;br /&gt;
=== Общее описание алгоритма &amp;lt;ref&amp;gt; https://en.wikipedia.org/wiki/Quicksort — From Wikipedia, the free encyclopedia &amp;lt;/ref&amp;gt; ===&lt;br /&gt;
Основной идеей данного алгоритма является разбиение всего массива данных на блоки меньшего размера таким образом, что между соответствующими блоками после разбиения можно установить отношение упорядоченности. Сортировка производится следующим образом: выбирается некоторым образом ведущий элемент, после чего происходит разделение исходного массива данных на два блока относительно ведущего элемента: в первый блок помещаются элементы, меньшие ведущего, а во второй --- большие ведущего. Таким образом, можно утверждать, что наибольший элемент первого блока меньше наименьшего элемента второго блока. Это означает, что повторив эту операцию для каждого из блоков отдельно некоторое количество раз и объединив результаты, получим массив с исходными данными в отсортированном виде. Из описания становится очевидно, что данный алгоритм можно легко обобщить для параллельной вычислительной системы с количеством процессоров &amp;lt;math&amp;gt;p = 2^n&amp;lt;/math&amp;gt;. Для этого алгоритм необходимо лишь дополнить методом выбора процессоров, между которыми будут происходить обмены данными на i-ом шаге. Распределим произвольным образом данные между процессорами, далее выбираем некоторым образом ведущий элемент и рассылаем его всем процессорам системы. Т.к. топология системы имеет вид n-мерного куба, номер каждого процессора имеет двоичное представление длины &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, следовательно, можно ввести правило: на каждом процессоре происходит сравнение имеющегося блока данных с текущим ведущим элементом, после чего элементы меньше ведущего отправляются от процессора с номером &amp;lt;math&amp;gt;n_1&amp;lt;/math&amp;gt; процессору номер &amp;lt;math&amp;gt;n_2&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;n_1&amp;lt;/math&amp;gt; отличается от &amp;lt;math&amp;gt;n_2&amp;lt;/math&amp;gt; только в n-том разряде двоичного представления, в двоичном представлении числа &amp;lt;math&amp;gt;n_1&amp;lt;/math&amp;gt; на n-той позиции стоит 1, а &amp;lt;math&amp;gt;n_2&amp;lt;/math&amp;gt; — 0. Таким образом, после данной операции все данные будут разделены между процессорами, образующими n-1-мерные кубы таким образом, что элемент блока данных любого процессора из первого куба больше любого элемента блока данных процессора из второго куба. Повторив аналогичные действия для каждого из n-1-мерных кубов, получим 4 n-2-мерных куба и т.д. Последним этапом работы алгоритма является объединение разрозненных блоков отсортированных данных в единый массив в правильном порядке. Порядок объединения не трудно восстановить исходя из двоичных представлений номеров процессоров.&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Очевидно, что наиболее медленной операцией в описанной выше схеме является операция обмена данными между процессорами, следовательно, хотелось бы получить некоторую оценку количества обменов. Такая оценка приведена ниже:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\sum_{i=1}^{n} i = n(n+1)/2 ≈ \log^2 p &amp;lt;/math&amp;gt; &amp;lt;ref&amp;gt; http://ssd.sscc.ru/ru — Supercomputer Software Department &amp;lt;/ref&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;math&amp;gt; p &amp;lt;/math&amp;gt; — количество задействованных процессоров.&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;br /&gt;
&amp;lt;references /&amp;gt;&lt;/div&gt;</summary>
		<author><name>Ashabokov 415</name></author>
	</entry>
</feed>