Этот баннер — требование Роскомнадзора для исполнения 152 ФЗ.
«На сайте осуществляется обработка файлов cookie, необходимых для работы сайта, а также для анализа использования сайта и улучшения предоставляемых сервисов с использованием метрической программы Яндекс.Метрика. Продолжая использовать сайт, вы даёте согласие с использованием данных технологий».
Политика конфиденциальности
|
|
|
Тяпничная пирамида
|
|||
|---|---|---|---|
|
#18+
Dima TРезультат 5-ти видов сортировки на массиве в 10 млн. элементов. Места ставил по времени. Несортированный АлгоритмВремя мсКопированийСравненийПримечаниеmerge_sort()1 990243 222 784230 068 109из инетаstd::sort()2 035338 720 497375 556 538MSVC2015insert_sort()2 049363 169 751376 875 415моя поделкаquick_sort()2 510168 421 944389 659 279из инетаqsort()3 045н/д277 090 450MSVC2015 Сортированный АлгоритмВремя мсКопированийСравненийinsert_sort()520 19 999 998std::sort()48017 415 788220 483 043quick_sort()5526 465 373243 606 228merge_sort()827243 222 784129 428 083qsort()1 054н/д237 187 025 Респект за проделанную работу. Я-бы еще предложил-бы дать на вход варианты данных (N штук): 1) Белый шум из N элементов. 2) Белый шум с низкой кардинальностью (всего 3-10 уникальных элементов из N) 3) Серии монотонных под-последовательностей 3-5 штук из N. Монотонные возрастающие-убывающие ("пила", синусоида). 4) Прочие краевые случаи. Например - неблагоприятные наборы на которых q-sort "переключается" в обычный алгоритм или валится со stackoverflow (depends on implementation) ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 01.02.2017, 00:02 |
|
||
|
Тяпничная пирамида
|
|||
|---|---|---|---|
|
#18+
maytonРеспект за проделанную работу. Я-бы еще предложил-бы дать на вход варианты данных (N штук): 1) Белый шум из N элементов. 2) Белый шум с низкой кардинальностью (всего 3-10 уникальных элементов из N) 3) Серии монотонных под-последовательностей 3-5 штук из N. Монотонные возрастающие-убывающие ("пила", синусоида). 4) Прочие краевые случаи. Например - неблагоприятные наборы на которых q-sort "переключается" в обычный алгоритм или валится со stackoverflow (depends on implementation) У меня 1й вариант реализован. Надо функцию fill() допилить: на вход параметр давать какого типа последовательность нужна. По п.4 не знаю как сгенерить, предлагай алгоритм. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 01.02.2017, 07:08 |
|
||
|
Тяпничная пирамида
|
|||
|---|---|---|---|
|
#18+
Друзья. Как вы заметили в последнее время я редко пишу посты. Чортова работа + курсы придавили меня к земле и не дают продохнуть. :) Но я читаю все посты где я участник так что - мысленно с вами :) ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 01.02.2017, 10:03 |
|
||
|
Тяпничная пирамида
|
|||
|---|---|---|---|
|
#18+
mayton4) Прочие краевые случаи. Например - неблагоприятные наборы на которых q-sort "переключается" в обычный алгоритм или валится со stackoverflow (depends on implementation) при правильной реализации QSort stackoverflow невозможен ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 01.02.2017, 14:17 |
|
||
|
Тяпничная пирамида
|
|||
|---|---|---|---|
|
#18+
Добавил разные исходные заполнения Код: plaintext 1. 2. 3. 4. 5. 6. 7. Исходник Код: plaintext 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26. 27. 28. 29. 30. 31. 32. 33. 34. 35. 36. 37. 38. 39. 40. 41. 42. 43. 44. 45. 46. 47. 48. 49. 50. 51. 52. 53. 54. 55. 56. 57. 58. 59. 60. 61. 62. 63. 64. 65. 66. 67. 68. 69. 70. 71. 72. 73. 74. 75. 76. 77. 78. 79. 80. 81. 82. 83. 84. 85. 86. Убрал qsort() добавил std::stable_sort() Время мс АлгоритмNEARLYORDEREDRANDOMRANDOM_DOUBLESREVERSESINUSSTAIRSinsert_sort()13131311369319128138merge_sort()64363817711164652835836quick_sort()1631621119579176415418std::sort()2712681255344305115127std::stable_sort()4254301238818502601608 Операций (копирований + сравнений) АлгоритмNEARLYORDEREDRANDOMRANDOM_DOUBLESREVERSESINUSSTAIRSinsert_sort()10 004 6959 999 999738 371 870199 030 889302 776 605131 526 867142 030 677merge_sort()362 011 134362 010 944463 267 963462 644 325357 657 408453 386 928453 368 256quick_sort()236 447 825236 445 593541 750 828403 557 861256 445 617387 576 172382 637 354std::sort()228 952 229228 951 438737 463 387186 343 940282 625 386111 500 018122 000 152std::stable_sort()325 963 938325 963 568565 121 728563 475 795468 497 124547 301 462542 329 730 Подробнее Копирования АлгоритмNEARLYORDEREDRANDOMRANDOM_DOUBLESREVERSESINUSSTAIRSinsert_sort()7900369 072 660102 318 66272 827 95476 243 23879 998 904merge_sort()243 222 784243 222 784243 222 784243 222 784243 222 784243 222 784243 222 784quick_sort()5 807 0165 805 696169 379 23263 116 09720 805 69737 944 05239 390 073std::sort()17 903 42017 902 850363 987 48889 248 99552 799 54856 249 95860 000 051std::stable_sort()209 375 190209 375 000291 879 725291 127 627369 375 000286 375 000280 500 000 Сравнения АлгоритмNEARLYORDEREDRANDOMRANDOM_DOUBLESREVERSESINUSSTAIRSinsert_sort()10 003 9059 999 999369 299 21096 712 227229 948 65155 283 62962 031 773merge_sort()118 788 350118 788 160220 045 179219 421 541114 434 624210 164 144210 145 472quick_sort()230 640 809230 639 897372 371 596340 441 764235 639 920349 632 120343 247 281std::sort()211 048 809211 048 588373 475 89997 094 945229 825 83855 250 06062 000 101std::stable_sort()116 588 748116 588 568273 242 003272 348 16899 122 124260 926 462261 829 730 В предыдущий замер сравнения неккоректно считались, т.к. перед записью был std::is_sorted(), который тоже счетчик менял. PS C предыдущими замерами не сравнивать, т.к. элемент массива с char[10] поменял на int64_t, чтобы порядок удобнее было задавать. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 01.02.2017, 17:08 |
|
||
|
Тяпничная пирамида
|
|||
|---|---|---|---|
|
#18+
maytonДалее. По поводу последовательности Код: plaintext 1. Я-бы выделил в ней две под-последовательности Код: plaintext 1. Они - монотонные. Неубывающие. И хорошо проходят через merge-sort. В противоположность. Если на вход пойдет белый шум длиной N элементов - то нужно эвристически принять решение о его НЕПРИГОДНОСТИ к частичным методам даже если случайно в нем будут меньше чем N подпоследовательностей. Ну в общем надо исходить из какой-то разумной пропорции. Зацепил ты меня этим постом, писать некогда, пока просто размышляю. Про белый шум не согласен, см. тест выше - отлично сортируется, т.е. можно сортировать что угодно. Идея как эффективно смержить две соседних возрастающих последовательности уже есть. Непонятки дальше. Последовательностей может быть много, очень много. Размеры у них разные. Тупо мержить в цикле первую с последующими не эффективно. Надо какой-то алгоритм какие мержить в каком порядке. Как интуитивно подозреваю: эффективнее всего мержить последовательности примерно равного размера. Например есть последовательности [4][2][55][48][2][12] число в скобках это количество элементов в каждой последовательности. В каком порядке их мержить? Может ты что предложишь? У меня мысли есть по этому поводу, но не нравятся они мне. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 01.02.2017, 20:08 |
|
||
|
Тяпничная пирамида
|
|||
|---|---|---|---|
|
#18+
Dima T, вопрос интересный. Приду домой - по думаю. Но сразу скажу что я не такой уж теоретик и знания у меня Весьма осколочные. Но гонять бенчмаркинг на разных данных - очень важно. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 01.02.2017, 20:43 |
|
||
|
Тяпничная пирамида
|
|||
|---|---|---|---|
|
#18+
[quot Dima T]maytonДалее. По поводу последовательности Например есть последовательности [4][2][55][48][2][12] число в скобках это количество элементов в каждой последовательности. В каком порядке их мержить? Может ты что предложишь? У меня мысли есть по этому поводу, но не нравятся они мне. Судя по всему, асимптотика merge двух массивов составляет . В твоем случае, такой порядок будет оптимальным: 2 merge 2, 4 merge 4,8 merge 12, 20 merge 48, 55 merge 68. Итого 2+4+12+48+68 операций. Возможно лучшим алгоритмом будет выбор двух минимальных по размеру массивов перед каждым merge(в этом я до конца не уверен). Но перед последней итерацией, идеальным будет merge двух равных по размеру массивов ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 01.02.2017, 22:04 |
|
||
|
Тяпничная пирамида
|
|||
|---|---|---|---|
|
#18+
А, да это же задача о рюкзаке с определенными ограничениями)) Не зря я сомневался в выборе двух минимальных на каждой итерации ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 01.02.2017, 22:07 |
|
||
|
Тяпничная пирамида
|
|||
|---|---|---|---|
|
#18+
ДмитрийМожет ты что предложишь? У меня мысли есть по этому поводу, но не нравятся они мне. Потому не зря они тебе не нравились)) ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 01.02.2017, 22:17 |
|
||
|
Тяпничная пирамида
|
|||
|---|---|---|---|
|
#18+
Если каналов доступа к памяти два. И "удачно лягут карты" - то можно попробовать в 2 потока запустить merge sort. +Если мы храним min/max для каждой серии то возможно стоит изучить вариант просто тривиальной конкатенации серий (опять-же если мы имеем дело с неким синтетическим источником данных). ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 02.02.2017, 01:12 |
|
||
|
Тяпничная пирамида
|
|||
|---|---|---|---|
|
#18+
Dima T... Например есть последовательности [4][2][55][48][2][12] число в скобках это количество элементов в каждой последовательности. В каком порядке их мержить? ... Есть такой алгоритм - "естественная двусторонняя сортировка слиянием" (nature merge sort или nature 2-way merge sort) (у которой есть "неестественные" вариации - вроде двоичной двусторонней бла-бла-бла, и далее - многоветочные истории, которые, правда, вроде как скисают на большом числе веток и больших сортируемых объемах - я в них не разбирался детально.) не поленись, погугли. Идею алгоритма приписывают Кнуту. Смысл в том, чтобы сливать с двух краев в середину (свеча слияния горит с двух концов). То есть на первом шаге алгоритма слияние идет в таком порядке: [4][2][55][48][2][12] || x||x xx||xx при этом на фазе самого слияния используют двоичный поиск. То есть Сортированный_результат = ГоримСДвухСторон(Разбиение_на_Сортированные_диапазоны(Сортируемый_Список)) В принципе, алгоритму не требует наличия сколь-нибудь протяженных предварительно сортированных поддиапазонов. Но, если сортируемый список представляет чистый белый шум, то у некоторых имплементаторов есть мнение, что разумно натравить на БелыйШум сортировку вставкой, с размером итоговых сортированных поддиапазонов на 8 - 16 элементов, что и создаст стартовую точку для горения с двух сторон. Еще есть изобретения in-place слияния. имхо, годное к разглядыванию обсуждение: http://stackoverflow.com/questions/2571049/how-to-sort-in-place-using-the-merge-sort-algorithm ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 02.02.2017, 02:16 |
|
||
|
Тяпничная пирамида
|
|||
|---|---|---|---|
|
#18+
booby, существенная деталь - в свечном производстве с головы ищут неубывающую подпоследовательность, а с хвоста - невозрастающую. т.е. в исходной идее, в голове - [4][2][55] - это возрастающие поддиапазоны (asc), а [48][2][12] - убывающие (desc) поддиапазоны ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 02.02.2017, 02:29 |
|
||
|
Тяпничная пирамида
|
|||
|---|---|---|---|
|
#18+
booby, очень заманчиво выглядит по сравнению с наивной квадратичной реализацией, ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 02.02.2017, 10:37 |
|
||
|
Тяпничная пирамида
|
|||
|---|---|---|---|
|
#18+
У меня мысль минимизировать копирования, т.к. из-за них тормоза на почти сортированной последовательности. Поэтому видится вариант работы внутри исходного массива. Т.е. ограничится только слиянием соседних подмассивов. Слияние двух соседних сортированных подмассивов Код: plaintext 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26. 27. 28. 29. 30. 31. 32. 33. 34. 35. 36. 37. Из-за очереди тормозит, надо ее на массив менять, но для замера количества операций сойдет Затестил последовательное слияние, т.е. первый со вторым, результат с третьим и т.д. Итого на 1000 элементах в 50 раз больше операций чем у std::sort() на обратносортированной, т.е. алгоритм выродился в сортировку вставками. На "белом шуме" больше "всего" в 14 раз. booby, тоже самое будет со свечой, разве что вдвое быстрее, т.е. вместо O(n 2 ) получим O(n 2 /2). Затестил вариант слияния попарно, т.е. Код: plaintext 1. 2. 3. тут результаты получше Заполнениеstd::sort()merge_ordered()СоотношениеRANDOM737 463 387592 349 26880%RANDOM_DOUBLES186 343 940588 526 298316%ORDERED228 951 4389 999 9994%STAIRS122 000 152488 230 344400%SINUS111 500 018552 390 781495%NEARLY228 952 22910 001 4324%REVERSE282 625 386613 296 588217%Максимум737 463 387613 296 58883% Цифры это всего операций (сравнений + копирований). Размер массива 10 млн. В принципе уже неплохо. Но мне кажется можно еще улучшить, хотя бы до показателей merge_sort() на несортированных. Надо придумать алгоритм типа такого: перебираем в цикле массив подмассивов. Каждый subarr[i] сравниваем с соседними subarr[i-1] и subarr[i+1], затем принимаем решение с каким из них смержить или оставить как есть на данном проходе. И так по кругу в цикле пока все не смержатся. Осталось придумать как сравнивать подмассивы. По ним есть размер и минимальный/максимальный элемент. Склеивание парами Код: plaintext 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26. 27. 28. 29. 30. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 02.02.2017, 11:12 |
|
||
|
Тяпничная пирамида
|
|||
|---|---|---|---|
|
#18+
Dima T, код внимательно разглядывать не могу, но, кажется, ты не обратил внимание на то, что свечка при слиянии подмассивов заведомо рассчитывает на то, что имеет дело с уже отсортированными диапазонами. Поэтому не боится использовать двоичный поиск на фазе слияния. Пусть сливаются отрезки с длинами а)[4](левый) и б)[12] (правый) /*текущая позиция в а */ и = старт_а голова_цикла: номер_позиции_а(и)_в_б = двоичным поиском ищем позицию(б) от текущего начала не перелитой части б до найденной и вываливаем все б(ж) в область слияния вываливаем в область слияния элементы а, пока они не больше а(и) устанавливаемся в новую позицию и в а Если диапазоны не кончились, то ГОУ ТУ голова_цикла Тут надо обратить внимание на то, что, с одной стороны, в принципе всегда хотелось бы иметь ведущий диапазон меньшего размера, а тот, в котором будем искать двоичным поиском - большего. Но, если их переставлять не глядя, то нарушится стабильность, присущая исходному merge sort. Поэтому фига из трех пальцев - либо плюнуть на стабильность, либо плюнуть на разборки - кто из них длиннее, либо озаботиться устабилизацией обмена диапазонов. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 02.02.2017, 12:03 |
|
||
|
Тяпничная пирамида
|
|||
|---|---|---|---|
|
#18+
boobyDima T, код внимательно разглядывать не могу, но, кажется, ты не обратил внимание на то, что свечка при слиянии подмассивов заведомо рассчитывает на то, что имеет дело с уже отсортированными диапазонами. Поэтому не боится использовать двоичный поиск на фазе слияния. Двочный поиск у меня есть. В merge_near() им ищется место откуда слияние начинать. Все подмассивы считаются сортированными. Может я неправильно понял описание твоего алгоритма. Пишу как понял, например массив: Код: plaintext 1. где то что в [] это уже сортированные подмассивы, цифры - количество элементов далее смерживаем Код: plaintext 1. 2. 3. 4. 5. 6. 7. 8. Если так то, я почти так и делал, только полсвечи, т.е. Код: plaintext 1. 2. 3. 4. 5. Такой подход тормозит на обратносортированном, твоя свеча тоже будет тормозить, т.к. добавление будет всегда по одному элементу в начало, т.е. сортировка вставками, а двоичный поиск только лишние тормоза даст, т.к. достаточно сравнения первого с первым элемента. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 02.02.2017, 13:03 |
|
||
|
Тяпничная пирамида
|
|||
|---|---|---|---|
|
#18+
Dima T, сортировка слияниями базируется на том что слияние двух сортированных массивов имеет сложность не больше O(a+b), где a и b размеры сливаемых массивов собственно на каждом уровне итерации - k необходимо произвести 2^k слияний мощностью (N/2^k), в сумме для уровня <= O(N) всего уровней log2(N) - общая сложность - O(N* Ln(N)) если процедура слияния не удовлетворяет крайней оценке O(a+b), то ни о каких O(N* Ln(N)) для сортировки речи идти не может в сабже от booby предлагается сделать с внешним массивом, тогда можно добиться O(a+b), но в крайнем случае размер временного массива должен быть равен N с другой стороны если использовать дополнительный массив, то тот же heapsort легко избавляется от своего главного недостатка - построение обратной кучи на первом этапе ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 02.02.2017, 13:35 |
|
||
|
Тяпничная пирамида
|
|||
|---|---|---|---|
|
#18+
kealon(Ruslan)Dima T, сортировка слияниями базируется на том что слияние двух сортированных массивов имеет сложность не больше O(a+b), где a и b размеры сливаемых массивов собственно на каждом уровне итерации - k необходимо произвести 2^k слияний мощностью (N/2^k), в сумме для уровня <= O(N) всего уровней log2(N) - общая сложность - O(N* Ln(N)) При слиянии парами у меня так и получилось, например Код: plaintext 1. Но это O(N* Ln(N)) на уровне слияний, но сами слияния тоже отличаются например [48][2][12] можно слить Код: plaintext 1. а можно Код: plaintext 1. ИМХО второй вариант предпочтительней, т.е. предпочтение надо как-то отдать слиянию меньших подмассивов. Есть одна мысль, вечером потестю, выложу результаты. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 02.02.2017, 14:15 |
|
||
|
Тяпничная пирамида
|
|||
|---|---|---|---|
|
#18+
Сделал склеивание только тех подмассивов, которые дадут итого меньше двух средних размеров Код: plaintext 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26. 27. 28. 29. 30. 31. 32. 33. 34. 35. 36. 37. 38. 39. 40. Особых изменений нет, чуть-чуть получше местами. Думаю в разы этот алгоритм не улучшить. std::sort()insert_sort()%merge_ordered()%Заполнение737 463 387738 371 870100%600 849 36181%Случайные (диапазон 0...TEST_SIZE*2)186 343 940199 030 889107%596 760 728320%Случайные с повторами (диапазон 0...100)228 951 4389 999 9994%9 999 9994%Отсортированный122 000 152142 030 677116%488 230 344400%Лесенка по 10 (1 2 3 ...8 9 0 1 ...)111 500 018131 526 867118%549 117 750492%Синусоида по 10 (1 2 3...8 9 8 7 ...)228 952 22910 004 6954%10 001 4324%Почти сортированный (20 значений смещено на 20 позиций)282 625 386302 776 605107%613 296 588217%Обратно сортированный730 224 311711 355 83597%80 000 07811%4 одинаковых подмассива Посчитаны операции (сравнения + копирования) Проценты по отношению к std::sort() ИМХО insert_sort() (сортировка вставками + двоичный поиск + std::sort()) в общем случае быстрее. Исключение последний тест, где массив это 4 сортированных подмассива. Но это редкий случай и его можно заменить на слияние во время объединения подмассивов. Еще Белый шум получше сортирует, но по времени в 7 раз медленнее, есть что оптимизировать (std::queue на массив заменить), но сомневаюсь что оптимизаторством такой разрыв времени можно компенсировать. Да и памяти дополнительной надо прилично. insert_sort() победил Код: plaintext 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26. 27. 28. 29. 30. 31. 32. 33. 34. 35. 36. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 02.02.2017, 17:29 |
|
||
|
Тяпничная пирамида
|
|||
|---|---|---|---|
|
#18+
Dima T, "Поиск места вставки" можно чуток оптимизировать не сразу задавая int r = 0 а расширять диапазон в нужную сторону от прошлого места вставки с помощью бинарного расширения в нужную сторону и к этому диапазону потом применить бинарный поиск худшую асимптотику поиска это не увеличит, а вот на частично-отсортированных массивах ускорит основательно ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 02.02.2017, 23:18 |
|
||
|
Тяпничная пирамида
|
|||
|---|---|---|---|
|
#18+
boobyDima T, код внимательно разглядывать не могу, но, кажется, ты не обратил внимание на то, что свечка при слиянии подмассивов заведомо рассчитывает на то, что имеет дело с уже отсортированными диапазонами. Поэтому не боится использовать двоичный поиск на фазе слияния. Пусть сливаются отрезки с длинами а)[4](левый) и б)[12] (правый) /*текущая позиция в а */ и = старт_а голова_цикла: номер_позиции_а(и)_в_б = двоичным поиском ищем позицию(б) от текущего начала не перелитой части б до найденной и вываливаем все б(ж) в область слияния вываливаем в область слияния элементы а, пока они не больше а(и) устанавливаемся в новую позицию и в а Если диапазоны не кончились, то ГОУ ТУ голова_цикла Тут надо обратить внимание на то, что, с одной стороны, в принципе всегда хотелось бы иметь ведущий диапазон меньшего размера, а тот, в котором будем искать двоичным поиском - большего. Но, если их переставлять не глядя, то нарушится стабильность, присущая исходному merge sort. Поэтому фига из трех пальцев - либо плюнуть на стабильность, либо плюнуть на разборки - кто из них длиннее, либо озаботиться устабилизацией обмена диапазонов. А что будет с вашим алгоритмом, если массивы будут стыковаться как две расчески? Асимптотика слияния О(max(a_s,b_s)), не понятно о чем дискуссия. Оптимальный способ порядка сливания множества массивов - NP полная задача. Свечка возможно даст хорошее решение, но не оптимальное. Да и то, судя по всему необходимо будет проводите действия по переупорядочиванию элементов свечи, что также накладно. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 03.02.2017, 00:19 |
|
||
|
Тяпничная пирамида
|
|||
|---|---|---|---|
|
#18+
SashaMercuryА что будет с вашим алгоритмом, если массивы будут стыковаться как две расчески? (Кнута это алгоритм, Дональда Эрвина, который русский выучил только за то, что им разговаривал Андрей Петрович Ершов. Чтобы книжки его читать в оригинале. ) Вопрос правильный. Остановится при перехлесте. Так как слежение за перехлестом встроено в (реальный) алгоритм. Без опасности перехлеста работает 2-way. Который не смотрит на то, есть ли естественным образом сортированные куски, а вменяет сливаемым диапазонам быть сортированными путем слияния диапазонов, начиная 1. А так как первые пять шагов слияния в 2way, стартующего с единичных крайних элементов занимаются слиянием слишком коротких массивов, сам Кнут настаивает - не надо так делать. Надо натравить сортировку вставками для разбиения массива на сортированные диапазоны размером в 16 в качестве первого шага, а потом можно включать 2way ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 03.02.2017, 01:40 |
|
||
|
Тяпничная пирамида
|
|||
|---|---|---|---|
|
#18+
Dima TМожет я неправильно понял описание твоего алгоритм Сейчас покопался еще раз в началах и концах. Нашел следующее - в варианте, описанном у Кнута (5.2.4), действительно, слева ищутся возрастающие, справа убывающие диапазоны. При этом само слияние совмещено с просмотром. Такая версия подачи затрудняет общее понимание идеи. Стартуя с приведенной мной ссылки можно добраться до книжки "Элементарные алгоритмы", в которой изложена упрощенная версия, не ждущая убывающего диапазона с правой стороны. Имхо этот вариант проще для понимания и после него легче будет смотреть в книжку Кнута. Пусть дан для сортировки массив M[8, 12, 14 , 0, 1, 4, 11, 2, 3, 5, 9, 13, 10, 6, 15, 7] И известно, что элементов в нем 16 N=16; merge_step = 0 0) Выделим память размером в полученный массив (N) M[8, 12, 14 , 0, 1, 4, 11, 2, 3, 5, 9, 13, 10, 6, 15, 7] -- доп. память N=16 P[x, xx, xx , x, x, x, xx, x, x, x, x, xx, xx, xx, xx, x] <<ДЕЛАЙ ВСЕГДА>> ileft_start = 1; //начало левого диапазона ileft_stop = 1; //конец левого диапазона iright_start = N; // начало правого диапазона iright_stop = N; // конец правого диапазона merge_leftpos_start = 1; // позиция, начиная с которой будем дописывать в массив промежуточного результата // мы считаем с 1, хоть форум и по C++ merge_rightpos_start = N; // 16 - позиция, в которую будем дописывать справа //шаг слияния, первый рабочий шаг будет 1 (нечетный шаг) (на нечетных шагах будем дописывать в левую часть выделенной памяти, на четной - в правую ) merge_step = 1; <<ЦИКЛ ПОКА ПРОБЕГА ПОКА НЕ ПРОСМОТРИМ M ЦЕЛИКОМ (ileft_stop < iright_start)>> //ищем позицию в которой завершается первый неубывающий диапазон слева ileft_stop = поиск_слева(ileft_start ); // здесь получим 3 на первом шаге для конкретного массива ЕСЛИ ileft_stop >= N то алгоритм завершен, т.к. массив полностью сортирован. // вот что мы нашли M[ 8, 12, 14 | , 0, 1, 4, 11, 2, 3, 5, 9, 13, 10, 6, 15, 7] // //ищем позицию упорядоченного убывающего диапазона справа iright_start = поиск_справа(iright_stop)// получим 15 на первом просмотре ЕСЛИ ileft_stop >=iright_start то случился перехлест, любим левый край: iright_start = ileft_stop + 1 // //вот что мы нашли M[ 8, 12, 14 |, 0, 1, 4, 11, 2, 3, 5, 9, 13, 10, 6,| 15, 7 ] // здесь мы уже знаем какой размер займет результат // - 5 элементов = (ileft_stop - ileft_start +1) + (iright_stop - iright_start+1) // но, т.к. у нас две позиции вставки - левая и правая, то пусть их формирует процедура //слияния, которой мы будет рассказывать, в какую сторону - левую или правую ей надо доливать, а она нам за это вернет новую позицию после долива Если Нечетно(merge_step) Сливаем_в_M(ileft_start, ileft_stop, iright_start, iright_stop,merge_leftpos_start,Слева_Если_Нечетно(merge_step)); Иначе Сливаем_в_M(ileft_start, ileft_stop, iright_start, iright_stop,merge_rightpos_start, Слева_Если_Нечетно(merge_step)); // результат M[ 8, 12, 14 | , 0, 1, 4, 11, 2, 3, 5, 9, 13, 10, 6, 15, 7] P[7, 8, 12, 14, 15, x, xx, x, x, x, x, xx, xx, xx, xx, x] merge_step = NOT merge_step ileft_start = ileft_stop + 1; // 4 после первого прохода iright_stop = iright_start - 1; //14 после первого прохода <<КОНЕЦ ЦИКЛА ПОКА>> // завершен один полный пробег по M // меняем местами M и P - swap ОБМЕНЯТЬ(M,P); <<КОНЕЦ ДЕЛАЙ ВСЕГДА>> ---------- ------------------------------------ //т.к. у нас не программа а лог ее выполнения - пишем дальше. //сейчас мы на втором проходе внутри цикла <<ЦИКЛ ПОКА ПРОБЕГА ПОКА НЕ ПРОСМОТРИМ M ЦЕЛИКОМ (ileft_stop < iright_start)>> // продолжаем... //ищем позицию в которой завершается первый неубывающий диапазон слева // начало у нас сейчас в 4 ileft_stop = поиск_слева(ileft_start ); // здесь получим 7 на втором шаге для конкретного массива // вот что мы нашли M[8, 12, 14, 0, 1, 4, 11 |, 2, 3, 5, 9, 13, 10, 6, 15, 7] //ищем позицию упорядоченного убывающего диапазона справа //стоп у нас в 14 iright_start = поиск_справа(iright_stop)// получим 12 на втором просмотре // вот что мы нашли M[8, 12, 14, 0, 1, 4, 11 |, 2, 3, 5, 9,| 13, 10, 6 |, 15, 7] // шаг четиный, потому сливаем вправо //!! В правый угол пишем в обратной последовательности Если нечетно Сливаем_в_M(ileft_start, ileft_stop, iright_start, iright_stop,merge_leftpos_start, Слева_Если_Нечетно(merge_step)); Иначе Сливаем_в_M(ileft_start, ileft_stop, iright_start, iright_stop,merge_rightpos_start, Слева_Если_Нечетно(merge_step)); // резултьтат M[8, 12, 14, 0, 1, 4, 11 |, 2, 3, 5, 9,| 13, 10, 6 |, 15, 7] P[7, 8, 12, 14, 15, x, xx, x, x, 13, 11, 10, 6, 4, 1, 0] и так далее... ------------------------------------- натуральной такую свечку Кнут называет из-за того, что она двигается в поисках однородной последовательности столько, сколько может. Мне кажется, на том же основании ее можно было бы назвать жадной свечкой. Она то жадная, но всегда не знает, сколько сейчас ей хотеть, потому собирает всякий раз по копеечке. Кнут оценивает ее как в среднем уступающую быстрой сортировке, но выигрывающей на почти сортированном массиве. А на таком специальном почти сортированном, который за одно слияние становится сортированным, ее трудно обогнать. В записи Кнута просмотры осуществляются с обоих концов разом и совмещены с копированием в результат (слиянием). Главный недостаток - в этой версии алгоритму всегда неизвестно, где расположены сейчас границы диапазонов. Хотя по мере заполнения P все размеры получающихся диапазонов известны, и после первого swap их можно было бы поддерживать. Но, такую версию, вроде как, выписывать не принято. Считается, что если входной массив сортированный, но не настолько, чтобы обойтись одним-двумя проходами главного цикла, то дешевле и умнее сразу вооружиться 2way версией (подкрученной до стартовой insertion sort), которая путем применения вмененной арифметики всегда знает границы своих сортированных частей для четного случая. А нечетный сводится к четному путем определения места для нечетного элемента двоичным поиском на последнем шаге сортировки. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 03.02.2017, 04:25 |
|
||
|
|

start [/forum/topic.php?fid=57&msg=39397691&tid=2018242]: |
0ms |
get settings: |
9ms |
get forum list: |
12ms |
check forum access: |
4ms |
check topic access: |
4ms |
track hit: |
53ms |
get topic data: |
9ms |
get forum data: |
3ms |
get page messages: |
60ms |
get tp. blocked users: |
2ms |
| others: | 284ms |
| total: | 440ms |

| 0 / 0 |
