Википедия

Сортировка слиянием

Сортировка слиянием (англ. merge sort) — алгоритм сортировки, который упорядочивает списки (или другие структуры данных, доступ к элементам которых можно получать только последовательно, например — потоки) в определённом порядке. Эта сортировка — хороший пример использования принципа «разделяй и властвуй». Сначала задача разбивается на несколько подзадач меньшего размера. Затем эти задачи решаются с помощью рекурсивного вызова или непосредственно, если их размер достаточно мал. Наконец, их решения комбинируются, и получается решение исходной задачи.

Сортировка слиянием
image
Пример сортировки слиянием. Сначала делим список на кусочки (по 1 элементу), затем сравниваем каждый элемент с соседним, сортируем и объединяем. В итоге, все элементы отсортированы и объединены вместе.
Автор Джон фон Нейман
Предназначение Алгоритм сортировки
Структура данных список, массив
Худшее время
Лучшее время
Среднее время
Затраты памяти для списка, для массива
image Медиафайлы на Викискладе

Алгоритм был изобретён Джоном фон Нейманом в 1945 году.

Подробный алгоритм сортировки

image
Действие алгоритма на примере сортировки случайных точек.

Для решения задачи сортировки эти три этапа выглядят так:

  1. Сортируемый массив разбивается на две части примерно одинакового размера;
  2. Каждая из получившихся частей сортируется отдельно, например — тем же самым алгоритмом;
  3. Два упорядоченных массива половинного размера соединяются в один.

1.1. — 2.1. Рекурсивное разбиение задачи на меньшие происходит до тех пор, пока размер массива не достигнет единицы (любой массив длины 1 можно считать упорядоченным).

3.1. Соединение двух упорядоченных массивов в один.
Основную идею слияния двух отсортированных массивов можно объяснить на следующем примере. Пусть мы имеем два уже отсортированных по возрастанию подмассива. Тогда:
3.2. Слияние двух подмассивов в третий результирующий массив.
На каждом шаге мы берём меньший из двух первых элементов подмассивов и записываем его в результирующий массив. Счётчики номеров элементов результирующего массива и подмассива, из которого был взят элемент, увеличиваем на 1.
3.3. «Прицепление» остатка.
Когда один из подмассивов закончился, мы добавляем все оставшиеся элементы второго подмассива в результирующий массив.

Реализация на языках программирования

