powered by simpleCommunicator - 2.0.38     © 2025 Programmizd 02
Форумы / Microsoft Office [игнор отключен] [закрыт для гостей] / сортировка Шелла на VBA, сравнение производительности различных последовательностей.
14 сообщений из 14, страница 1 из 1
сортировка Шелла на VBA, сравнение производительности различных последовательностей.
    #39829620
booby
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Недавно мне понадобилась собственная сортировка одномерных массивов на VBA.
Условия следующие: размер массива от нескольких сотен элементов до чуть более сорока тысяч,
основная масса сортируемых массивов в пределах 1500 - 2800 элементов.
Массивы всегда "почти сортированы" - не в своей позиции, как правило, находятся всего несколько элементов.
Это хорошие условия для сортировки Шелла.
Дополнительным её преимуществом является предельная простота и ясность кода.
Нарисовал себе обменный вариант, взяв его из книжки Сэджвика "Алгоритмы на Java"
(в прикладываемом файле он назван обменным вариантом Кнута).
Его фактическая работа на "моих" массивах меня полностью устраивает, и вряд ли я буду его заменять.

Но в пятницу случайно наткнулся на сайте у Сэджвика на "драйвер", сравнивающий
эффект работы различных последовательностей h-сортировки на общий результат,
и решил сделать нечто похожее на VBA.
Адрес Седжвикова драйвера:
https://www.cs.princeton.edu/~rs/shell/driver.c

То, что получилось, выкладываю здесь.
Я не стал выписывать для каждой версии обменные варианты, только для тех вариантов, которые меня заинтересовали.
Последовательность Ciura, 2001 A102549 проигнорировал целиком.
Также взял не все варианты, рассмотренные в дрйвере Сэджвика, но взамен взял последовательность Токуда A108870.

Общие выводы у меня получаются такими:
- с обменными вариантами лучше не соваться в область сотен тысяч элементов в случайно заполненном массиве
- при работе с почти сортированными массивами обменные варианты хоть и немного, но отчетливо выигрывают.
- глубоко удовлетворен почти линейными характеристиками при работе на почти сортированных массивах.
- удивился поразительно хорошим общим характеристикам работы первой последовательности Сэджвика и последовательности Токуда.
- производительность последовательности Gonnet 5/11 скачет как бешеный заяц по отношению к соседям.

Далее, в процедуре тестирования видно два объявления массива тестируемых размеров.
На большем из них на моем стареньком AMD полный тест отрабатывает примерно за 16 минут.
На меньшем - около трех минут.

Для измерения времени взят код с www.decisionmodels.com
а именно: https://fastexcel.wordpress.com/2011/10/26/match-vs-find-vs-variant-array-vba-performance-shootout/

для генерации случайного целого числа используется такой код:

Код: vbnet
1.
2.
3.
Function next_RND_Long(ByVal ileftBound As Long, ByVal iRightBound As Long) As Long
  next_RND_Long = Fix((iRightBound - ileftBound) * Rnd) + ileftBound
End Function




Код под кнопкой запуска теста:
Код: vbnet
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.
Private Sub btnDoTest_Click()
 Dim dTime As Double

 dTime = MicroTimer

 Dim r As Range
 Dim ilastRow&
 
 [A1].Value = "Подождите несколько минут, будет сообщение о заврешении построения"
 
'получим последнюю строку заполненных данных
 ilastRow = Range("A:D").Find(What:="", After:=Range("A3"), LookIn:=xlFormulas, LookAt:= _
        xlPart, SearchOrder:=xlByColumns, SearchDirection:=xlNext, MatchCase:= _
        False, SearchFormat:=False).Row - 1&
          
 'очистим область размещения результата
 If ilastRow > 3 Then
   Range("A4:D" & ilastRow).ClearContents
 End If
 Set r = [A4:D4]
 
 Test_shellsort r
 
 dTime = MicroTimer - dTime
 dTime = Round(dTime, 0)
 
 Dim nMinutes As Long, nSecs As Long
 nMinutes = dTime \ 60&
 nSecs = dTime - 60# * nMinutes
 '[A1].ClearContents
 [A1].Value = "Общее время работы - минут: " & nMinutes & " секунд: " & nSecs
 MsgBox "Построение завершено."
End Sub



код модуля с вариантами сортировок Шелла:

Код: vbnet
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.
87.
88.
89.
90.
91.
92.
93.
94.
95.
96.
97.
98.
99.
100.
101.
102.
103.
104.
105.
106.
107.
108.
109.
110.
111.
112.
113.
114.
115.
116.
117.
118.
119.
120.
121.
122.
123.
124.
125.
126.
127.
128.
129.
130.
131.
132.
133.
134.
135.
136.
137.
138.
139.
140.
141.
142.
143.
144.
145.
146.
147.
148.
149.
150.
151.
152.
153.
154.
155.
156.
157.
158.
159.
160.
161.
162.
163.
164.
165.
166.
167.
168.
169.
170.
171.
172.
173.
174.
175.
176.
177.
178.
179.
180.
181.
182.
183.
184.
185.
186.
187.
188.
189.
190.
191.
192.
193.
194.
195.
196.
197.
198.
199.
200.
201.
202.
203.
204.
205.
206.
207.
208.
209.
210.
211.
212.
213.
214.
215.
216.
217.
218.
219.
220.
221.
222.
223.
224.
225.
226.
227.
228.
229.
230.
231.
232.
233.
234.
235.
236.
237.
238.
239.
240.
241.
242.
243.
244.
245.
246.
247.
248.
249.
250.
251.
252.
253.
254.
255.
256.
257.
258.
259.
260.
261.
262.
263.
264.
265.
266.
267.
268.
269.
270.
271.
272.
273.
274.
275.
276.
277.
278.
279.
280.
281.
282.
283.
284.
285.
286.
287.
288.
289.
290.
291.
292.
293.
294.
295.
296.
297.
298.
299.
300.
301.
302.
303.
304.
305.
306.
307.
308.
309.
310.
311.
312.
313.
314.
315.
316.
317.
318.
319.
320.
321.
322.
323.
324.
325.
326.
327.
328.
329.
330.
331.
332.
333.
334.
335.
336.
337.
338.
339.
340.
341.
342.
343.
344.
345.
346.
347.
348.
349.
350.
351.
352.
353.
354.
355.
356.
357.
358.
359.
360.
361.
362.
363.
364.
365.
366.
367.
368.
369.
370.
371.
372.
373.
374.
375.
376.
377.
378.
379.
380.
381.
382.
383.
384.
385.
386.
387.
388.
389.
390.
391.
392.
393.
394.
395.
396.
397.
398.
399.
400.
401.
402.
403.
404.
405.
406.
407.
408.
409.
410.
411.
412.
413.
414.
415.
416.
417.
418.
419.
420.
421.
422.
423.
424.
425.
426.
427.
428.
429.
430.
431.
432.
433.
434.
435.
436.
437.
438.
439.
440.
441.
442.
443.
444.
445.
446.
447.
448.
449.
450.
451.
452.
453.
454.
455.
456.
457.
458.
459.
460.
461.
462.
463.
464.
465.
466.
467.
468.
469.
470.
471.
472.
473.
474.
475.
476.
477.
478.
479.
480.
481.
482.
483.
484.
485.
486.
487.
488.
489.
490.
491.
492.
493.
494.
495.
496.
497.
498.
499.
500.
501.
502.
503.
504.
505.
506.
507.
508.
509.
510.
511.
512.
513.
514.
515.
516.
517.
518.
519.
520.
521.
522.
523.
524.
525.
526.
527.
528.
529.
530.
531.
532.
533.
534.
535.
536.
537.
538.
539.
540.
541.
542.
543.
544.
545.
546.
547.
548.
549.
550.
551.
552.
553.
554.
555.
556.
557.
558.
559.
560.
561.
562.
563.
564.
565.
566.
567.
568.
569.
570.
571.
572.
573.
574.
575.
576.
577.
578.
579.
580.
581.
582.
583.
584.
585.
586.
587.
588.
589.
590.
591.
592.
593.
594.
595.
596.
597.
598.
599.
600.
601.
602.
603.
604.
605.
606.
607.
608.
609.
610.
611.
612.
613.
614.
615.
616.
617.
618.
619.
620.
621.
622.
623.
624.
625.
626.
627.
628.
629.
630.
631.
632.
633.
634.
635.
636.
637.
638.
639.
640.
641.
642.
643.
644.
645.
646.
647.
648.
649.
650.
651.
652.
653.
654.
655.
656.
657.
658.
659.
660.
661.
662.
663.
664.
665.
666.
667.
668.
669.
670.
671.
672.
673.
674.
675.
676.
677.
678.
679.
680.
681.
682.
683.
684.
685.
686.
687.
688.
689.
690.
691.
692.
693.
694.
695.
696.
697.
698.
699.
700.
701.
702.
703.
704.
705.
706.
707.
708.
709.
710.
711.
712.
713.
714.
715.
716.
717.
718.
719.
720.
721.
722.
723.
724.
725.
726.
727.
728.
729.
730.
731.
732.
733.
734.
735.
736.
737.
738.
739.
740.
741.
742.
743.
744.
745.
746.
747.
748.
749.
750.
751.
752.
753.
754.
755.
756.
757.
758.
759.
760.
761.
762.
763.
764.
765.
766.
767.
768.
769.
770.
771.
772.
773.
774.
775.
776.
777.
778.
779.
780.
781.
782.
Option Explicit

