Визуализировать сортировку

20

Скажем, у меня есть список типа [3, 0, 4, 2, 1], и я использую сортировку выбора, чтобы отсортировать ее, я мог бы визуализировать это так:

3,0,4,2,1
|-|
0,3,4,2,1
  |-----|
0,1,4,2,3
    |-|
0,1,2,4,3
      |-|
0,1,2,3,4

Эта задача о визуализации сортировки, как это.

вход

Ваш ввод будет список положительных чисел, в любом формате, который вам нравится.

задача

Ваше представление должно отсортировать входной список, меняя местами только два элемента, и при каждом обмене представление должно отображать список и символ под каждым из заменяемых элементов. Если число, которое было поменяно местами, имеет более одной цифры, символ может находиться в любом месте под ним. В конце представления должно отображаться отсортированный список.

Другие правила

  • Сортировка должна использовать меньше свопов, чем n 4 , где n - длина списка.
  • Сортировка не должна быть детерминированной.
  • Символы под поменяемыми местами могут быть любыми символами, кроме пробела.
Loovjo
источник
Могу ли я предположить, что целые числа являются уникальными?
Йорг Хюльсерманн
n^4? Вы немного щедры здесь.
orlp
@ JörgHülsermann Нет
Loovjo
2
Если кто-то заинтересован в сортировке toptal.com/developers/sorting-algorithms
exussum
3
Вы говорите, что входные данные являются положительными целыми числами, но в вашем примере есть 0(пожалуйста, исправьте только пример, чтобы не аннулировать ответы, которые не могут обработать 0)
Ton Hospel

Ответы:

10

Perl, 62 байта

Включает +3 для -p

Введите ввод в виде одной строки чисел на STDIN:

perl -M5.010 visisort.pl <<< "3 0 4 2 1"

Неоднократно менял местами первую инверсию. Сложность свопа есть O(n^2), сложность времени есть O(n^3). Использует числа, поменяемые местами как метки:

3 0 4 2 1
3 0
0 3 4 2 1
    4 2
0 3 2 4 1
  3 2
0 2 3 4 1
      4 1
0 2 3 1 4
    3 1
0 2 1 3 4
  2 1
0 1 2 3 4

visisort.pl:

#!/usr/bin/perl -p
$&>$'&&say$_.$"x"@-".!s/(\S+) \G(\S+)/$2 $1/.$&while/\S+ /g

Программа также поддерживает отрицательные значения и числа с плавающей запятой

Если вы настаиваете на соединительном символе, код становится 66 байтами:

#!/usr/bin/perl -p
$&>$'&&say$_.$"x"@-".!s/(\S+) \G(\S+)/$2 $1/.$1.-$2while/\S+ /g

Но теперь он больше не поддерживает отрицательные числа и 0 (но в любом случае программа должна поддерживать только положительные целые числа. В 0данном примере это ошибка)

Тон Хоспел
источник
Учитывая, что у The characters under the swapped can be any char except space. вас не должно быть пробелов между
цифрами в
@ edc65 Символ (ы) под заменяемыми элементами не является пробелом. Ничего не сказано о персонажах между ними
Тон Хоспел
Не совсем уверен, но хорошо. Я слишком быстро понизил голосование (но я привлек ваше внимание). Если вы
внесете
@ edc65 Ваш комментарий заставил меня перечитать вызов очень внимательно. Обратите внимание, что он также говорит о случае многозначных чисел, ясно означающих, что вы можете, например, просто поставить _под первой цифрой, что означает, что все символы между ними на самом деле будут пробелами). Поэтому я придерживаюсь своей интерпретации (если, конечно, ФП не согласен). Но только для того, чтобы вы были счастливы, я добавил версию без пробела :-)
Тон Хоспел
9

JavaScript (ES6), 158 байт

a=>{for(;;){console.log(``+a);i=a.findIndex((e,i)=>e<a[i-1]);if(i<0)break;console.log(` `.repeat(`${a.slice(0,i)}`.length-1)+`|-|`);t=a[i];a[i]=a[--i];a[i]=t}}

Пузырьковая сортировка. Образец вывода:

3,0,4,2,1
|-|
0,3,4,2,1
    |-|
0,3,2,4,1
  |-|
0,2,3,4,1
      |-|
0,2,3,1,4
    |-|
0,2,1,3,4
  |-|
0,1,2,3,4
Нил
источник
@nimi Так как я всегда меняю соседние элементы, я всегда могу поставить -под, ,и тогда две |s всегда будут под соседними числами.
Нил
ааа, умно! Благодарность!
Ними
1
Пузырьковая сортировка - это действительно разумный выбор, чтобы упростить выделение помененных мест. Отлично сработано!
Арно
9

