2013-05-12 2 views
1

Помогая ученику с его классами, я внедрил двойной алгоритм быстрой сортировки, чтобы подготовить сеанс и заинтриговать. После запуска некоторых статистических данных, затем решения ситуации с наихудшим случаем, затем повторного запуска статистики и повторного решения следующей ситуации в худшем случае и повторения этого процесса несколько раз, полученный код не более 80 строк простого простого кода Python (бит меньше кода Владимира). Новая часть состоит в том, как три раздела построены в сочетании с очень простой, но эффективной постобработкой. Теперь мне нужна помощь в том, как правильно тестировать и делать статистику.Подсчет свопов для сортировки статистики - что с свопами с двумя заданиями вместо трех

Особенно о том, как подсчитать свопы: большинство свопов выполняют только два задания вместо трех. Поэтому я должен считать их полными свопами или, справедливо ли считать их только как «2/3» обмен?

Подсчет каждый свопа, как 1, то Cn в Cn * N * log2(N) составляет около 0.48 на короткие списки (< 100 элементов) и вокруг 0.55 на более длинных списках нескольких миллионов элементов. Это только теоретический минимум , рассчитанный на Владимир Ярославский.

Counting легких свопов как 2/3 вместо этого, количества необходимых свопов практически одинаков для любого размера списка и составляет около 0.36 (STDEV вокруг 0.015).

Cn для числа сравнений в среднем около 1.3 для списков 2 миллиона записей, что составляет менее чем теоретическое 1,38 (от 2 * N * Ln (N)), и ниже для более коротких списков, т.е. 1024 элементов, это около 1.21

то есть для списков с 100% уникальных номеров и случайным образом упорядоченных с Питона random.shuffle().


Так что мой вопрос:

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


Также интересен:

  • более одинаковых элементов в списке, тем быстрее сорта. Cn - 0.03 и 0.1 для свопов и сравнений соответственно для 2 миллиона список всех равные элементы.
  • Cn для отсортирован и обратных упорядоченных списков почти одинаковы для всех размеров: 0.3 и 1 для свопа (подсчитанный с 2/3) и сравнением соответственно.

Я отправлю список с более подробной статистикой, которая включает в себя максимальную глубину стека, количество рекурсивных вызовов помимо свопов и сравнений. Есть ли еще другие вещи?

Также существуют некоторые «стандартные» тестовые комплекты с файлами всех видов ситуаций (с равными, частично отсортированными и т. Д.), Которые можно использовать для тестирования алгоритма сортировки и для сопоставления результатов с другими алгоритмами сортировки.



Добавлено 5 мая: я улучшил алгоритм специально для отсортированных списков. Ниже приведены результаты для 20 прогонов для каждого. Хорошие ли результаты?

New statistics: 
Random.shuffle(), unique number 
    Length  Swaps/Nlog2(N)  Comparisons/Nlog2(N) Maximum Stack/log2(N) 
     16  0.367    0.922     0.250 
     64  0.360    1.072     0.500 
    256  0.342    1.122     0.625 
    1024  0.358    1.156     0.800 
    4096  0.359    1.199     0.917 
    16384  0.359    1.244     1.071 
    65536  0.360    1.244     1.125 
    262144  0.360    1.269     1.167 
1048576  0.362    1.275     1.200 

Sorted, unique numbers 
    Length  Swaps/Nlog2(N)  Comparisons/Nlog2(N) Maximum Stack/log2(N) 
     16  0.172    0.531     0.250 
     64  0.117    0.586     0.333 
    256  0.087    0.609     0.375 
    1024  0.075    0.740     0.500 
    4096  0.060    0.732     0.500 
    16384  0.051    0.726     0.500 
    65536  0.044    0.722     0.500 
    262144  0.041    0.781     0.556 
1048576  0.036    0.774     0.550 
2097152  0.035    0.780     0.571 

Reversed order, unique numbers 
    Length  Swaps/Nlog2(N)  Comparisons/Nlog2(N) Maximum Stack/log2(N) 
     16  0.344    0.828     0.250 
     64  0.279    0.812     0.333 
    256  0.234    0.788     0.375 
    1024  0.210    0.858     0.500 
    4096  0.190    0.865     0.500 
    16384  0.172    0.855     0.500 
    65536  0.158    0.846     0.500 
    262144  0.153    0.900     0.556 
1048576  0.143    0.892     0.550 
2097152  0.140    0.895     0.571 
+0

Как мы можем поменять местами два числа с двумя заданиями? – Sayakiss

+0

@Sayakiss При сортировке перенос записи в нужное место не всегда требует обмена с другим значением. Хорошим примером является перемещение позиции списка 1, не нужно менять каждый элемент. –

ответ

3

Я выбрал для подсчета присвоений, выполняемых для элементов, подлежащих сортировке, вместо «свопов». Присвоения и сравнения индексов не учитываются.

Я преобразовал код Владимира Ярославского в его документ (Последнее обновление: 22 сентября 2009 г.) на Python и добавил счетчики так же, как и в моей собственной реализации. Код включен в конце.