'Booby 2019

Public Function Ceiling(ByVal X As Double, Optional ByVal Factor As Double = 1) As Double
    Ceiling = (Int(X / Factor) - (X / Factor - Int(X / Factor) > 0)) * Factor
End Function

Sub randArray(pa() As Variant, ByVal pN As Long)
' формирует массив с числом элементов pN,
' и заполняет его случайными целыми
' в диапазоне от 0 до pN - 1

 ReDim pa(0 To pN - 1&)
 Dim i&
 For i = 0 To pN - 1&
   pa(i) = next_RND_Long(1, pN)
 Next
End Sub

Sub copyArray(ByRef pa() As Variant, ByRef pb() As Variant)
' копмрует целиком массив pa в массив pb
  pb = pa
End Sub

Function Less_V(ByRef a As Variant, ByRef B As Variant) As Boolean
  Less_V = (a < B)
End Function

Private Sub Swap_VS(ByRef pv_left As Variant, ByRef pv_right As Variant)
 ' обмен значений скалярных (простых) типов, переданных во входных параметрах по ссылке
  Dim v_Temp As Variant
  v_Temp = pv_right
  pv_right = pv_left
  pv_left = v_Temp
End Sub

Sub FindMinFirstMaxLastIndex(pa() As Variant, ByVal iLeft As Long, ByVal iRight As Long, ByRef iMin As Long, ByRef iMax As Long)
' процелура отыскивает методом линейного поиска индексы первого минимального и последнего максимального элементов
' в массиве pa() в позициях с iLeft (левая граница поиска) до iRight (правая граница поиска)
  Dim v_Min As Variant, v_Max As Variant
  Dim v_Temp As Variant
  Dim i As Long
  
  v_Min = pa(iLeft)
  iMin = iLeft
  v_Max = pa(iLeft)
  iMax = iLeft
  
  For i = iLeft + 1 To iRight
    v_Temp = pa(i)
    If v_Temp < v_Min Then
    'при сортировке по возрастанию левый элемент первый среди равных
      v_Min = pa(i)
      iMin = i
    End If
    
    If v_Temp >= v_Max Then
      'при сортировке по возрастанию ставим правый элемент последний среди равных
      v_Max = pa(i)
      iMax = i
    End If
  Next
  
End Sub

Sub FindMinFirstMaxLastIndex2(pa() As Variant, ByVal iLeft As Long, ByVal iRight As Long, ByRef iMin As Long, ByRef iMax As Long, ByRef bSorted As Boolean)
' процелура отыскивает методом линейного поиска индексы первого минимального и последнего максимального элементов
' в массиве pa() в позициях с iLeft (левая граница поиска) до iRight (правая граница поиска)
' дополнительно к FindMinFirstMaxLastIndex устанавливает флаг сортированности массива
' (Не используется в тесте)

  Dim v_Min As Variant, v_Max As Variant
  Dim v_Temp As Variant
  Dim i As Long
  
  bSorted = True
  
  v_Min = pa(iLeft)
  iMin = iLeft
  v_Max = pa(iLeft)
  iMax = iLeft
  
  For i = iLeft + 1 To iRight
    v_Temp = pa(i)
    If v_Temp < v_Min Then
    'при сортировке по возрастанию левый элемент первый среди равных
      v_Min = pa(i)
      iMin = i
      bSorted = False
    End If
    
    If v_Temp >= v_Max Then
      'при сортировке по возрастанию ставим правый элемент последний среди равных
      v_Max = pa(i)
      iMax = i
    End If
  Next
  
End Sub


Sub ShellSort_Shell(ByRef a() As Variant, ByVal iLeft As Long, ByVal iRight As Long)
'ваиант сортировки самого Шелла, с шагом h-сортировки, равным степеням двойки.
'не уходит от квадратичной зависимости.
'Приведен в исторических целях

Dim v As Variant
Dim i&, j&, h&
j = (iRight - iLeft) \ 4&
h = 1&
Do
  h = h + h
Loop While h <= j

Do While h > 0&
  For i = iLeft + h To iRight
    j = i
    v = a(i)
    Do While j >= iLeft + h
      If Less_V(v, a(j - h)) Then
        a(j) = a(j - h)
        j = j - h
      Else
        Exit Do
      End If
    Loop
    a(j) = v
  Next
  h = h \ 2&
Loop

End Sub

Sub ShellSort_Knuth(ByRef a() As Variant, ByVal iLeft As Long, ByVal iRight As Long)
' на основе исходных кодов Сэджвика https://www.cs.princeton.edu/~rs/shell/driver.c
' последовательность h-сортировок совпадает с последовательностью Пратта в англоязычной википедии, в которой нарастание идет до (iRight - iLeft) \ 3&
Dim v As Variant
Dim i&, j&, h&
j = (iRight - iLeft) \ 9&
h = 1&
Do
  h = 3 * h + 1
Loop While h <= j

Do While h > 0&
  For i = iLeft + h To iRight
    j = i
    v = a(i)
    Do While j >= iLeft + h
      If Less_V(v, a(j - h)) Then
        a(j) = a(j - h)
        j = j - h
      Else
        Exit Do
      End If
    Loop
    a(j) = v
  Next
  h = h \ 3&
Loop

End Sub

Sub ShellSort_Knuth_Sent(ByRef a() As Variant, ByVal iLeft As Long, ByVal iRight As Long)
' см. комментарий к ShellSort_Knuth
' отличия от ShellSort_Knuth:
' с целью исключения проверки j >= iLeft + h во внутреннем цикле жертвуется проход по массиву
' на котором выявляются позиции минимального и максимального элементов в массиве
' дополнительно к этому, проход на h=1 выделен в самостоятельный цикл.
Dim v As Variant
Dim i&, j&, h&
j = (iRight - iLeft) \ 9& '3& '9&
h = 1&
Do
  h = 3 * h + 1
Loop While h <= j

'поиск индексов минимального и максимального элементов
Dim iMinPos As Long, iMaxPos As Long
FindMinFirstMaxLastIndex a, iLeft, iRight, iMinPos, iMaxPos

If iLeft <> iMinPos Then
  'минимальный элемент в первую позицию
  Swap_VS a(iLeft), a(iMinPos)
End If

If iRight <> iMaxPos Then
  ' максимальный элемент в последнюю позицию
  Swap_VS a(iRight), a(iMaxPos)
End If

iRight = iRight - 1& ' правый элемент здесь на месте

Do While h > 1&
  For i = iLeft + h + 1 To iRight
    j = i
    v = a(i)
    Do
      If Less_V(v, a(j - h)) Then
        a(j) = a(j - h)
        j = j - h
      Else
        Exit Do
      End If
    Loop While j >= iLeft + h
    a(j) = v
  Next
  h = h \ 3&
Loop

' цикл для h = 1 выделяем в самостоятельный
' так как первый и последний элемент на своих местах, сдвигаем цикл на единицу
' в этой версии знаем, что первый (то есть нулевой) элемент точно на месте
For i = iLeft + 2 To iRight ' правый элемент здесь на месте
  j = i
  v = a(i)
  Do While Less_V(v, a(j - 1))
      a(j) = a(j - 1)
      j = j - 1
  Loop
  a(j) = v
Next
  
End Sub

Sub ShellSort_Knuth_Swapped(ByRef a() As Variant, ByVal iLeft As Long, ByVal iRight As Long)
' последовательность h-сортировок совпадает с последовательностью Пратта, в которой нарастание идет до (iRight - iLeft) \ 3&
'обменный вариант

Dim i&, j&, h&
j = (iRight - iLeft) \ 9&
h = 1&
Do
  h = 3 * h + 1
Loop While h <= j
'
Do While h > 0&
  For i = iLeft + h To iRight
    j = i
    Do While j >= iLeft + h
      If Less_V(a(j), a(j - h)) Then
        Swap_VS a(j - h), a(j)
        j = j - h
      Else
        Exit Do
      End If
    Loop
  Next
  h = h \ 3&
Loop

End Sub

Sub ShellSort_Gonnet(ByRef a() As Variant, ByVal iLeft As Long, ByVal iRight As Long)
' на основе исходных кодов Сэджвика https://www.cs.princeton.edu/~rs/shell/driver.c
' последовательность h-сортировок Gonnet 5/11
Dim v As Variant
Dim i&, j&, h&