PHP, 248 байт

Bubblesort скучные победы

<?for($c=count($a=$_GET[a]);$c--;){for($s=$i=0;$i<$c;){$l=strlen($j=join(",",$a));if($a[$i]>$a[$i+1]){$t=$a[$i];$a[$i]=$a[$i+1];$a[$i+1]=$t;$m=" ";$m[$s]=I;$m[$s+strlen($a[$i].$a[$i+1])]=X;echo"$j\n$m\n";}$s+=strlen($a[$i++])+1;}}echo join(",",$a);

PHP, 266 байт путь с array_slice и min

измененный вывод I Xвместо*~~*

<?for($c=count($a=$_GET[a]);$i<$c;){$j=join(",",$s=($d=array_slice)($a,$i));$x=array_search($m=min($s),$s);echo($o=join(",",$a));$a[$x+$i]=$a[$i];$a[$i]=$m;if($i++!=$c-1){$t=" ";$t[$z=($f=strlen)($o)-($l=$f($j))]=I;$t[$l+$z-$f(join(",",$d($s,$x)))]=X;echo"\n$t\n";}}

282 байта

<?for($c=count($a=$_GET[a]);$i<$c;){$j=join(",",$s=($d=array_slice)($a,$i));$x=array_search($m=min($s),$s);echo($o=join(",",$a));$a[$x+$i]=$a[$i];$a[$i]=$m;if($i++!=$c-1)echo"\n".str_repeat(" ",($f=strlen)($o)-($l=$f($j))).($x?str_pad("*",$l-$f(join(",",$d($s,$x))),"~"):"")."*\n";}

Как это устроено

Ищет минимум в массиве и принимает его в первой позиции. Ищет минимум без первой позиции .... и т. Д. Если значение равно двойному, первое значение будет заменено

Пример вывода

31,7,0,5,5,5,753,5,99,4,333,5,2,1001,35,1,67
*~~~~*
0,7,31,5,5,5,753,5,99,4,333,5,2,1001,35,1,67
  *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*
0,1,31,5,5,5,753,5,99,4,333,5,2,1001,35,7,67
    *~~~~~~~~~~~~~~~~~~~~~~~~~*
0,1,2,5,5,5,753,5,99,4,333,5,31,1001,35,7,67
      *~~~~~~~~~~~~~~*
0,1,2,4,5,5,753,5,99,5,333,5,31,1001,35,7,67
        *
0,1,2,4,5,5,753,5,99,5,333,5,31,1001,35,7,67
          *
0,1,2,4,5,5,753,5,99,5,333,5,31,1001,35,7,67
            *~~~*
0,1,2,4,5,5,5,753,99,5,333,5,31,1001,35,7,67
              *~~~~~~*
0,1,2,4,5,5,5,5,99,753,333,5,31,1001,35,7,67
                *~~~~~~~~~~*
0,1,2,4,5,5,5,5,5,753,333,99,31,1001,35,7,67
                  *~~~~~~~~~~~~~~~~~~~~~*
0,1,2,4,5,5,5,5,5,7,333,99,31,1001,35,753,67
                    *~~~~~~*
0,1,2,4,5,5,5,5,5,7,31,99,333,1001,35,753,67
                       *~~~~~~~~~~~*
0,1,2,4,5,5,5,5,5,7,31,35,333,1001,99,753,67
                          *~~~~~~~~~~~~~~~*
0,1,2,4,5,5,5,5,5,7,31,35,67,1001,99,753,333
                             *~~~~*
0,1,2,4,5,5,5,5,5,7,31,35,67,99,1001,753,333
                                *~~~~~~~~*
0,1,2,4,5,5,5,5,5,7,31,35,67,99,333,753,1001
                                    *
0,1,2,4,5,5,5,5,5,7,31,35,67,99,333,753,1001
Йорг Хюльсерманн
источник
Вместо этого echo$t."\n";вы можете использовать echo"$t\n";и сохранить байт.
Исмаэль Мигель
@IsmaelMiguel Не стесняйтесь редактировать мои сообщения, если вы найдете что-то для улучшения
Йорг Хюльсерманн
7
Редактирование кода на сообщениях обычно осуждается, с чем я полностью согласен.
Исмаэль Мигель
3

Haskell, 165 164 162 байта