Любые комментарии приветствуются.

Ниже приведены результаты, полученные в среднем за 10 прогонов.

Столбцы с пометкой VY - это результаты для реализации Владимиром, столбцы, помеченные JB, являются моими собственными воплощениями.

Length  F Function call Assignements Comparisons Maximum Stack 
of list   per N   per N.log2(N) per N.log2(N) per log2(N) 

Random.shuffle(), unique number 
Version    VY  JB  VY  JB  VY  JB  VY  JB 
     64  1 0.170 0.266 1.489 1.029 1.041 1.028 0.417 0.633 
    256  1 0.171 0.270 1.463 1.016 1.066 1.138 0.575 0.812 
    1024  1 0.167 0.275 1.451 1.046 1.089 1.165 0.690 1.010 
    4096  1 0.164 0.273 1.436 1.069 1.119 1.189 0.800 1.075 
    16384  1 0.166 0.273 1.444 1.077 1.117 1.270 0.843 1.221 
    65536  1 0.166 0.273 1.440 1.108 1.126 1.258 0.919 1.281 
    262144  1 0.166 0.273 1.423 1.102 1.134 1.278 0.950 1.306 
1048576  1 0.166 0.273 1.426 1.085 1.131 1.273 0.990 1.290 

Sorted, unique numbers 
Version    VY  JB  VY  JB  VY  JB  VY  JB 
     64  1 0.203 0.203 1.036 0.349 0.643 0.586 0.333 0.333 
    256  1 0.156 0.156 0.904 0.262 0.643 0.609 0.375 0.375 
    1024  1 0.118 0.355 0.823 0.223 0.642 0.740 0.400 0.500 
    4096  1 0.131 0.267 0.840 0.181 0.679 0.732 0.500 0.500 
    16384  1 0.200 0.200 0.926 0.152 0.751 0.726 0.500 0.500 
    65536  1 0.150 0.150 0.866 0.131 0.737 0.722 0.500 0.500 
    262144  1 0.113 0.338 0.829 0.124 0.728 0.781 0.500 0.556 
1048576  1 0.147 0.253 0.853 0.108 0.750 0.774 0.550 0.550 

Reversed order, unique numbers 
Version    VY  JB  VY  JB  VY  JB  VY  JB 
     64  1 0.203 0.203 1.320 0.836 0.841 0.802 0.333 0.333 
    256  1 0.156 0.156 1.118 0.703 0.795 0.783 0.375 0.375 
    1024  1 0.118 0.312 1.002 0.631 0.768 0.852 0.400 0.500 
    4096  1 0.125 0.267 0.977 0.569 0.776 0.861 0.500 0.500 
    16384  1 0.200 0.200 1.046 0.516 0.834 0.852 0.500 0.500 
    65536  1 0.150 0.150 0.974 0.475 0.813 0.844 0.500 0.500 
    262144  1 0.113 0.338 0.925 0.459 0.795 0.896 0.500 0.556 
1048576  1 0.145 0.253 0.938 0.430 0.811 0.890 0.550 0.550 

Random, with increasing frequency of the numbers. 
The last row is a list of the same number 
Version    VY  JB  VY  JB  VY  JB  VY  JB 
    65536  1 0.166 0.273 1.429 1.051 1.113 1.251 0.881 1.156 
    65536  2 0.167 0.270 1.404 1.075 1.112 1.238 0.894 1.194 
    65536  4 0.168 0.273 1.373 1.039 1.096 1.213 0.906 1.238 
    65536  8 0.151 0.245 1.302 1.029 1.069 1.199 0.900 1.262 
    65536  16 0.132 0.127 1.264 0.970 1.020 1.150 0.912 1.188 
    65536  32 0.090 0.064 1.127 0.920 0.950 1.099 0.856 1.119 
    65536  64 0.051 0.032 1.000 0.845 0.879 0.993 0.819 1.019 
    65536  128 0.026 0.016 0.884 0.792 0.797 0.923 0.725 0.931 
    65536  256 0.013 0.008 0.805 0.704 0.728 0.840 0.675 0.856 
    65536  512 0.006 0.004 0.690 0.615 0.652 0.728 0.588 0.669 
    65536  1024 0.003 0.002 0.635 0.557 0.579 0.654 0.519 0.625 
    65536  2048 0.002 0.001 0.541 0.487 0.509 0.582 0.438 0.463 
    65536  4096 0.001 0.000 0.459 0.417 0.434 0.471 0.369 0.394 
    65536  8192 0.000 0.000 0.351 0.359 0.357 0.405 0.294 0.300 
    65536 16384 0.000 0.000 0.247 0.297 0.253 0.314 0.206 0.194 
    65536 32768 0.000 0.000 0.231 0.188 0.209 0.212 0.125 0.081 
    65536 65536 0.000 0.000 0.063 0.125 0.063 0.125 0.062 0.000 

Вот код Владимирс рода в Python:

DIST_SIZE = 13 
TINY_SIZE = 17 