h = iRight - iLeft + 1&
Do While h > 0&
    Do While h > 0&
      For i = iLeft + h To iRight
        j = i
        v = a(i)
        Do While j >= iLeft + h
          If Less_V(v, a(j - h)) Then
            a(j) = a(j - h)
            j = j - h
          Else
            Exit Do
          End If
        Loop
        a(j) = v
      Next
      h = h \ 3&
    Loop
  If h > 1& And h < 5& Then
    h = 1&
  Else
    h = (5 * h) \ 11
  End If
Loop
End Sub

Sub ShellSort_Sedg1(ByRef a() As Variant, ByVal iLeft As Long, ByVal iRight As Long)
' на основе исходных кодов Сэджвика https://www.cs.princeton.edu/~rs/shell/driver.c
' 1я последовательность Седжвика 1986г.   4^{k}+3*2^{k-1} + 1
Dim v As Variant
Dim i&, j&, h&, t&

t = 1&
While 4& * t * t < (iRight - iLeft)
  t = t + t
Wend
'
h = (iRight - iLeft) \ 4&
Do While t > 0&
      For i = iLeft + h To iRight
        j = i
        v = a(i)
        Do While j >= h
          If Less_V(v, a(j - h)) Then
            a(j) = a(j - h)
            j = j - h
          Else
            Exit Do
          End If
        Loop
        a(j) = v
      Next
  t = t \ 2&
  h = t * t - ((3& * t) \ 2) + 1&
Loop
End Sub

Sub ShellSort_Sedg1_Swapped(ByRef a() As Variant, ByVal iLeft As Long, ByVal iRight As Long)
' 1я последовательность Седжвика 1986г.   4^{k}+3*2^{k-1} + 1
' обменный вариант
'

Dim i&, j&, h&, t&

t = 1&
While 4& * t * t < (iRight - iLeft)
  t = t + t
Wend

h = (iRight - iLeft) \ 4&
Do While t > 0&
      For i = iLeft + h To iRight
        j = i
        Do While j >= h
          If Less_V(a(j), a(j - h)) Then
            Swap_VS a(j - h), a(j)
            j = j - h
          Else
            Exit Do
          End If
        Loop
      Next
  t = t \ 2&
  h = t * t - ((3& * t) \ 2) + 1&
Loop
End Sub

Sub ShellSort_Sedg1_Sent(ByRef a() As Variant, ByVal iLeft As Long, ByVal iRight As Long)
' 1я последовательность Седжвика 1986г.   4^{k}+3*2^{k-1} + 1
' оптимизации, аналогичные ShellSort_Knuth_Sent (см. комментарий)
' в данном случае они себя не оправдывают

Dim v As Variant
Dim i&, j&, h&, t&

'----------
t = 1&
While 4& * t * t < (iRight - iLeft)
  t = t + t
Wend

'поиск индексов минимального и максимального элементов
Dim iMinPos As Long, iMaxPos As Long ', bSorted As Boolean

FindMinFirstMaxLastIndex a, iLeft, iRight, iMinPos, iMaxPos ', bSorted
'FindMinFirstMaxLastIndex2 A, iLeft, iRight, iMinPos, iMaxPos, bSorted
'If bSorted Then
'   Exit Sub
'End If

If iLeft <> iMinPos Then
  'минимальный элемент в первую позицию
  Swap_VS a(iLeft), a(iMinPos)
End If

If iRight <> iMaxPos Then
  ' максимальный элемент в последнюю позицию
  Swap_VS a(iRight), a(iMaxPos)
End If

iRight = iRight - 1& ' правый элемент здесь на месте

h = (iRight + 1& - iLeft) \ 4&
Do While h > 1& And t > 0&
      For i = iLeft + h + 1 To iRight
        j = i
        v = a(i)
        Do While j >= h
          If Less_V(v, a(j - h)) Then
            a(j) = a(j - h)
            j = j - h
          Else
            Exit Do
          End If
        Loop
        a(j) = v
      Next

  t = t \ 2&
  h = t * t - ((3& * t) \ 2&) + 1&
Loop

' цикл для h = 1 выделяем в самостоятельный
' так как первый и последний элемент на своих местах, сдвигаем цикл на единицу
' в этой версии знаем, что первый (то есть нулевой) элемент точно на месте
For i = iLeft + 2 To iRight ' правый элемент здесь на месте
  j = i
  v = a(i)
  Do While Less_V(v, a(j - 1&))
      a(j) = a(j - 1&)
      j = j - 1&
  Loop
  a(j) = v
Next

End Sub

Sub ShellSort_Incerpi(ByRef a() As Variant, ByVal iLeft As Long, ByVal iRight As Long)
' на основе исходных кодов Сэджвика https://www.cs.princeton.edu/~rs/shell/driver.c
' последовательность h-сортировок совпадает с последовательностью A036569, Incerpi-Sedgewick-Knuth
Dim v As Variant
Dim i&, j&, h&, k&, t&
'-------------------
Static incs(0 To 15) As Long
If incs(0) = 0 Then
  incs(0) = 1391376
  incs(1) = 463792
  incs(2) = 198768
  incs(3) = 86961
  incs(4) = 33936
  incs(5) = 13776
  incs(6) = 4592
  incs(7) = 1968
  incs(8) = 861
  incs(9) = 336
  incs(10) = 112
  incs(11) = 48
  incs(12) = 21
  incs(13) = 7
  incs(14) = 3
  incs(15) = 1
End If

For k = 0 To 15
    h = incs(k)
    For i = iLeft + h To iRight
      j = i
      v = a(i)
      Do While j >= h
        If Less_V(v, a(j - h)) Then
          a(j) = a(j - h)
          j = j - h
        Else
          Exit Do
        End If
      Loop
      a(j) = v
    Next
Next
End Sub

'1, 4, 9, 20, 46, 103, 233, 525, 1182, 2660, 5985, 13467, 30301, 68178, 153401, 345152, 776591, 1747331, 3931496
Sub ShellSort_Tokuda(ByRef a() As Variant, ByVal iLeft As Long, ByVal iRight As Long)
' последовательность h-сортировок совпадает с последовательностью Tokuda A108870
Dim v As Variant
Dim i&, j&, h&, k&, t&

Static incs(0 To 18) As Long
If incs(0) = 0 Then
  incs(0) = 3931496
  incs(1) = 1747331
  incs(2) = 776591
  incs(3) = 345152
  incs(4) = 153401
  incs(5) = 68178
  incs(6) = 30301
  incs(7) = 13467
  incs(8) = 5985
  incs(9) = 2660
  incs(10) = 1182
  incs(11) = 525
  incs(12) = 233
  incs(13) = 103
  incs(14) = 46
  incs(15) = 20
  incs(16) = 9
  incs(17) = 4
  incs(18) = 1
End If

For k = 0 To 18
    h = incs(k)
    For i = iLeft + h To iRight
      j = i
      v = a(i)
      Do While j >= h
        If Less_V(v, a(j - h)) Then
          a(j) = a(j - h)
          j = j - h
        Else
          Exit Do
        End If
      Loop
      a(j) = v
    Next
Next

End Sub

'1, 4, 9, 20, 46, 103, 233, 525, 1182, 2660, 5985, 13467, 30301, 68178, 153401, 345152, 776591, 1747331, 3931496
Sub ShellSort_Tokuda_Swapped(ByRef a() As Variant, ByVal iLeft As Long, ByVal iRight As Long)
' последовательность h-сортировок совпадает с последовательностью Tokuda A108870
' обменный вариант

Dim v As Variant
Dim i&, j&, h&, k&, t&

Static incs(0 To 18) As Long
If incs(0) = 0 Then
  incs(0) = 3931496
  incs(1) = 1747331
  incs(2) = 776591
  incs(3) = 345152
  incs(4) = 153401
  incs(5) = 68178
  incs(6) = 30301
  incs(7) = 13467
  incs(8) = 5985
  incs(9) = 2660
  incs(10) = 1182
  incs(11) = 525
  incs(12) = 233
  incs(13) = 103
  incs(14) = 46
  incs(15) = 20
  incs(16) = 9
  incs(17) = 4
  incs(18) = 1
End If

For k = 0 To 18
    h = incs(k)
    For i = iLeft + h To iRight
      j = i
      Do While j >= h
        If Less_V(a(j), a(j - h)) Then
          Swap_VS a(j - h), a(j)
          j = j - h
        Else
          Exit Do
        End If
      Loop
    Next
Next

End Sub

Sub PrintResults(ByRef r As Range, ByVal vcName As String, ByVal nSize As Long, ByVal nTime1 As Double, ByVal nTime2 As Double)
'вывод результатов
  Static a(1 To 1, 1 To 4) As Variant
  If vcName <> "---------------------------------" Then
  a(1, 1) = vcName
  a(1, 2) = nSize
  a(1, 3) = nTime1
  a(1, 4) = nTime2
  Else
  a(1, 1) = vcName
  a(1, 2) = "-----"
  a(1, 3) = "-----"
  a(1, 4) = "-----"
  End If
  r.Value2 = a
  Set r = r.Offset(1, 0)
  
End Sub