Пример сортировки на языке Си

 /**  * Сортирует массив, используя рекурсивную сортировку слиянием  * up - указатель на массив, который нужно сортировать  * down - указатель на массив с, как минимум, таким же размером как у 'up', используется как буфер  * left - левая граница массива, передайте 0, чтобы сортировать массив с начала  * right - правая граница массива, передайте длину массива - 1, чтобы сортировать массив до последнего элемента  * возвращает: указатель на отсортированный массив. Из-за особенностей работы данной реализации  * отсортированная версия массива может оказаться либо в 'up', либо в 'down'  **/ int* merge_sort(int *up, int *down, unsigned int left, unsigned int right) {  if (left == right)  {  down[left] = up[left];  return down;  }  unsigned int middle = left + (right - left) / 2;  // разделяй и сортируй  int *l_buff = merge_sort(up, down, left, middle);  int *r_buff = merge_sort(up, down, middle + 1, right);  // слияние двух отсортированных половин  int *target = l_buff == up ? down : up;  unsigned int l_cur = left, r_cur = middle + 1;  for (unsigned int i = left; i <= right; i++)  {  if (l_cur <= middle && r_cur <= right)  {  if (l_buff[l_cur] < r_buff[r_cur])  {  target[i] = l_buff[l_cur];  l_cur++;  }  else  {  target[i] = r_buff[r_cur];  r_cur++;  }  }  else if (l_cur <= middle)  {  target[i] = l_buff[l_cur];  l_cur++;  }  else  {  target[i] = r_buff[r_cur];  r_cur++;  }  }  return target; } 

Реализация на языке C++11

#include <algorithm> #include <cstddef> #include <iterator> #include <memory> template<typename T> void merge_sort(T array[], std::size_t size) noexcept {  if (size > 1)  {  std::size_t const left_size = size / 2;  std::size_t const right_size = size - left_size;  merge_sort(&array[0], left_size);  merge_sort(&array[left_size], right_size);  std::size_t lidx = 0, ridx = left_size, idx = 0;  std::unique_ptr<T[]> tmp_array(new T[size]);  while (lidx < left_size || ridx < size)  {  if (array[lidx] < array[ridx])  {  tmp_array[idx++] = std::move(array[lidx]);  lidx++;  }  else  {  tmp_array[idx++] = std::move(array[ridx]);  ridx++;  }  if (lidx == left_size)  {  std::copy(std::make_move_iterator(&array[ridx]),  std::make_move_iterator(&array[size]),  &tmp_array[idx]);  break;  }  if (ridx == size)  {  std::copy(std::make_move_iterator(&array[lidx]),  std::make_move_iterator(&array[left_size]),  &tmp_array[idx]);  break;  }  }  std::copy(std::make_move_iterator(tmp_array.get()),  std::make_move_iterator(&tmp_array[size]),  array);  } } 

Реализация на языке C++14 с распараллеливанием от OpenMP

#include <algorithm> #include <iterator> #include <omp.h> #include <memory>  template <typename Iterator> void mergesort(Iterator from, Iterator to) { #pragma omp parallel  { #pragma omp single nowait  static_assert(!std::is_same<typename std::iterator_traits<Iterator>::value_type, void>::value);   auto n = std::distance(from, to);   if (1 < n)  { #pragma omp task firstprivate (from, to, n)  {  Iterator l_from = from;  Iterator l_to = l_from;  std::advance(l_to, n/2);  mergesort(l_from, l_to);  } #pragma omp task firstprivate (from, to, n)  {  Iterator r_from = from;  std::advance(r_from, n/2);  Iterator r_to = r_from;  std::advance(r_to, n-(n/2));  mergesort(r_from, r_to);  } #pragma omp taskwait   auto tmp_array = std::make_unique<typename Iterator::value_type[]>(n);  Iterator l_iter = from;  Iterator l_end = l_iter;  std::advance(l_end, n/2);  Iterator r_iter = l_end;  Iterator& r_end = to;   auto tmp_iter = tmp_array.get();   while (l_iter != l_end || r_iter != r_end)  {  if (*l_iter < *r_iter)  {  *tmp_iter = std::move(*l_iter);  ++l_iter;  ++tmp_iter;  }  else  {  *tmp_iter = std::move(*r_iter);  ++r_iter;  ++tmp_iter;  }   if (l_iter == l_end)  {  std::copy(  std::make_move_iterator(r_iter),  std::make_move_iterator(r_end),  tmp_iter  );   break;  }   if (r_iter == r_end)  {  std::copy(  std::make_move_iterator(l_iter),  std::make_move_iterator(l_end),  tmp_iter  );   break;  }  }   std::copy(  std::make_move_iterator(tmp_array.get()),  std::make_move_iterator(&tmp_array[n]),  from  );  }  } } 

Итеративная реализация на языке C++

template<typename T> void MergeSort(T a[], size_t l) { size_t BlockSizeIterator; size_t BlockIterator; size_t LeftBlockIterator; size_t RightBlockIterator; size_t MergeIterator; size_t LeftBorder; size_t MidBorder; size_t RightBorder; for (BlockSizeIterator = 1; BlockSizeIterator < l; BlockSizeIterator *= 2) { for (BlockIterator = 0; BlockIterator < l - BlockSizeIterator; BlockIterator += 2 * BlockSizeIterator) { //Производим слияние с сортировкой пары блоков начинающуюся с элемента BlockIterator //левый размером BlockSizeIterator, правый размером BlockSizeIterator или меньше LeftBlockIterator = 0; RightBlockIterator = 0; LeftBorder = BlockIterator; MidBorder = BlockIterator + BlockSizeIterator; RightBorder = BlockIterator + 2 * BlockSizeIterator; RightBorder = (RightBorder < l) ? RightBorder : l; int* SortedBlock = new int[RightBorder - LeftBorder]; //Пока в обоих массивах есть элементы выбираем меньший из них и заносим в отсортированный блок while (LeftBorder + LeftBlockIterator < MidBorder && MidBorder + RightBlockIterator < RightBorder) { if (a[LeftBorder + LeftBlockIterator] < a[MidBorder + RightBlockIterator]) { SortedBlock[LeftBlockIterator + RightBlockIterator] = a[LeftBorder + LeftBlockIterator]; LeftBlockIterator += 1; } else { SortedBlock[LeftBlockIterator + RightBlockIterator] = a[MidBorder + RightBlockIterator]; RightBlockIterator += 1; } } //После этого заносим оставшиеся элементы из левого или правого блока while (LeftBorder + LeftBlockIterator < MidBorder) { SortedBlock[LeftBlockIterator + RightBlockIterator] = a[LeftBorder + LeftBlockIterator]; LeftBlockIterator += 1; } while (MidBorder + RightBlockIterator < RightBorder) { SortedBlock[LeftBlockIterator + RightBlockIterator] = a[MidBorder + RightBlockIterator]; RightBlockIterator += 1; } for (MergeIterator = 0; MergeIterator < LeftBlockIterator + RightBlockIterator; MergeIterator++) { a[LeftBorder + MergeIterator] = SortedBlock[MergeIterator]; } delete[] SortedBlock; if b* } } } 

Реализация на языке Python

def merge_sort(arr):  if len(arr) <= 1:  return arr   mid = len(arr) // 2  left_half = arr[:mid]  right_half = arr[mid:]   left_half = merge_sort(left_half)  right_half = merge_sort(right_half)   return merge(left_half, right_half)  def merge(left, right):  merged = []  while left and right:  if left[0] < right[0]:  merged.append(left.pop(0))  else:  merged.append(right.pop(0))  merged.extend(left or right)  return merged 

Псевдокод

Псевдокод алгоритма слияния без «прицепления» остатка на Си-подобном языке:

L = *In1; R = *In2; if( L == R ) { *Out++ = L; In1++; *Out++ = R; In2++; } else if(L < R) { *Out++ = L; In1++; } else { *Out++ = R; In2++; } 

В приведённом алгоритме на Си-подобном языке используется проверка на равенство двух сравниваемых элементов подмассивов с отдельным блоком обработки в случае равенства. Отдельная проверка на равенство удваивает число сравнений, что усложняет код программы. Вместо отдельной проверки на равенство и отдельного блока обработки в случае равенства можно использовать две проверки if(L <= R) и if(L >= R), что почти вдвое уменьшает код программы.

Псевдокод улучшенного алгоритма слияния без «прицепления» остатка на Си-подобном языке:

L = *In1; R = *In2; if( L <= R ) { *Out++ = L; In1++; } if( L >= R ) { *Out++ = R; In2++; } 

Число проверок можно сократить вдвое убрав проверку if(L >= R). При этом, в случае равенства L и R, L запишется в Out в первой итерации, а R - во второй. Этот вариант будет работать эффективно, если в исходном массиве повторяющиеся элементы не будут преобладать над остальными элементами.

Псевдокод сокращенного алгоритма слияния без «прицепления» остатка на Си-подобном языке:

L = *In1; R = *In2; if( L <= R ) { *Out++ = L; In1++; } else { *Out++ = R; In2++; } 

Две операции пересылки в переменные L и R упрощают некоторые записи в программе, что может оказаться полезным в учебных целях, но в действительных программах их можно удалить, что сократит программный код. Также можно использовать тернарный оператор, что ещё больше сократит программный код.

Псевдокод ещё более улучшенного алгоритма слияния без «прицепления» остатка на Си-подобном языке:

*Out++ = *In1 <= *In2  ? In1++ : In2++; 

Время работы алгоритма порядка O(n * log n) при отсутствии деградации на неудачных случаях, которая является больным местом быстрой сортировки (тоже алгоритм порядка O(n * log n), но только для среднего случая). Расход памяти выше, чем для быстрой сортировки, при намного более благоприятном паттерне выделения памяти — возможно выделение одного региона памяти с самого начала и отсутствие выделения при дальнейшем исполнении.

Популярная реализация требует однократно выделяемого временного буфера памяти, равного сортируемому массиву, и не имеет рекурсий. Шаги реализации:

  1. InputArray = сортируемый массив, OutputArray = временный буфер;
  2. над каждым отрезком входного массива InputArray[N * MIN_CHUNK_SIZE..(N + 1) * MIN_CHUNK_SIZE] выполняется какой-то вспомогательный алгоритм сортировки, например, сортировка Шелла или быстрая сортировка;
  3. устанавливается ChunkSize = MIN_CHUNK_SIZE;
  4. сливаются два отрезка InputArray[N * ChunkSize..(N + 1) * ChunkSize] и InputArray[(N + 1) * ChunkSize..(N + 2) * ChunkSize] попеременным шаганием слева и справа (см. выше), результат помещается в OutputArray[N * ChunkSize..(N + 2) * ChunkSize], и так для всех N, пока не будет достигнут конец массива;
  5. ChunkSize удваивается;
  6. если ChunkSize стал >= размера массива, то конец, результат в OutputArray, который (ввиду перестановок, описанных ниже) есть либо сортируемый массив, либо временный буфер, во втором случае он целиком копируется в сортируемый массив;
  7. иначе меняются местами InputArray и OutputArray перестановкой указателей, и всё повторяется с пункта 4.

Такая реализация также поддерживает размещение сортируемого массива и временного буфера в дисковых файлах, то есть пригодна для сортировки огромных объёмов данных. Реализация ORDER BY в СУБД MySQL при отсутствии подходящего индекса устроена именно так (источник: filesort.cc в исходном коде MySQL).

Пример реализации алгоритма простого двухпутевого слияния на псевдокоде:

function mergesort(m) var list left, right, result if length(m) ≤ 1 return m else middle = length(m) / 2 for each x in m up to middle add x to left for each x in m after middle add x to right left = mergesort(left) right = mergesort(right) result = merge(left, right) return result end if 

Есть несколько вариантов функции merge(), наиболее простой вариант может выглядеть так:

function merge(left,right) var list result while length(left) > 0 and length(right) > 0 if first(left) ≤ first(right) append first(left) to result left = rest(left) else append first(right) to result right = rest(right) end if while length(left) > 0 append first(left) to result left = rest(left) while length(right) > 0 append first(right) to result right = rest(right) return result 

Достоинства и недостатки

Достоинства:

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

Недостатки:

  • На «почти отсортированных» массивах работает столь же долго, как на хаотичных. Существует вариант сортировки слиянием, который работает быстрее на частично отсортированных данных, но он требует дополнительной памяти, помимо временного буфера, который используется непосредственно для сортировки.
  • Требует дополнительной памяти по размеру исходного массива.

Примечания

  1. Knuth, D.E. The Art of Computer Programming. Volume 3: Sorting and Searching (англ.). — 2nd. — Addison-Wesley, 1998. — P. 159. — ISBN 0-201-89685-0.

Литература

  • Левитин А. В. Глава 4. Метод декомпозиции: Сортировка слиянием // Алгоритмы. Введение в разработку и анализМ.: Вильямс, 2006. — С. 169—172. — 576 с. — ISBN 978-5-8459-0987-9
  • Кормен, Т., Лейзерсон, Ч., Ривест, Р., Штайн, К. Алгоритмы: построение и анализ = Introduction to Algorithms / Под ред. И. В. Красикова. — 2-е изд. — М.: Вильямс, 2005. — 1296 с. — ISBN 5-8459-0857-4.

Ссылки

  • Многофазное слияние на algolist.manual.ru
  • Сортировка слиянием — восходящая сортировка, естественная сортировка, измерение быстродействия.
  • Описание метода и листинг программ сортировки слиянием.
  • Динамическая визуализация 7 алгоритмов сортировки с открытым исходным кодом
  • Пример реализации на Java

Википедия, чтение, книга, библиотека, поиск, нажмите, истории, книги, статьи, wikipedia, учить, информация, история, скачать, скачать бесплатно, mp3, видео, mp4, 3gp, jpg, jpeg, gif, png, картинка, музыка, песня, фильм, игра, игры, мобильный, телефон, Android, iOS, apple, мобильный телефон, Samsung, iphone, xiomi, xiaomi, redmi, honor, oppo, nokia, sonya, mi, ПК, web, Сеть, компьютер, Информация о Сортировка слиянием, Что такое Сортировка слиянием? Что означает Сортировка слиянием?

Sortirovka sliyaniem angl merge sort algoritm sortirovki kotoryj uporyadochivaet spiski ili drugie struktury dannyh dostup k elementam kotoryh mozhno poluchat tolko posledovatelno naprimer potoki v opredelyonnom poryadke Eta sortirovka horoshij primer ispolzovaniya principa razdelyaj i vlastvuj Snachala zadacha razbivaetsya na neskolko podzadach menshego razmera Zatem eti zadachi reshayutsya s pomoshyu rekursivnogo vyzova ili neposredstvenno esli ih razmer dostatochno mal Nakonec ih resheniya kombiniruyutsya i poluchaetsya reshenie ishodnoj zadachi Sortirovka sliyaniemPrimer sortirovki sliyaniem Snachala delim spisok na kusochki po 1 elementu zatem sravnivaem kazhdyj element s sosednim sortiruem i obedinyaem V itoge vse elementy otsortirovany i obedineny vmeste Avtor Dzhon fon NejmanPrednaznachenie Algoritm sortirovkiStruktura dannyh spisok massivHudshee vremya O nlog n displaystyle O n log n Luchshee vremya O nlog n displaystyle O n log n Srednee vremya O nlog n displaystyle O n log n Zatraty pamyati O 1 displaystyle O 1 dlya spiska O n displaystyle O n dlya massiva Mediafajly na Vikisklade Algoritm byl izobretyon Dzhonom fon Nejmanom v 1945 godu Podrobnyj algoritm sortirovkiDejstvie algoritma na primere sortirovki sluchajnyh tochek Dlya resheniya zadachi sortirovki eti tri etapa vyglyadyat tak Sortiruemyj massiv razbivaetsya na dve chasti primerno odinakovogo razmera Kazhdaya iz poluchivshihsya chastej sortiruetsya otdelno naprimer tem zhe samym algoritmom Dva uporyadochennyh massiva polovinnogo razmera soedinyayutsya v odin 1 1 2 1 Rekursivnoe razbienie zadachi na menshie proishodit do teh por poka razmer massiva ne dostignet edinicy lyuboj massiv dliny 1 mozhno schitat uporyadochennym 3 1 Soedinenie dvuh uporyadochennyh massivov v odin Osnovnuyu ideyu sliyaniya dvuh otsortirovannyh massivov mozhno obyasnit na sleduyushem primere Pust my imeem dva uzhe otsortirovannyh po vozrastaniyu podmassiva Togda 3 2 Sliyanie dvuh podmassivov v tretij rezultiruyushij massiv Na kazhdom shage my beryom menshij iz dvuh pervyh elementov podmassivov i zapisyvaem ego v rezultiruyushij massiv Schyotchiki nomerov elementov rezultiruyushego massiva i podmassiva iz kotorogo byl vzyat element uvelichivaem na 1 3 3 Priceplenie ostatka Kogda odin iz podmassivov zakonchilsya my dobavlyaem vse ostavshiesya elementy vtorogo podmassiva v rezultiruyushij massiv Realizaciya na yazykah programmirovaniyaPrimer sortirovki na yazyke Si Sortiruet massiv ispolzuya rekursivnuyu sortirovku sliyaniem up ukazatel na massiv kotoryj nuzhno sortirovat down ukazatel na massiv s kak minimum takim zhe razmerom kak u up ispolzuetsya kak bufer left levaya granica massiva peredajte 0 chtoby sortirovat massiv s nachala right pravaya granica massiva peredajte dlinu massiva 1 chtoby sortirovat massiv do poslednego elementa vozvrashaet ukazatel na otsortirovannyj massiv Iz za osobennostej raboty dannoj realizacii otsortirovannaya versiya massiva mozhet okazatsya libo v up libo v down int merge sort int up int down unsigned int left unsigned int right if left right down left up left return down unsigned int middle left right left 2 razdelyaj i sortiruj int l buff merge sort up down left middle int r buff merge sort up down middle 1 right sliyanie dvuh otsortirovannyh polovin int target l buff up down up unsigned int l cur left r cur middle 1 for unsigned int i left i lt right i if l cur lt middle amp amp r cur lt right if l buff l cur lt r buff r cur target i l buff l cur l cur else target i r buff r cur r cur else if l cur lt middle target i l buff l cur l cur else target i r buff r cur r cur return target Realizaciya na yazyke C 11 include lt algorithm gt include lt cstddef gt include lt iterator gt include lt memory gt template lt typename T gt void merge sort T array std size t size noexcept if size gt 1 std size t const left size size 2 std size t const right size size left size merge sort amp array 0 left size merge sort amp array left size right size std size t lidx 0 ridx left size idx 0 std unique ptr lt T gt tmp array new T size while lidx lt left size ridx lt size if array lidx lt array ridx tmp array idx std move array lidx lidx else tmp array idx std move array ridx ridx if lidx left size std copy std make move iterator amp array ridx std make move iterator amp array size amp tmp array idx break if ridx size std copy std make move iterator amp array lidx std make move iterator amp array left size amp tmp array idx break std copy std make move iterator tmp array get std make move iterator amp tmp array size array Realizaciya na yazyke C 14 s rasparallelivaniem ot OpenMP include lt algorithm gt include lt iterator gt include lt omp h gt include lt memory gt template lt typename Iterator gt void mergesort Iterator from Iterator to pragma omp parallel pragma omp single nowait static assert std is same lt typename std iterator traits lt Iterator gt value type void gt value auto n std distance from to if 1 lt n pragma omp task firstprivate from to n Iterator l from from Iterator l to l from std advance l to n 2 mergesort l from l to pragma omp task firstprivate from to n Iterator r from from std advance r from n 2 Iterator r to r from std advance r to n n 2 mergesort r from r to pragma omp taskwait auto tmp array std make unique lt typename Iterator value type gt n Iterator l iter from Iterator l end l iter std advance l end n 2 Iterator r iter l end Iterator amp r end to auto tmp iter tmp array get while l iter l end r iter r end if l iter lt r iter tmp iter std move l iter l iter tmp iter else tmp iter std move r iter r iter tmp iter if l iter l end std copy std make move iterator r iter std make move iterator r end tmp iter break if r iter r end std copy std make move iterator l iter std make move iterator l end tmp iter break std copy std make move iterator tmp array get std make move iterator amp tmp array n from Iterativnaya realizaciya na yazyke C template lt typename T gt void MergeSort T a size t l size t BlockSizeIterator size t BlockIterator size t LeftBlockIterator size t RightBlockIterator size t MergeIterator size t LeftBorder size t MidBorder size t RightBorder for BlockSizeIterator 1 BlockSizeIterator lt l BlockSizeIterator 2 for BlockIterator 0 BlockIterator lt l BlockSizeIterator BlockIterator 2 BlockSizeIterator Proizvodim sliyanie s sortirovkoj pary blokov nachinayushuyusya s elementa BlockIterator levyj razmerom BlockSizeIterator pravyj razmerom BlockSizeIterator ili menshe LeftBlockIterator 0 RightBlockIterator 0 LeftBorder BlockIterator MidBorder BlockIterator BlockSizeIterator RightBorder BlockIterator 2 BlockSizeIterator RightBorder RightBorder lt l RightBorder l int SortedBlock new int RightBorder LeftBorder Poka v oboih massivah est elementy vybiraem menshij iz nih i zanosim v otsortirovannyj blok while LeftBorder LeftBlockIterator lt MidBorder amp amp MidBorder RightBlockIterator lt RightBorder if a LeftBorder LeftBlockIterator lt a MidBorder RightBlockIterator SortedBlock LeftBlockIterator RightBlockIterator a LeftBorder LeftBlockIterator LeftBlockIterator 1 else SortedBlock LeftBlockIterator RightBlockIterator a MidBorder RightBlockIterator RightBlockIterator 1 Posle etogo zanosim ostavshiesya elementy iz levogo ili pravogo bloka while LeftBorder LeftBlockIterator lt MidBorder SortedBlock LeftBlockIterator RightBlockIterator a LeftBorder LeftBlockIterator LeftBlockIterator 1 while MidBorder RightBlockIterator lt RightBorder SortedBlock LeftBlockIterator RightBlockIterator a MidBorder RightBlockIterator RightBlockIterator 1 for MergeIterator 0 MergeIterator lt LeftBlockIterator RightBlockIterator MergeIterator a LeftBorder MergeIterator SortedBlock MergeIterator delete SortedBlock if b Realizaciya na yazyke Python def merge sort arr if len arr lt 1 return arr mid len arr 2 left half arr mid right half arr mid left half merge sort left half right half merge sort right half return merge left half right half def merge left right merged while left and right if left 0 lt right 0 merged append left pop 0 else merged append right pop 0 merged extend left or right return mergedPsevdokodPsevdokod algoritma sliyaniya bez pricepleniya ostatka na Si podobnom yazyke L In1 R In2 if L R Out L In1 Out R In2 else if L lt R Out L In1 else Out R In2 V privedyonnom algoritme na Si podobnom yazyke ispolzuetsya proverka na ravenstvo dvuh sravnivaemyh elementov podmassivov s otdelnym blokom obrabotki v sluchae ravenstva Otdelnaya proverka na ravenstvo udvaivaet chislo sravnenij chto uslozhnyaet kod programmy Vmesto otdelnoj proverki na ravenstvo i otdelnogo bloka obrabotki v sluchae ravenstva mozhno ispolzovat dve proverki if L lt R i if L gt R chto pochti vdvoe umenshaet kod programmy Psevdokod uluchshennogo algoritma sliyaniya bez pricepleniya ostatka na Si podobnom yazyke L In1 R In2 if L lt R Out L In1 if L gt R Out R In2 Chislo proverok mozhno sokratit vdvoe ubrav proverku if L gt R Pri etom v sluchae ravenstva L i R L zapishetsya v Out v pervoj iteracii a R vo vtoroj Etot variant budet rabotat effektivno esli v ishodnom massive povtoryayushiesya elementy ne budut preobladat nad ostalnymi elementami Psevdokod sokrashennogo algoritma sliyaniya bez pricepleniya ostatka na Si podobnom yazyke L In1 R In2 if L lt R Out L In1 else Out R In2 Dve operacii peresylki v peremennye L i R uproshayut nekotorye zapisi v programme chto mozhet okazatsya poleznym v uchebnyh celyah no v dejstvitelnyh programmah ih mozhno udalit chto sokratit programmnyj kod Takzhe mozhno ispolzovat ternarnyj operator chto eshyo bolshe sokratit programmnyj kod Psevdokod eshyo bolee uluchshennogo algoritma sliyaniya bez pricepleniya ostatka na Si podobnom yazyke Out In1 lt In2 In1 In2 Vremya raboty algoritma poryadka O n log n pri otsutstvii degradacii na neudachnyh sluchayah kotoraya yavlyaetsya bolnym mestom bystroj sortirovki tozhe algoritm poryadka O n log n no tolko dlya srednego sluchaya Rashod pamyati vyshe chem dlya bystroj sortirovki pri namnogo bolee blagopriyatnom patterne vydeleniya pamyati vozmozhno vydelenie odnogo regiona pamyati s samogo nachala i otsutstvie vydeleniya pri dalnejshem ispolnenii Populyarnaya realizaciya trebuet odnokratno vydelyaemogo vremennogo bufera pamyati ravnogo sortiruemomu massivu i ne imeet rekursij Shagi realizacii InputArray sortiruemyj massiv OutputArray vremennyj bufer nad kazhdym otrezkom vhodnogo massiva InputArray N MIN CHUNK SIZE N 1 MIN CHUNK SIZE vypolnyaetsya kakoj to vspomogatelnyj algoritm sortirovki naprimer sortirovka Shella ili bystraya sortirovka ustanavlivaetsya ChunkSize MIN CHUNK SIZE slivayutsya dva otrezka InputArray N ChunkSize N 1 ChunkSize i InputArray N 1 ChunkSize N 2 ChunkSize poperemennym shaganiem sleva i sprava sm vyshe rezultat pomeshaetsya v OutputArray N ChunkSize N 2 ChunkSize i tak dlya vseh N poka ne budet dostignut konec massiva ChunkSize udvaivaetsya esli ChunkSize stal gt razmera massiva to konec rezultat v OutputArray kotoryj vvidu perestanovok opisannyh nizhe est libo sortiruemyj massiv libo vremennyj bufer vo vtorom sluchae on celikom kopiruetsya v sortiruemyj massiv inache menyayutsya mestami InputArray i OutputArray perestanovkoj ukazatelej i vsyo povtoryaetsya s punkta 4 Takaya realizaciya takzhe podderzhivaet razmeshenie sortiruemogo massiva i vremennogo bufera v diskovyh fajlah to est prigodna dlya sortirovki ogromnyh obyomov dannyh Realizaciya ORDER BY v SUBD MySQL pri otsutstvii podhodyashego indeksa ustroena imenno tak istochnik filesort cc v ishodnom kode MySQL Primer realizacii algoritma prostogo dvuhputevogo sliyaniya na psevdokode function mergesort m var list left right result if length m 1 return m else middle length m 2 for each x in m up to middle add x to left for each x in m after middle add x to right left mergesort left right mergesort right result merge left right return result end if Est neskolko variantov funkcii merge naibolee prostoj variant mozhet vyglyadet tak function merge left right var list result while length left gt 0 and length right gt 0 if first left first right append first left to result left rest left else append first right to result right rest right end if while length left gt 0 append first left to result left rest left while length right gt 0 append first right to result right rest right return resultDostoinstva i nedostatkiDostoinstva Rabotaet dazhe na strukturah dannyh posledovatelnogo dostupa Horosho sochetaetsya s podkachkoj i keshirovaniem pamyati Neploho rabotaet v parallelnom variante legko razbit zadachi mezhdu processorami porovnu no trudno sdelat tak chtoby drugie processory vzyali na sebya rabotu v sluchae esli odin processor zaderzhitsya Ne imeet trudnyh vhodnyh dannyh Ustojchivaya sohranyaet poryadok ravnyh elementov prinadlezhashih odnomu klassu ekvivalentnosti po sravneniyu Nedostatki Na pochti otsortirovannyh massivah rabotaet stol zhe dolgo kak na haotichnyh Sushestvuet variant sortirovki sliyaniem kotoryj rabotaet bystree na chastichno otsortirovannyh dannyh no on trebuet dopolnitelnoj pamyati pomimo vremennogo bufera kotoryj ispolzuetsya neposredstvenno dlya sortirovki Trebuet dopolnitelnoj pamyati po razmeru ishodnogo massiva PrimechaniyaKnuth D E The Art of Computer Programming Volume 3 Sorting and Searching angl 2nd Addison Wesley 1998 P 159 ISBN 0 201 89685 0 LiteraturaLevitin A V Glava 4 Metod dekompozicii Sortirovka sliyaniem Algoritmy Vvedenie v razrabotku i analiz M Vilyams 2006 S 169 172 576 s ISBN 978 5 8459 0987 9 Kormen T Lejzerson Ch Rivest R Shtajn K Algoritmy postroenie i analiz Introduction to Algorithms Pod red I V Krasikova 2 e izd M Vilyams 2005 1296 s ISBN 5 8459 0857 4 SsylkiImeetsya vikiuchebnik po teme Primery realizacii sortirovki sliyaniem Mnogofaznoe sliyanie na algolist manual ru Sortirovka sliyaniem voshodyashaya sortirovka estestvennaya sortirovka izmerenie bystrodejstviya Opisanie metoda i listing programm sortirovki sliyaniem Dinamicheskaya vizualizaciya 7 algoritmov sortirovki s otkrytym ishodnym kodom Primer realizacii na JavaV state est spisok istochnikov no ne hvataet snosok Bez snosok slozhno opredelit iz kakogo istochnika vzyato kazhdoe otdelnoe utverzhdenie Vy mozhete uluchshit statyu prostaviv snoski na istochniki podtverzhdayushie informaciyu Svedeniya bez snosok mogut byt udaleny 30 iyunya 2021

NiNa.Az

NiNa.Az - Абсолютно бесплатная система, которая делится для вас информацией и контентом 24 часа в сутки.
Взгляните
Закрыто