def dualPivotQuicksort(a, left, right, nesting=0): 
    global assignements, comparisons, oproepen, maxnesting 
    oproepen += 1 
    maxnesting = max(maxnesting, nesting) 

    length = right - left 
    if length < TINY_SIZE: # insertion sort on tiny array 
    # note by JB: rewritten to minimize the assignements 
    for i in xrange(left+1, right+1): 
     key = a[i] 
     assignements += 1 

     while i > left: 
     comparisons += 1 
     if key < a[i - 1]: 
      assignements += 1 
      a[i] = a[i-1] 
      i -= 1 
     else: 
      break 

     assignements += 1 
     a[i] = key 

    return 

    # median indexes 
    sixth = length/6 
    m1 = left + sixth 
    m2 = m1 + sixth 
    m3 = m2 + sixth 
    m4 = m3 + sixth 
    m5 = m4 + sixth 
    assignements += 9*3 
    comparisons += 9 
    ## 5-element sorting network 
    if a[m1] > a[m2]: a[m1],a[m2] = a[m2],a[m1] 
    if a[m4] > a[m5]: a[m4],a[m5] = a[m5],a[m4] 
    if a[m1] > a[m3]: a[m1],a[m3] = a[m3],a[m1] 
    if a[m2] > a[m3]: a[m2],a[m3] = a[m3],a[m2] 
    if a[m1] > a[m4]: a[m1],a[m4] = a[m4],a[m1] 
    if a[m3] > a[m4]: a[m3],a[m4] = a[m4],a[m3] 
    if a[m2] > a[m5]: a[m2],a[m5] = a[m5],a[m2] 
    if a[m2] > a[m3]: a[m2],a[m3] = a[m3],a[m2] 
    if a[m4] > a[m5]: a[m4],a[m5] = a[m5],a[m4] 

    # pivots: [ < pivot1 | pivot1 <= && <= pivot2 | > pivot2 ] 
    assignements += 2 
    pivot1 = a[m2] 
    pivot2 = a[m4] 

    comparisons += 1 
    diffPivots = pivot1 != pivot2 

    assignements += 2 
    a[m2] = a[left] 
    a[m4] = a[right] 

    # center part pointers 
    less = left + 1 
    great = right - 1 

    # sorting 
    if (diffPivots): 
    k = less 
    while k <= great: 
     assignements += 1 
     x = a[k] 

     comparisons += 2 
     if (x < pivot1): 
     comparisons -= 1 
     assignements += 2 
     a[k] = a[less] 
     a[less] = x 
     less += 1 

     elif (x > pivot2): 
     while k < great: 
      comparisons += 1 
      if a[great] > pivot2: 
      great -= 1 
      else: 
      break 

     assignements += 3 
     a[k] = a[great] 
     a[great] = x 
     great -= 1 
     x = a[k] 

     comparisons += 1 
     if (x < pivot1): 
      assignements += 2 
      a[k] = a[less] 
      a[less] = x 
      less += 1 

     k += 1 

    else: 
    k = less 
    while k <= great: 
     assignements += 1 
     x = a[k] 

     comparisons += 1 
     if (x == pivot1): 
     k += 1 
     continue 

     comparisons += 1 
     if (x < pivot1): 
     assignements += 2 
     a[k] = a[less] 
     a[less] = x 
     less += 1 

     else: 
     while k < great: 
      comparisons += 1 
      if a[great] > pivot2: 
      great -= 1 
      else: 
      break 

     assignements += 3 
     a[k] = a[great] 
     a[great] = x 
     great -= 1 
     x = a[k] 

     comparisons += 1 
     if (x < pivot1): 
      assignements += 2 
      a[k] = a[less] 
      a[less] = x 
      less += 1 

     k += 1 

    # swap 
    assignements += 2 
    a[left] = a[less - 1] 
    a[less - 1] = pivot1 

    assignements += 2 
    a[right] = a[great + 1] 
    a[great + 1] = pivot2 

    # left and right parts 
    dualPivotQuicksort(a, left, less - 2, nesting+1) 
    dualPivotQuicksort(a, great + 2, right, nesting+1) 

    # equal elements 
    if (great - less > length - DIST_SIZE and diffPivots): 
    k = less 
    while k <= great: 
     assignements += 1 
     x = a[k] 

     comparisons += 2 
     if (x == pivot1): 
     comparisons -= 1 
     assignements += 2 
     a[k] = a[less] 
     a[less] = x 
     less += 1 

     elif (x == pivot2): 
     assignements += 3 
     a[k] = a[great] 
     a[great] = x 
     great -= 1 
     x = a[k] 

     comparisons += 1 
     if (x == pivot1): 
      assignements += 2 
      a[k] = a[less] 
      a[less] = x 
      less += 1 

     k += 1 

    # center part 
    if (diffPivots): 
     dualPivotQuicksort(a, less, great, nesting+1) 

Этот код около 190 строк, моя текущая реализация написана с тем же форматированием составляет около 110 строк.

Так что любые замечания приветствуются.

Смежные вопросы