Sub Test_shellsort(ByRef r As Range)
'тест производительности вариантов сортировки
  Dim a_sizes
  ' этот тест больше 16 минут
  a_sizes = Array(127, 323, 600, 1024, 2048, 4096, 8192, 12500, 25000, 50001, 66535, 88446, 128247, 189958, 269839, 539278, 728025, 1024& * 1024) ', 910031)
  
  ' около  3х минут
  'a_sizes = Array(127, 323, 600, 1024, 2048, 4096, 8192, 12500, 25000, 50001, 66535, 88446, 128247, 189958) ', 269839), 539278, 728025, 1024& * 1024) ', 910031)
  
  Dim dTime As Double
  Dim a_src() As Variant
  Dim a() As Variant
  Dim iSize&
  
  Dim s&
  
  For s = 0 To UBound(a_sizes)
  
  Randomize a_sizes(s)
  randArray a_src, a_sizes(s) 'iSize
    
  iSize = a_sizes(s)
  
  If iSize < 150000 Then
  'исходный вариант Шелла квдратичный по времени, поэтому показываем его не более чем до 150000 элементов
    copyArray a_src, a
    dTime = MicroTimer
    ShellSort_Shell a, 0, iSize - 1
    dTime = MicroTimer - dTime
    PrintResults r, "ShellSort_Shell", iSize, dTime, dTime * 1000000 / iSize
  End If
  
  copyArray a_src, a
  dTime = MicroTimer
  ShellSort_Knuth a, 0, iSize - 1
  dTime = MicroTimer - dTime
  PrintResults r, "ShellSort_Knuth", iSize, dTime, dTime * 1000000 / iSize
    
  copyArray a_src, a
  dTime = MicroTimer
  ShellSort_Knuth_Sent a, 0, iSize - 1
  dTime = MicroTimer - dTime
  PrintResults r, "ShellSort_Knuth_Sent", iSize, dTime, dTime * 1000000 / iSize
  
  copyArray a_src, a
  dTime = MicroTimer
  ShellSort_Knuth_Swapped a, 0, iSize - 1
  dTime = MicroTimer - dTime
  PrintResults r, "ShellSort_Knuth_Swapped", iSize, dTime, dTime * 1000000 / iSize
  '
  copyArray a_src, a
  dTime = MicroTimer
  ShellSort_Sedg1_Swapped a, 0, iSize - 1
  dTime = MicroTimer - dTime
  PrintResults r, "ShellSort_Sedg1_Swapped", iSize, dTime, dTime * 1000000 / iSize
  '
  copyArray a_src, a
  dTime = MicroTimer
  ShellSort_Sedg1 a, 0, iSize - 1
  dTime = MicroTimer - dTime
  PrintResults r, "ShellSort_Sedge1", iSize, dTime, dTime * 1000000 / iSize
  '
  copyArray a_src, a
  dTime = MicroTimer
  ShellSort_Sedg1_Sent a, 0, iSize - 1
  dTime = MicroTimer - dTime
  PrintResults r, "ShellSort_Sedge1_Sent", iSize, dTime, dTime * 1000000 / iSize
  '
  copyArray a_src, a
  dTime = MicroTimer
  ShellSort_Gonnet a, 0, iSize - 1
  dTime = MicroTimer - dTime
  PrintResults r, "ShellSort_Gonnet", iSize, dTime, dTime * 1000000 / iSize
  '
  copyArray a_src, a
  dTime = MicroTimer
  ShellSort_Incerpi a, 0, iSize - 1
  dTime = MicroTimer - dTime
  PrintResults r, "ShellSort_Incerpi", iSize, dTime, dTime * 1000000 / iSize
  '
  copyArray a_src, a
  dTime = MicroTimer
  ShellSort_Tokuda a, 0, iSize - 1
  dTime = MicroTimer - dTime
  PrintResults r, "ShellSort_Tokuda", iSize, dTime, dTime * 1000000 / iSize
  '
  copyArray a_src, a
  dTime = MicroTimer
  ShellSort_Tokuda_Swapped a, 0, iSize - 1
  dTime = MicroTimer - dTime
  PrintResults r, "ShellSort_Tokuda_Swapped", iSize, dTime, dTime * 1000000 / iSize
  '
  
  If iSize > 157 Then
  
  ' работа с почти сортированными массивами
  ' имитация работы с почти сортированным массивом (3 перестановки)
  If iSize > 37 Then
    Swap_VS a(23), a(37)
    If iSize > 157 Then
      Swap_VS a(123), a(157)
      If iSize > 500 Then
        Swap_VS a(323), a(477)
      End If
    End If
  End If
  dTime = MicroTimer
  ShellSort_Knuth a, 0, iSize - 1
  dTime = MicroTimer - dTime
  PrintResults r, "ShellSort_Knuth почти сортирован", iSize, dTime, dTime * 1000000 / iSize
  
  ' имитация работы с почти сортированным массивом (3 перестановки)
  If iSize > 37 Then
    Swap_VS a(23), a(37)
    If iSize > 157 Then
      Swap_VS a(123), a(157)
      If iSize > 500 Then
        Swap_VS a(323), a(477)
      End If
    End If
  End If
  dTime = MicroTimer
  ShellSort_Knuth_Sent a, 0, iSize - 1
  dTime = MicroTimer - dTime
  PrintResults r, "ShellSort_Knuth_Sent почти сортирован", iSize, dTime, dTime * 1000000 / iSize
    
  ' имитация работы с почти сортированным массивом (3 перестановки)
  If iSize > 37 Then
    Swap_VS a(23), a(37)
    If iSize > 157 Then
      Swap_VS a(123), a(157)
      If iSize > 500 Then
        Swap_VS a(323), a(477)
      End If
    End If
  End If
  dTime = MicroTimer
  ShellSort_Knuth_Swapped a, 0, iSize - 1
  dTime = MicroTimer - dTime
  PrintResults r, "ShellSort_Knuth_Swapped почти сортирован", iSize, dTime, dTime * 1000000 / iSize
   
   ' имитация работы с почти сортированным массивом (3 перестановки)
  If iSize > 37 Then
    Swap_VS a(23), a(37)
    If iSize > 157 Then
      Swap_VS a(123), a(157)
      If iSize > 500 Then
        Swap_VS a(323), a(477)
      End If
    End If
  End If
  dTime = MicroTimer
  ShellSort_Sedg1_Swapped a, 0, iSize - 1
  dTime = MicroTimer - dTime
  PrintResults r, "ShellSort_Sedg1_Swapped почти сортирован", iSize, dTime, dTime * 1000000 / iSize
   
   ' имитация работы с почти сортированным массивом (3 перестановки)
  If iSize > 37 Then
    Swap_VS a(23), a(37)
    If iSize > 157 Then
      Swap_VS a(123), a(157)
      If iSize > 500 Then
        Swap_VS a(323), a(477)
      End If
    End If
  End If
  dTime = MicroTimer
  ShellSort_Sedg1 a, 0, iSize - 1
  dTime = MicroTimer - dTime
  PrintResults r, "ShellSort_Sedg1 почти сортирован", iSize, dTime, dTime * 1000000 / iSize
  
  ' имитация работы с почти сортированным массивом (3 перестановки)
  If iSize > 37 Then
    Swap_VS a(23), a(37)
    If iSize > 157 Then
      Swap_VS a(123), a(157)
      If iSize > 500 Then
        Swap_VS a(323), a(477)
      End If
    End If
  End If
  dTime = MicroTimer
  ShellSort_Tokuda a, 0, iSize - 1
  dTime = MicroTimer - dTime
  PrintResults r, "ShellSort_Tokuda почти сортирован", iSize, dTime, dTime * 1000000 / iSize
  
  ' имитация работы с почти сортированным массивом (3 перестановки)
  If iSize > 37 Then
    Swap_VS a(23), a(37)
    If iSize > 157 Then
      Swap_VS a(123), a(157)
      If iSize > 500 Then
        Swap_VS a(323), a(477)
      End If
    End If
  End If
  dTime = MicroTimer
  ShellSort_Tokuda_Swapped a, 0, iSize - 1
  dTime = MicroTimer - dTime
  PrintResults r, "ShellSort_Tokuda_Swapped почти сортирован", iSize, dTime, dTime * 1000000 / iSize
  End If
  '-----------------------------------------------------------
  PrintResults r, "---------------------------------", 0, 0, 0

  Next
End Sub



Может быть кому-то всё это окажется интересным.
И, даже, может быть, кто-то, приложит файл, заполненный результатами прогона на совем, более быстром компьютере.
(При счете новые результаты полностью затирают старые)
...
Рейтинг: 0 / 0
сортировка Шелла на VBA, сравнение производительности различных последовательностей.
    #39829622
booby
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
booby,

окажется -> покажется, совем -> своём
...
Рейтинг: 0 / 0
сортировка Шелла на VBA, сравнение производительности различных последовательностей.
    #39829652
Predeclared
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Результат на моей железке:
...
Рейтинг: 0 / 0
сортировка Шелла на VBA, сравнение производительности различных последовательностей.
    #39829653