s%c=drop 2$show s>>c
p#x|(h,t:s)<-span(/=minimum x)x=id=<<[show$p++x,"\n ",[' '|p>[]],p%" ","|",h%"-",['|'|h>[]],"\n",(p++[t])#(drop 1h++take 1h++s)]|1<2=""
([]#)

Это визуализирует выбор сортировки. Пример использования:

*Main> putStr $ ([]#) [31,7,0,5,5,5,753,5,99,4,333,5,2,1001,35,1,67]
[31,7,0,5,5,5,753,5,99,4,333,5,2,1001,35,1,67]
 |----|
[0,7,31,5,5,5,753,5,99,4,333,5,2,1001,35,1,67]
   |-------------------------------------|
[0,1,31,5,5,5,753,5,99,4,333,5,2,1001,35,7,67]
     |-------------------------|
[0,1,2,5,5,5,753,5,99,4,333,5,31,1001,35,7,67]
       |--------------|
[0,1,2,4,5,5,753,5,99,5,333,5,31,1001,35,7,67]
         |
[0,1,2,4,5,5,753,5,99,5,333,5,31,1001,35,7,67]
           |
[0,1,2,4,5,5,753,5,99,5,333,5,31,1001,35,7,67]
             |---|
[0,1,2,4,5,5,5,753,99,5,333,5,31,1001,35,7,67]
               |------|
[0,1,2,4,5,5,5,5,99,753,333,5,31,1001,35,7,67]
                 |----------|
[0,1,2,4,5,5,5,5,5,753,333,99,31,1001,35,7,67]
                   |---------------------|
[0,1,2,4,5,5,5,5,5,7,333,99,31,1001,35,753,67]
                     |------|
[0,1,2,4,5,5,5,5,5,7,31,99,333,1001,35,753,67]
                        |-----------|
[0,1,2,4,5,5,5,5,5,7,31,35,333,1001,99,753,67]
                           |---------------|
[0,1,2,4,5,5,5,5,5,7,31,35,67,1001,99,753,333]
                              |----|
[0,1,2,4,5,5,5,5,5,7,31,35,67,99,1001,753,333]
                                 |--------|
[0,1,2,4,5,5,5,5,5,7,31,35,67,99,333,753,1001]
                                     |
[0,1,2,4,5,5,5,5,5,7,31,35,67,99,333,753,1001]
                                         |

Как это устроено:

s % cвспомогательная функция , которая делает length (show s) - 2копию символа c. Он используется для интервалов до того и другого |, один раз с c == ' 'и один раз с c == '-'.

Основная функция #принимает список, pкоторый является отсортированной частью списка и xкоторая еще не отсортирована. Сопоставление с образцом (h,t:s)<-span(/=minimum x)xразбивает список xпо минимальному элементу и привязывает hк части до минимума, tк самому минимуму и sк части после минимума. Остальное форматирует две строки: 1) список в его текущем состоянии ( p++x) и 2) |----|часть, за которой следует рекурсивный вызов #с tдобавлением pи заголовком hвставки между хвостом hиs .

PS: работает также с отрицательными числами и / или числами с плавающей запятой:

*Main> putStr $ ([]#) [-3,-1,4e33,-7.3]
[-3.0,-1.0,4.0e33,-7.3]
 |----------------|
[-7.3,-1.0,4.0e33,-3.0]
      |-----------|
[-7.3,-3.0,4.0e33,-1.0]
           |------|
[-7.3,-3.0,-1.0,4.0e33]
                |

Редактировать: @BlackCap сохранил 2 байта. Благодарность!

Ними
источник
id=<<[show$p++x,"\n ",[' '|p>[]],p%" ","|",h%"-",['|'|h>[]],"\n",(p++[t])#(drop 1h++take 1h++s)]
BlackCap
1

Python 2, 267 байт

Работает с десятичными и отрицательными числами.

p=1
while p!=len(a):    
 q=p-1;k=a[p:];m=min(k);n=k.index(m)+p;b=map(str,a)
 if a[q]>m:print','.join(b)+'\n'+''.join(' '*len(i)for i in b[:q])+' '*q+'*'+'-'*(len(b[n])+n-q-2)+''.join('-'*len(i)for i in b[q:n])+'*';a[q],a[n]=[a[n],a[q]]
 p+=1
print','.join(map(str,a))

Пример:

7,2,64,-106,52.7,-542.25,54,209,0,-1,200.005,200,3,6,1,0,335,-500,3.1,-0.002
*----------------------*
-542.25,2,64,-106,52.7,7,54,209,0,-1,200.005,200,3,6,1,0,335,-500,3.1,-0.002
        *-------------------------------------------------------*
-542.25,-500,64,-106,52.7,7,54,209,0,-1,200.005,200,3,6,1,0,335,2,3.1,-0.002
             *-----*
-542.25,-500,-106,64,52.7,7,54,209,0,-1,200.005,200,3,6,1,0,335,2,3.1,-0.002
                  *-------------------*
-542.25,-500,-106,-1,52.7,7,54,209,0,64,200.005,200,3,6,1,0,335,2,3.1,-0.002
                     *-----------------------------------------------------*
-542.25,-500,-106,-1,-0.002,7,54,209,0,64,200.005,200,3,6,1,0,335,2,3.1,52.7
                            *--------*
-542.25,-500,-106,-1,-0.002,0,54,209,7,64,200.005,200,3,6,1,0,335,2,3.1,52.7
                              *-----------------------------*
-542.25,-500,-106,-1,-0.002,0,0,209,7,64,200.005,200,3,6,1,54,335,2,3.1,52.7
                                *------------------------*
-542.25,-500,-106,-1,-0.002,0,0,1,7,64,200.005,200,3,6,209,54,335,2,3.1,52.7
                                  *-------------------------------*
-542.25,-500,-106,-1,-0.002,0,0,1,2,64,200.005,200,3,6,209,54,335,7,3.1,52.7
                                    *--------------*
-542.25,-500,-106,-1,-0.002,0,0,1,2,3,200.005,200,64,6,209,54,335,7,3.1,52.7
                                      *-------------------------------*
-542.25,-500,-106,-1,-0.002,0,0,1,2,3,3.1,200,64,6,209,54,335,7,200.005,52.7
                                          *------*
-542.25,-500,-106,-1,-0.002,0,0,1,2,3,3.1,6,64,200,209,54,335,7,200.005,52.7
                                            *-----------------*
-542.25,-500,-106,-1,-0.002,0,0,1,2,3,3.1,6,7,200,209,54,335,64,200.005,52.7
                                              *----------------------------*
-542.25,-500,-106,-1,-0.002,0,0,1,2,3,3.1,6,7,52.7,209,54,335,64,200.005,200
                                                   *----*
-542.25,-500,-106,-1,-0.002,0,0,1,2,3,3.1,6,7,52.7,54,209,335,64,200.005,200
                                                      *--------*
-542.25,-500,-106,-1,-0.002,0,0,1,2,3,3.1,6,7,52.7,54,64,335,209,200.005,200
                                                         *-----------------*
-542.25,-500,-106,-1,-0.002,0,0,1,2,3,3.1,6,7,52.7,54,64,200,209,200.005,335
                                                             *---------*
-542.25,-500,-106,-1,-0.002,0,0,1,2,3,3.1,6,7,52.7,54,64,200,200.005,209,335
Питер
источник
1

JavaScript (ES6), 147 155

Использование n * n сравнивает, но (я считаю) минимальное количество перестановок. И позиции обмена более изменчивы по сравнению с типом скучных пузырьков.

l=>l.reduce((z,v,i)=>l.map((n,j)=>s+=`${j>i?n<l[i]?l[p=j,t=s,i]=n:0:u=s,n},`.length,s=p=0)|p?z+`
${l[p]=v,' '.repeat(u)}^${Array(t-u)}^
`+l:z,''+l)

Менее гольф и, надеюсь, более понятным

l=>
  l.reduce( (z,v,i) => // update z for each list element v at position i
    ( // begin outer loop body
      // loop to find the least value that is to be placed at pos i
      l.map( (n,j) => // for each list element n at position j
        ( // begin inner loop body
          j > i ? // check if at position after i
            n < l[i] && // check if lower value 
            (
              p = j, // remember position in p 
              l[i] = n, // store value in l[i] (could change later)
              t = s // in t, string length of list elements up element preciding j
            )
          : // else, position up to i
            u = s, // in u, string length of list elements up element preciding i
          s += `${n},`.length, // string length of list elements up to this point (value length + comma)
        ) // end inner loop body
        , s = p = 0 // init s and p at start of inner loop
      ), 
      p ? (// if found a lower value, complete the swap and update output
          l[p] = v, // complete swap, l[i] was assigned before
          z + '\n' + ' '.repeat(u) + // spaces to align 
               '^' + // left marker
               Array(t-u) + // swap highlight, using sequence of commas
               '^\n' + // right marker, newline
               l + // list values after the swap, newline
      )
      : z // else output is unchanged
    ) // end outer loop body
    , ''+l // init string output at start of outer loop
  ) // output is the result of reduce

Тестовое задание

f=
l=>l.reduce((z,v,i)=>l.map((n,j)=>s+=`${j>i?n<l[i]?l[p=j,t=s,i]=n:0:u=s,n},`.length,s=p=0)|p?z+`
${l[p]=v,' '.repeat(u)}^${Array(t-u)}^
`+l:z,''+l)

function sort()
{
  var list=I.value.match(/-?[\d.]+/g).map(x=>+x)
  O.textContent = f(list)
}

sort()
#I { width:80% }
<input id=I value='3, 0, 4, 2, 1'>
<button onclick='sort()'>Sort</button>
<pre id=O></pre>

edc65
источник
0

Java 7, 256 241 282 байта

Спасибо @Geobits и @Axelh за сохранение 15 байт

 void f(int[]a){int m,i,j,l=a.length;for(i=0;i<l;j=a[i],a[i]=a[m],a[m]=j,i++){for(int k:a)System.out.print(k+" ");System.out.println();for(j=i+1,m=i;j<l;m=a[j]<a[m]?j:m,j++);for(j=0;j<=m&i!=l-1;j++)System.out.print(j==i|j==m?a[j]+" ":"  ");System.out.println();}}

Ungolfed

 void f(int[]a){
    int m,i,j,l=a.length;
for(i=0;i<l;j=a[i],a[i]=a[m],a[m]=j,i++){
    for(int k:a)
        System.out.print(k+" ");
    System.out.println();
     for(j=i+1,m=i;j<l;m=a[j]<a[m]?j:m,j++);
      for(j=0;j<=m&i!=l-1;j++)
      System.out.print(j==i|j==m?a[j]+" ":"  ");
      System.out.println();        

}
}

выход

3 0 1 4 2 
3 0 
0 3 1 4 2 
  3 1 
0 1 3 4 2 
    3   2 
0 1 2 4 3 
      4 3 
0 1 2 3 4 
Numberknot
источник
4
Это по-прежнему отсутствует объявление out, вам нужно поместить что-то вроде PrintStream out=System.out;где-то в вашем коде.
Loovjo
2
После исправления импорта / объявления out, вы должны использовать троичный вместо того, if/elseесли вы собираетесь печатать на обеих ветвях. Нечто подобное out.print(a>b?a:b);вместоif(a>b)out.print(a);else out.print(b);
Geobits
Вы можете уменьшить значение if if this: if(j==i|j==m)out.print(a[j]);out.print(" ");или, что еще лучше, с помощью троичного символа, out.print((j==i|j==m?a[j]:" ")+" ");а затем удалить цикл {}. PS: я использую статический импорт для экземпляра out, если это нормально;)
AxelH
Хм, кроме советов по игре в гольф от других, вывод неправильный. Вот идеон с вашим кодом, вставленным копированием (и добавленным System.перед outs), и он пропускает 2и 3на двух последних линиях обмена.
Кевин Круйссен
@KevinCruijssen Я исправил это. На самом деле я смешиваю переменную i с переменной j (должна быть i) в этой строкеfor(j=0;j<=m&i!=l-1;j++)
Numberknot,
0

Желе , 36 байт

I;0CMḢ;L‘ṬCœṗ¹UF©µÐĿ,n+32Ọ$¥¥2\;/®ṭG

Попробуйте онлайн!

объяснение

I;0CMḢ;L‘ṬCœṗ¹UF©µÐĿ,n+32Ọ$¥¥2\;/®ṭG
                 µÐĿ                 Repeat until we see a previously seen value:
I;0                                    Take differences of adjacent inputs, and 0
   CM                                  Find the indices (M) of the smallest (C) 
           œṗ                          Split {the input} into pieces
        ‘Ṭ                               that end
      ;L  C                              everywhere except
     Ḣ                                 the first of the chosen deltas
             ¹                         Resolve parser ambiguity
              U                        Reverse each piece
               F                       Concatenate the pieces back into a list
                ©                      Store the value in a register
                                     Then, on the accumulated list of results:
                             2\        Look at each consecutive pair of results
                    ,       ¥  ;/      and return the first element, followed by
                      +32Ọ$            the character with code 32 plus
                     n     ¥           1 (if unequal), 0 (if equal)
                                 ®ṭ  Append the value of the register
                                   G Output in grid form

Пример, показанный в ссылке TIO, является особенно сложным для этой программы; ;0вблизи начала необходимо убедиться , что цикл заканчивается как раз в тот момент , когда вход становится отсортированный. Обычно это не требуется (потому что это закончится после еще одной итерации), но если последний обмен состоит из первых двух элементов (как показано здесь), еще одна итерация не произойдет и сделает невозможным завершение список последовательно. Таким образом, мы должны убедиться, что мы ничего не меняем на последней итерации цикла.


источник