Predeclared
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
И файлик:
...
Рейтинг: 0 / 0
сортировка Шелла на VBA, сравнение производительности различных последовательностей.
    #39829655
booby
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Predeclared,

Спасибо!
:)
Первое впечатление - хорошая железка!
По "почти сортировкам" втрое лучше мой, навскидку, по просто сортировкам - вдвое.
Как-то надо будет это осмыслить...
:))

Спасибо.
...
Рейтинг: 0 / 0
сортировка Шелла на VBA, сравнение производительности различных последовательностей.
    #39829660
booby
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Predeclared,

Одну деталь увидел:
На твоем суперкомпьютере вариант последовательности Tokuda обгоняет
Кнуто-Пратто-Седжвикову тройку+1 для "случайного" заполнения начиная с самого первого
установленного значения размера массива в 127 элементов.

Хотя на малых числах здравый смысл голосует за общую простоту кода, что на моём медленном amd подтверждается, где троечный плюс 1 Кнут-Пратт-Сэджвик склонен выигрывать.

Косвенно это подтверждается маргинально лучшим временем этого варианта в твоём прогоне
для "почти сортированного" массива.
Это я к тому, что я теоретически не хочу менять код на своих условиях и размерах.
А твои результаты вносят малое смущение в моё теоретическое вероисповедание.
...
Рейтинг: 0 / 0
сортировка Шелла на VBA, сравнение производительности различных последовательностей.
    #39829663
booby
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
booby,

склонен выигрывать -> склонен выигрывать на совсем малых размерах массива.
...
Рейтинг: 0 / 0
сортировка Шелла на VBA, сравнение производительности различных последовательностей.
    #39829667
Predeclared
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
booby... А твои результаты вносят малое смущение в моё теоретическое вероисповедание.

Вот тут я могу только либо поздравить, либо посочувствовать,
потому как сильно далек и от теории, и от практики в этой области.

Есть у меня "алюминька", потенциально в 1,5 раза быстрее "железки",
но на ней я еще офис не ставил.
Если результаты теста на ней помогут побороть смущение,
я могу таки залить офис и потестить.

Надо ли?
...
Рейтинг: 0 / 0
сортировка Шелла на VBA, сравнение производительности различных последовательностей.
    #39829668
booby
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Predeclared,

специально для меня не надо.
Со своим смущением я как-нибудь сам справлюсь.

А за проявленное любопытство в любом случае спасибо.
Я для себя, в конечном счёте, оставлял, чтобы не потерять код....
как уже несколько раз бывало...
И в надежде, что модераторы не удалят топик за отсутствием вопроса немедленно...

А наличие читателя укрепляет себя в себе самом на завтра.
О чём с благодарностью и сообщаю.

PS
Что-то дёргаюсь я в последнее время порывисто.
Чёрт манит открыть топик по вопросам отдельных алгоритмов на VBA.
В некотором смысле, это воскресная проба пера в чёрный день.
Посмотрим, додёргает он меня меня, или вбок отойдёт...
...
Рейтинг: 0 / 0
сортировка Шелла на VBA, сравнение производительности различных последовательностей.
    #39829673
booby
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
booby,

но какой-то минорный эффект есть, для которого у меня нет немедленного понимания.
На "современном" компьютере исходный вариант Шелла замедляется медленнее, чем на "устаревшем", как и относительная скорость провала обменных вариантов.

Пока нет ясной модели в голове - у "современного" настолько больше процессорный кэш,
чтобы поглотить алгоритмические эффекты, или здесь нужно другое объяснение.
...
Рейтинг: 0 / 0
сортировка Шелла на VBA, сравнение производительности различных последовательностей.
    #39829674
booby
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
booby,

медленнее -> относительно медленнее
...
Рейтинг: 0 / 0
сортировка Шелла на VBA, сравнение производительности различных последовательностей.
    #39829681
Фотография vikkiv
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
вроде как это классика из серии ёжики и кактус?

понятно что подраздел специфичный именно под офис но VBA ведь интерпретируемый (по большей части)?

у меня на виртуальной с 2мя ядрами i7-8700 такой результат получился
(не знаю что он значит): Îáùåå âðåìÿ ðàáîòû - ìèíóò: 8 ñåêóíä: 39
(P.P.S. - о, а в preview иероглифы из Excel в кирилицу перевелись
)
П.С. перевёл здесь : Общее время работы - минут: 8 секунд: 39


во вторых неизвестно какие наборы инструкций процессора там на заднем плане
используются, если только SSE {даже последних версий 4.2} то у них
по сравнению с AVX производительность хуже больше чем в 2 раза.
(а у AVX против AVX2 тоже разница в 2 раза минимум)

причём у Intel есть отдельные MKL библиотеки оптимизаций под векторные задачи

кроме того я что-то не сильно заметил рост использования памяти
(max ушло 100 MB на Excel, хотя может и массивы не такие уж большие),
а процессор был загружен примерно на 50% всё время расчётов (хорошо хоть
оба ядра задействовались предоставленных VM,
т.е. исполнение вроде параллельное {что как оказалось - неверно, детали в конце})

это к тому что проблемы с реализацией могут быть как и в самом алгоритме/коде
(на уровне нюансов интерпретации в машинный код) так и в том как VBA
(который не сильно меняется уже много лет) работает с современным железом
так что большие вопросы в какого качества там P-Code это компилируется

кстати в Wiki пишут что Office 2013й и 2016й идут с одной и той-же версией VBA (7.1)
который не так уж и далеко ушел от Office 2010 с его VBA версией 7.0
и уж в 2010м Office остался практически без изменений (за искл. поддержки 64 битности)
по сравнению с Office 2007 который поставлялся с VBA 6.5
(на котором Microsoft прекратил выдавать лицензии на внешнее использование)

VB.NET вполне ещё развивают и поддерживают обновляя библиотеки, а VBA от него совсем
на другом пути развития/поддержки (так что не стоит от него ждать чего-то особенного).
в смысле не надейтесь на многое (по тому что происходит на заднем плане в машинном коде)

когда-то у них было отдельные попытки вынести расчёты в HPC , но вроде только для Office 2010


под конец нагуглил - VBA ещё как пишут на многих форумах оказывается ещё и однопоточный,
так что похоже ядра (много) не так уж и важны,

в завершении выключил виртуалку, добавил туда ещё 4 ядра
(всего стало 6) и оперативки (поднял до 16ти GB)
так использование памяти в Excel так и осталось как и при 8Gb (т.е. 100 МB)
а загрузка процессора упала до 17%
(при этом даже никакие 2 ядра не использовались одновременно как до этого)

результат получился такой: Îáùåå âðåìÿ ðàáîòû - ìèíóò: 8 ñåêóíä: 37

т.е. больше памяти и ядер, а результат такой-же.


Îáùåå âðåìÿ ðàáîòû - ìèíóò: 8 ñåêóíä: 37 VM: 6-cores of i7-8700 / DDR4 2666 - 16Gb / M2.0 NVMe
Вариант процедурыразмер массиваВремя работыМикросекунд на элемент массиваShellSort_Shell1270.00047173.7142ShellSort_Knuth1270.00049513.8984ShellSort_Knuth_Sent1270.00042573.3520ShellSort_Knuth_Swapped1270.00046143.6331ShellSort_Sedg1_Swapped1270.00042113.3157ShellSort_Sedge11270.00033772.6591ShellSort_Sedge1_Sent1270.00039993.1488ShellSort_Gonnet1270.00034522.7181ShellSort_Incerpi1270.00030752.4213ShellSort_Tokuda1270.00029812.3472ShellSort_Tokuda_Swapped1270.00034732.7346------------------------------------------------ShellSort_Shell3230.00152414.7186ShellSort_Knuth3230.00103143.1932ShellSort_Knuth_Sent3230.00098083.0365ShellSort_Knuth_Swapped3230.00133384.1294ShellSort_Sedg1_Swapped3230.00130744.0477ShellSort_Sedge13230.00103483.2037ShellSort_Sedge1_Sent3230.00108063.3455ShellSort_Gonnet3230.00098343.0446ShellSort_Incerpi3230.00099543.0817ShellSort_Tokuda3230.00093972.9093ShellSort_Tokuda_Swapped3230.00109733.3972ShellSort_Knuth ïî÷òè ñîðòèðîâàí3230.00037221.1523ShellSort_Knuth_Sent ïî÷òè ñîðòèðîâàí3230.00038871.2034ShellSort_Knuth_Swapped ïî÷òè ñîðòèðîâàí3230.00032671.0115ShellSort_Sedg1_Swapped ïî÷òè ñîðòèðîâàí3230.00039041.2087ShellSort_Sedg1 ïî÷òè ñîðòèðîâàí3230.00043311.3409ShellSort_Tokuda ïî÷òè ñîðòèðîâàí3230.00055251.7105ShellSort_Tokuda_Swapped ïî÷òè ñîðòèðîâàí3230.00047421.4681------------------------------------------------ShellSort_Shell6000.00361776.0295ShellSort_Knuth6000.00218293.6382ShellSort_Knuth_Sent6000.00214253.5708ShellSort_Knuth_Swapped6000.00277854.6308ShellSort_Sedg1_Swapped6000.00303555.0592ShellSort_Sedge16000.00228493.8082ShellSort_Sedge1_Sent6000.00227893.7982ShellSort_Gonnet6000.00199643.3273ShellSort_Incerpi6000.00205413.4235ShellSort_Tokuda6000.00202443.3740ShellSort_Tokuda_Swapped6000.00238003.9667ShellSort_Knuth ïî÷òè ñîðòèðîâàí6000.00088911.4818ShellSort_Knuth_Sent ïî÷òè ñîðòèðîâàí6000.00087821.4637ShellSort_Knuth_Swapped ïî÷òè ñîðòèðîâàí6000.00079451.3242ShellSort_Sedg1_Swapped ïî÷òè ñîðòèðîâàí6000.00078551.3092ShellSort_Sedg1 ïî÷òè ñîðòèðîâàí6000.00087371.4562ShellSort_Tokuda ïî÷òè ñîðòèðîâàí6000.00119911.9985ShellSort_Tokuda_Swapped ïî÷òè ñîðòèðîâàí6000.00107731.7955------------------------------------------------ShellSort_Shell10240.00733217.1603ShellSort_Knuth10240.00410224.0061ShellSort_Knuth_Sent10240.00393253.8403ShellSort_Knuth_Swapped10240.00527915.1554ShellSort_Sedg1_Swapped10240.00630686.1590ShellSort_Sedge110240.00464974.5407ShellSort_Sedge1_Sent10240.00475634.6448ShellSort_Gonnet10240.00445224.3479ShellSort_Incerpi10240.00392623.8342ShellSort_Tokuda10240.00388643.7953ShellSort_Tokuda_Swapped10240.00454644.4398ShellSort_Knuth ïî÷òè ñîðòèðîâàí10240.00155261.5162ShellSort_Knuth_Sent ïî÷òè ñîðòèðîâàí10240.00147631.4417ShellSort_Knuth_Swapped ïî÷òè ñîðòèðîâàí10240.00140421.3713ShellSort_Sedg1_Swapped ïî÷òè ñîðòèðîâàí10240.00125961.2301ShellSort_Sedg1 ïî÷òè ñîðòèðîâàí10240.00145451.4204ShellSort_Tokuda ïî÷òè ñîðòèðîâàí10240.00212922.0793ShellSort_Tokuda_Swapped ïî÷òè ñîðòèðîâàí10240.00183571.7927------------------------------------------------ShellSort_Shell20480.01970489.6215ShellSort_Knuth20480.01025455.0071ShellSort_Knuth_Sent20480.00968894.7309ShellSort_Knuth_Swapped20480.01312216.4073ShellSort_Sedg1_Swapped20480.01312106.4067ShellSort_Sedge120480.00992524.8463ShellSort_Sedge1_Sent20480.01022634.9933ShellSort_Gonnet20480.00957094.6733ShellSort_Incerpi20480.00934084.5609ShellSort_Tokuda20480.00859704.1978ShellSort_Tokuda_Swapped20480.01027075.0150ShellSort_Knuth ïî÷òè ñîðòèðîâàí20480.00342491.6723ShellSort_Knuth_Sent ïî÷òè ñîðòèðîâàí20480.00337391.6474ShellSort_Knuth_Swapped ïî÷òè ñîðòèðîâàí20480.00296361.4471ShellSort_Sedg1_Swapped ïî÷òè ñîðòèðîâàí20480.00283911.3863ShellSort_Sedg1 ïî÷òè ñîðòèðîâàí20480.00333701.6294ShellSort_Tokuda ïî÷òè ñîðòèðîâàí20480.00463612.2637ShellSort_Tokuda_Swapped ïî÷òè ñîðòèðîâàí20480.00396611.9366------------------------------------------------ShellSort_Shell40960.041961710.2446ShellSort_Knuth40960.02281035.5689ShellSort_Knuth_Sent40960.02193975.3564ShellSort_Knuth_Swapped40960.02965737.2406ShellSort_Sedg1_Swapped40960.03167797.7339ShellSort_Sedge140960.02337585.7070ShellSort_Sedge1_Sent40960.02413075.8913ShellSort_Gonnet40960.02312175.6449ShellSort_Incerpi40960.02147375.2426ShellSort_Tokuda40960.01949144.7586ShellSort_Tokuda_Swapped40960.02316155.6547ShellSort_Knuth ïî÷òè ñîðòèðîâàí40960.00793531.9373ShellSort_Knuth_Sent ïî÷òè ñîðòèðîâàí40960.00766091.8703ShellSort_Knuth_Swapped ïî÷òè ñîðòèðîâàí40960.00662351.6171ShellSort_Sedg1_Swapped ïî÷òè ñîðòèðîâàí40960.00562551.3734ShellSort_Sedg1 ïî÷òè ñîðòèðîâàí40960.00671541.6395ShellSort_Tokuda ïî÷òè ñîðòèðîâàí40960.01032682.5212ShellSort_Tokuda_Swapped ïî÷òè ñîðòèðîâàí40960.00869422.1226------------------------------------------------ShellSort_Shell81920.132608116.1875ShellSort_Knuth81920.05333536.5107ShellSort_Knuth_Sent81920.05097656.2227ShellSort_Knuth_Swapped81920.06995058.5389ShellSort_Sedg1_Swapped81920.07158928.7389ShellSort_Sedge181920.05192826.3389ShellSort_Sedge1_Sent81920.05424836.6221ShellSort_Gonnet81920.05817587.1015ShellSort_Incerpi81920.04792555.8503ShellSort_Tokuda81920.04470875.4576ShellSort_Tokuda_Swapped81920.05280996.4465ShellSort_Knuth ïî÷òè ñîðòèðîâàí81920.01616091.9728ShellSort_Knuth_Sent ïî÷òè ñîðòèðîâàí81920.01571331.9181ShellSort_Knuth_Swapped ïî÷òè ñîðòèðîâàí81920.01368131.6701ShellSort_Sedg1_Swapped ïî÷òè ñîðòèðîâàí81920.01299621.5865ShellSort_Sedg1 ïî÷òè ñîðòèðîâàí81920.01542331.8827ShellSort_Tokuda ïî÷òè ñîðòèðîâàí81920.02246952.7429ShellSort_Tokuda_Swapped ïî÷òè ñîðòèðîâàí81920.01902882.3229------------------------------------------------ShellSort_Shell125000.241291819.3033ShellSort_Knuth125000.09237047.3896ShellSort_Knuth_Sent125000.08834977.0680ShellSort_Knuth_Swapped125000.11959069.5672ShellSort_Sedg1_Swapped125000.11728179.3825ShellSort_Sedge1125000.08532386.8259ShellSort_Sedge1_Sent125000.08914827.1319ShellSort_Gonnet125000.09236767.3894ShellSort_Incerpi125000.07593726.0750ShellSort_Tokuda125000.07058285.6466ShellSort_Tokuda_Swapped125000.08411196.7290ShellSort_Knuth ïî÷òè ñîðòèðîâàí125000.02743922.1951ShellSort_Knuth_Sent ïî÷òè ñîðòèðîâàí125000.02654302.1234ShellSort_Knuth_Swapped ïî÷òè ñîðòèðîâàí125000.02402901.9223ShellSort_Sedg1_Swapped ïî÷òè ñîðòèðîâàí125000.01962791.5702ShellSort_Sedg1 ïî÷òè ñîðòèðîâàí125000.02326851.8615ShellSort_Tokuda ïî÷òè ñîðòèðîâàí125000.03547862.8383ShellSort_Tokuda_Swapped ïî÷òè ñîðòèðîâàí125000.02957702.3662------------------------------------------------ShellSort_Shell250000.675273027.0109ShellSort_Knuth250000.21870648.7483ShellSort_Knuth_Sent250000.21083218.4333ShellSort_Knuth_Swapped250000.293237111.7295ShellSort_Sedg1_Swapped250000.250260110.0104ShellSort_Sedge1250000.18478847.3915ShellSort_Sedge1_Sent250000.19116377.6465ShellSort_Gonnet250000.20564988.2260ShellSort_Incerpi250000.17028416.8114ShellSort_Tokuda250000.15998626.3994ShellSort_Tokuda_Swapped250000.19032827.6131ShellSort_Knuth ïî÷òè ñîðòèðîâàí250000.05704952.2820ShellSort_Knuth_Sent ïî÷òè ñîðòèðîâàí250000.05494482.1978ShellSort_Knuth_Swapped ïî÷òè ñîðòèðîâàí250000.04836631.9347ShellSort_Sedg1_Swapped ïî÷òè ñîðòèðîâàí250000.04486431.7946ShellSort_Sedg1 ïî÷òè ñîðòèðîâàí250000.05297072.1188ShellSort_Tokuda ïî÷òè ñîðòèðîâàí250000.07730173.0921ShellSort_Tokuda_Swapped ïî÷òè ñîðòèðîâàí250000.06492892.5972------------------------------------------------ShellSort_Shell500011.654783933.0950ShellSort_Knuth500010.49580209.9158ShellSort_Knuth_Sent500010.48286029.6570ShellSort_Knuth_Swapped500010.684138013.6825ShellSort_Sedg1_Swapped500010.569509611.3900ShellSort_Sedge1500010.41425578.2849ShellSort_Sedge1_Sent500010.43345158.6689ShellSort_Gonnet500010.43610298.7219ShellSort_Incerpi500010.37670947.5340ShellSort_Tokuda500010.33757176.7513ShellSort_Tokuda_Swapped500010.41385358.2769ShellSort_Knuth ïî÷òè ñîðòèðîâàí500010.12673012.5346ShellSort_Knuth_Sent ïî÷òè ñîðòèðîâàí500010.12459922.4919ShellSort_Knuth_Swapped ïî÷òè ñîðòèðîâàí500010.10593142.1186ShellSort_Sedg1_Swapped ïî÷òè ñîðòèðîâàí500010.09185431.8370ShellSort_Sedg1 ïî÷òè ñîðòèðîâàí500010.10888172.1776ShellSort_Tokuda ïî÷òè ñîðòèðîâàí500010.16689493.3378ShellSort_Tokuda_Swapped ïî÷òè ñîðòèðîâàí500010.14014932.8029------------------------------------------------ShellSort_Shell665352.802897642.1267ShellSort_Knuth665350.673690710.1254ShellSort_Knuth_Sent665350.65639119.8654ShellSort_Knuth_Swapped665350.952568714.3168ShellSort_Sedg1_Swapped665350.807242112.1326ShellSort_Sedge1665350.59602958.9581ShellSort_Sedge1_Sent665350.62561259.4028ShellSort_Gonnet665350.693737910.4267ShellSort_Incerpi665350.54498448.1909ShellSort_Tokuda665350.48436307.2798ShellSort_Tokuda_Swapped665350.56414578.4789ShellSort_Knuth ïî÷òè ñîðòèðîâàí665350.16748832.5173ShellSort_Knuth_Sent ïî÷òè ñîðòèðîâàí665350.16175372.4311ShellSort_Knuth_Swapped ïî÷òè ñîðòèðîâàí665350.14102722.1196ShellSort_Sedg1_Swapped ïî÷òè ñîðòèðîâàí665350.13210581.9855ShellSort_Sedg1 ïî÷òè ñîðòèðîâàí665350.15818362.3774ShellSort_Tokuda ïî÷òè ñîðòèðîâàí665350.22632183.4015ShellSort_Tokuda_Swapped ïî÷òè ñîðòèðîâàí665350.19029382.8601------------------------------------------------ShellSort_Shell884464.737400053.5626ShellSort_Knuth884460.997265711.2754ShellSort_Knuth_Sent884460.960966610.8650ShellSort_Knuth_Swapped884461.369369515.4825ShellSort_Sedg1_Swapped884461.068708812.0832ShellSort_Sedge1884460.78513388.8770ShellSort_Sedge1_Sent884460.80748389.1297ShellSort_Gonnet884460.947004410.7071ShellSort_Incerpi884460.73420748.3012ShellSort_Tokuda884460.64133727.2512ShellSort_Tokuda_Swapped884460.76643018.6655ShellSort_Knuth ïî÷òè ñîðòèðîâàí884460.22435012.5366ShellSort_Knuth_Sent ïî÷òè ñîðòèðîâàí884460.21669242.4500ShellSort_Knuth_Swapped ïî÷òè ñîðòèðîâàí884460.18879972.1346ShellSort_Sedg1_Swapped ïî÷òè ñîðòèðîâàí884460.17667371.9975ShellSort_Sedg1 ïî÷òè ñîðòèðîâàí884460.21192022.3960ShellSort_Tokuda ïî÷òè ñîðòèðîâàí884460.31195593.5271ShellSort_Tokuda_Swapped ïî÷òè ñîðòèðîâàí884460.26388052.9835------------------------------------------------ShellSort_Shell1282478.153047263.5730ShellSort_Knuth1282471.542278412.0258ShellSort_Knuth_Sent1282471.491803411.6323ShellSort_Knuth_Swapped1282472.104389716.4089ShellSort_Sedg1_Swapped1282471.673724413.0508ShellSort_Sedge11282471.20693069.4110ShellSort_Sedge1_Sent1282471.24608249.7163ShellSort_Gonnet1282471.468712211.4522ShellSort_Incerpi1282471.09040348.5024ShellSort_Tokuda1282470.96580137.5308ShellSort_Tokuda_Swapped1282471.16039709.0481ShellSort_Knuth ïî÷òè ñîðòèðîâàí1282470.35362662.7574ShellSort_Knuth_Sent ïî÷òè ñîðòèðîâàí1282470.34428572.6846ShellSort_Knuth_Swapped ïî÷òè ñîðòèðîâàí1282470.29871232.3292ShellSort_Sedg1_Swapped ïî÷òè ñîðòèðîâàí1282470.25806212.0122ShellSort_Sedg1 ïî÷òè ñîðòèðîâàí1282470.30888982.4086ShellSort_Tokuda ïî÷òè ñîðòèðîâàí1282470.46854033.6534ShellSort_Tokuda_Swapped ïî÷òè ñîðòèðîâàí1282470.39685843.0945------------------------------------------------ShellSort_Knuth1899582.446220412.8777ShellSort_Knuth_Sent1899582.363908312.4444ShellSort_Knuth_Swapped1899583.343823217.6030ShellSort_Sedg1_Swapped1899582.568641613.5222ShellSort_Sedge11899581.85883349.7855ShellSort_Sedge1_Sent1899581.916641310.0898ShellSort_Gonnet1899582.116215011.1404ShellSort_Incerpi1899581.68010588.8446ShellSort_Tokuda1899581.54408168.1285ShellSort_Tokuda_Swapped1899581.86850469.8364ShellSort_Knuth ïî÷òè ñîðòèðîâàí1899580.56278492.9627ShellSort_Knuth_Sent ïî÷òè ñîðòèðîâàí1899580.53593452.8213ShellSort_Knuth_Swapped ïî÷òè ñîðòèðîâàí1899580.47207262.4851ShellSort_Sedg1_Swapped ïî÷òè ñîðòèðîâàí1899580.41413032.1801ShellSort_Sedg1 ïî÷òè ñîðòèðîâàí1899580.46411962.4433ShellSort_Tokuda ïî÷òè ñîðòèðîâàí1899580.71931473.7867ShellSort_Tokuda_Swapped ïî÷òè ñîðòèðîâàí1899580.60925853.2073------------------------------------------------ShellSort_Knuth2698393.832044114.2012ShellSort_Knuth_Sent2698393.714049113.7639ShellSort_Knuth_Swapped2698395.296186919.6272ShellSort_Sedg1_Swapped2698393.749183313.8941ShellSort_Sedge12698392.746420210.1780ShellSort_Sedge1_Sent2698392.811505210.4192ShellSort_Gonnet2698394.201704215.5712ShellSort_Incerpi2698392.50544299.2850ShellSort_Tokuda2698392.18555118.0995ShellSort_Tokuda_Swapped2698392.64527269.8032ShellSort_Knuth ïî÷òè ñîðòèðîâàí2698390.81230243.0103ShellSort_Knuth_Sent ïî÷òè ñîðòèðîâàí2698390.78093432.8941ShellSort_Knuth_Swapped ïî÷òè ñîðòèðîâàí2698390.68477752.5377ShellSort_Sedg1_Swapped ïî÷òè ñîðòèðîâàí2698390.59826442.2171ShellSort_Sedg1 ïî÷òè ñîðòèðîâàí2698390.71426252.6470ShellSort_Tokuda ïî÷òè ñîðòèðîâàí2698391.05886833.9241ShellSort_Tokuda_Swapped ïî÷òè ñîðòèðîâàí2698390.89577853.3197------------------------------------------------ShellSort_Knuth5392788.806866416.3308ShellSort_Knuth_Sent5392788.556544715.8667ShellSort_Knuth_Swapped53927812.477130823.1367ShellSort_Sedg1_Swapped5392788.178620015.1659ShellSort_Sedge15392785.906939110.9534ShellSort_Sedge1_Sent5392786.097333011.3065ShellSort_Gonnet5392788.611139615.9679ShellSort_Incerpi5392785.34229439.9064ShellSort_Tokuda5392784.66057808.6423ShellSort_Tokuda_Swapped5392785.666162210.5069ShellSort_Knuth ïî÷òè ñîðòèðîâàí5392781.66442023.0864ShellSort_Knuth_Sent ïî÷òè ñîðòèðîâàí5392781.59631302.9601ShellSort_Knuth_Swapped ïî÷òè ñîðòèðîâàí5392781.39917122.5945ShellSort_Sedg1_Swapped ïî÷òè ñîðòèðîâàí5392781.21133562.2462ShellSort_Sedg1 ïî÷òè ñîðòèðîâàí5392781.45259442.6936ShellSort_Tokuda ïî÷òè ñîðòèðîâàí5392782.24336034.1599ShellSort_Tokuda_Swapped ïî÷òè ñîðòèðîâàí5392781.93312373.5847------------------------------------------------ShellSort_Knuth72802512.336017316.9445ShellSort_Knuth_Sent72802511.867966616.3016ShellSort_Knuth_Swapped72802517.055591223.4272ShellSort_Sedg1_Swapped72802511.383084415.6356ShellSort_Sedge17280258.286076511.3816ShellSort_Sedge1_Sent7280258.727400311.9878ShellSort_Gonnet72802512.675999617.4115ShellSort_Incerpi7280257.376207410.1318ShellSort_Tokuda7280256.49079598.9156ShellSort_Tokuda_Swapped7280257.879799410.8235ShellSort_Knuth ïî÷òè ñîðòèðîâàí7280252.25162513.0928ShellSort_Knuth_Sent ïî÷òè ñîðòèðîâàí7280252.16607502.9753ShellSort_Knuth_Swapped ïî÷òè ñîðòèðîâàí7280251.90240632.6131ShellSort_Sedg1_Swapped ïî÷òè ñîðòèðîâàí7280251.64740982.2628ShellSort_Sedg1 ïî÷òè ñîðòèðîâàí7280251.97029892.7064ShellSort_Tokuda ïî÷òè ñîðòèðîâàí7280253.08830064.2420ShellSort_Tokuda_Swapped ïî÷òè ñîðòèðîâàí7280252.58816333.5550------------------------------------------------ShellSort_Knuth104857618.973004718.0941ShellSort_Knuth_Sent104857618.227836817.3834ShellSort_Knuth_Swapped104857626.202618224.9888ShellSort_Sedg1_Swapped104857617.862330617.0348ShellSort_Sedge1104857612.667708912.0809ShellSort_Sedge1_Sent104857613.058176612.4532ShellSort_Gonnet104857618.259570417.4137ShellSort_Incerpi104857611.042220110.5307ShellSort_Tokuda10485769.83383779.3783ShellSort_Tokuda_Swapped104857611.727354911.1841ShellSort_Knuth ïî÷òè ñîðòèðîâàí10485763.48833143.3267ShellSort_Knuth_Sent ïî÷òè ñîðòèðîâàí10485763.34742543.1924ShellSort_Knuth_Swapped ïî÷òè ñîðòèðîâàí10485762.94616082.8097ShellSort_Sedg1_Swapped ïî÷òè ñîðòèðîâàí10485762.38107102.2708ShellSort_Sedg1 ïî÷òè ñîðòèðîâàí10485762.86181582.7292ShellSort_Tokuda ïî÷òè ñîðòèðîâàí10485764.61054354.3970ShellSort_Tokuda_Swapped ïî÷òè ñîðòèðîâàí10485763.88419323.7043------------------------------------------------
...
Рейтинг: 0 / 0
сортировка Шелла на VBA, сравнение производительности различных последовательностей.
    #39829683
Фотография vikkiv
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
ещё такая мысль - если уж есть желание именно родными средствами Office реализовывать,
то по идее можно ведь через VBA создать PowerPivot модель?
она под задачи сортировки наборов (работы с наборами) на много больше заточена
(как и большинство движков баз данных, хотя PowerPivot это OLAP, а не OLTP).

У тебя в VBA есть родные методы сортировки (и VBA и Excel) ?

Почему-то я одномерный массив из rand() на весь лист (1'048'576) отсортировал одной кнопкой
за долю секунды (что на порядок меньше чем результаты тестов выше)

, а при добавлении в PowerPivot - и того меньше (правда там на начальное добавление
в модель пара секунд ушла, индексирование {columnstore} и т.д)
...
Рейтинг: 0 / 0
сортировка Шелла на VBA, сравнение производительности различных последовательностей.
    #39837764
booby
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
небольшое дополнение.
В коде использована функция FindMinFirstMaxLastIndex,
отыскивающая первый минимальный и последний максимальный элемент, работающая за 2n-1 стравнений.
В стандартной библиотеке c++ подобная функция называется minmax_element.
Набрел на обсуждение использования этой функции в коде c++,
в котором говорится, что эта функция стандартной библиотеки c++ работает за ~(3/2)*n сравнений.
Там утверждается, что алгоритм изобретен в 1970-е одним из сотрудников университета UC Santa Cruz,
и приводится общее словесное описание алгоритма без выписывания полного кода.
Быстрый поиск в интернете не привел меня к обнаружению аутентичного алгоритма.
Под спойлером получившийся у меня вариант этого алгоритма VBA на базе словесного описания.

Код: vbnet
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.
Sub FindMinFirstMaxLastIndex_z32(pa() As Variant, ByVal iLeft As Long, ByVal iRight As Long, ByRef iMin As Long, ByRef iMax As Long)
' Booby, July 2019
' поиск индексов первого минимального и последнего максимального элементов
' в массиве pa() в позициях с iLeft (левая граница поиска) до iRight (правая граница поиска)
' алгоритм 3/2 сравнений, ( открыт в UC Santa Cruz в 70-е)
' исходный вариант кода не найден.
' выписывается по словесному комментарию к minmax_element c++ std library, реализованному на базе той же идеи

  Dim sTeps&
  sTeps = (iRight - iLeft) - 1&
  
  Dim v_Min As Variant, v_Max As Variant
  
  iMin = iLeft  
  iMax = iLeft + 1&

  If iMax <= iRight Then
    v_Min = pa(iMin)
    v_Max = pa(iMax)
    iLeft = iMax
  Else
    iMax = iMin
    Exit Sub
  End If
    
  If v_Max < v_Min Then
    Swap_VS v_Min, v_Max
    Swap_VS iMin, iMax
  End If
    
  Dim i&

  Dim hasLastStep&
  hasLastStep = (sTeps And 1&)
  'получаем четное число оставшихся пар
  sTeps = sTeps - hasLastStep
    
  Dim iNext&
  'при сортировке по возрастанию левый элемент первый среди равных
  'при сортировке по возрастанию ставим правый элемент последний среди равных
  'For i = 1& To sTeps Step 2&
  Do While iLeft < sTeps
    iLeft = iLeft + 1&
    iNext = iLeft + 1&
    
    If (pa(iLeft) < pa(iNext)) Then
      ' pa(iLeft) - потенциальный минимум
      If (pa(iLeft) < v_Min) Then
        v_Min = pa(iLeft)
        iMin = iLeft
      End If
      If Not (pa(iNext) < v_Max) Then
        v_Max = pa(iNext)
        iMax = iNext
      End If
    Else
      'pa(iNext) - потенциальный минимум
      If (pa(iNext) < v_Min) Then
        v_Min = pa(iNext)
        iMin = iNext
      End If
      If Not (pa(iLeft) < v_Max) Then
        v_Max = pa(iLeft)
        iMax = iLeft
      End If
    End If
    iLeft = iNext
  Loop
    
  'последний шаг
  If hasLastStep Then
    iLeft = iLeft + 1&
    If pa(iLeft) < v_Min Then
      v_Min = pa(iLeft)
      iMin = iLeft
    End If
    If Not (pa(iLeft) < v_Max) Then
      v_Max = pa(iLeft)
      iMax = iLeft
    End If
  End If
  
End Sub




проверка показала, что на массивах целых числе разница в быстродействии
между FindMinFirstMaxLastIndex и FindMinFirstMaxLastIndex_z32 на VBA не видна.
Но на массивах строк случайной длины, примерно от 32 до 128 символов, обещанная треть выигрыша получается.
Настолько сравнение строк дороже сравнения целых.

Для генерации массива случайных строк использован такой код
получение случайной строки:
Код: vbnet
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
Function next_RND_Long(ByVal ileftBound As Long, ByVal iRightBound As Long) As Long
  next_RND_Long = Fix((iRightBound - ileftBound) * Rnd) + ileftBound
End Function

Function next_RND_String(ByVal ileftBound As Long, ByVal iRightBound As Long) As String
  Dim iLen&, i&
  iLen = next_RND_Long(ileftBound, iRightBound)
  next_RND_String = String(iLen, vbNullChar)
  For i = 1 To iLen
    Mid$(next_RND_String, i, 1&) = Chr(next_RND_Long(33, 255)) '--1103))
  Next
  
End Function



Получение массива случайных строк:
Код: vbnet
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
Sub randArray_s(pa() As Variant, ByVal pN As Long)
' формирует массив с числом элементов pN,
' и заполняет его случайными элементами

 ReDim pa(0 To pN - 1&)
 Dim i&
 For i = 0 To pN - 1&
   pa(i) = next_RND_String(32, 128)
 Next
End Sub

...
Рейтинг: 0 / 0
14 сообщений из 14, страница 1 из 1
Форумы / Microsoft Office [игнор отключен] [закрыт для гостей] / сортировка Шелла на VBA, сравнение производительности различных последовательностей.
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]