Wizualizuj sortowanie


20

Powiedzmy, że mam listę [3, 0, 4, 2, 1]i używam sortowania selekcji, aby ją posortować, mógłbym to sobie wyobrazić w następujący sposób:

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

Wyzwanie polega na wizualizacji takiego sortowania.

Wejście

Twoje dane wejściowe będą listą liczb całkowitych dodatnich w dowolnym formacie.

Zadanie

Twoje zgłoszenie powinno posortować listę danych wejściowych poprzez zamianę tylko dwóch elementów jednocześnie, a przy każdej wymianie zgłoszenie powinno wyświetlać listę oraz znak pod każdym z wymienianych elementów. Jeśli zamieniona liczba ma więcej niż jedną cyfrę, znak może znajdować się gdziekolwiek pod nią. Na koniec przesłanie powinno wyświetlić posortowaną listę.

Inne zasady

  • Sortowanie musi wykorzystywać mniej swapów niż n 4 , gdzie n jest długością listy.
  • Sortowanie nie musi być deterministyczne.
  • Znaki pod zamianą mogą być dowolnymi znakami oprócz spacji.

Czy mogę założyć, że liczby całkowite są unikalne?
Jörg Hülsermann

n^4? Jesteś tu trochę hojny.
lub

@ JörgHülsermann No
Loovjo

2
Jeśli ktoś jest zainteresowany sortowaniem toptal.com/developers/sorting-algorithms
exussum 10.10.16

3
Mówisz, że wejście jest całkowite dodatnie, ale Twój przykład ma 0(proszę ustalić tylko przykład, tak nie do unieważnienia odpowiedzi, które nie mogą obsługiwać 0)
Ton Hospel

Odpowiedzi:


10

Perl, 62 bajty

Obejmuje +3 za -p

Podaj dane jako pojedynczy wiersz liczb na STDIN:

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

Wielokrotnie zamienia pierwszą inwersję. Złożoność wymiany to O(n^2)złożoność czasu O(n^3). Używa zamienianych liczb jako znaku:

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

Program obsługuje również wartości ujemne i liczby zmiennoprzecinkowe

Jeśli nalegasz na znak łączący, kod staje się 66 bajtami:

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

Ale teraz nie obsługuje już liczb ujemnych i 0 (ale program i tak musi obsługiwać tylko dodatnie liczby całkowite. W 0tym przykładzie jest błąd)


Biorąc pod uwagę, że The characters under the swapped can be any char except space. nie powinieneś mieć spacji między liczbą w linii znaku
edc65

@ edc65 Znak (i) pod zamienianymi elementami nie jest spacją. Nic nie mówi się o postaciach między nimi
Ton Hospel,

Nie do końca przekonany, ale w porządku. Byłem zbyt szybki w głosowaniu w dół (ale zwróciłem twoją uwagę). Jeśli wprowadzisz (pustą) zmianę w swojej odpowiedzi, zmienię mój głos
edc65,

@ edc65 Twój komentarz bardzo zmusił mnie do ponownego przeczytania wyzwania. Zauważ, że mówi on również o przypadku liczb wielocyfrowych, co oznacza, że ​​możesz np. Po prostu wstawić _pierwszą cyfrę, co oznacza, że ​​wszystkie znaki między nimi byłyby w rzeczywistości spacjami). Dlatego trzymam się mojej interpretacji (chyba że OP oczywiście się nie zgadza). Buit tylko po to, żeby cię uszczęśliwić. Dodałem też wersję bez miejsca :-)
Ton Hospel,

9

JavaScript (ES6), 158 bajtów

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}}

Sortowanie bąbelkowe. Przykładowe dane wyjściowe:

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 Ponieważ zawsze wymieniam sąsiednie elementy, zawsze mogę umieścić -pod ,i wtedy dwa |s będą zawsze pod sąsiednimi liczbami.
Neil,

aa, sprytne! Dzięki!
nimi

1
Sortowanie bąbelkowe jest naprawdę rozsądnym wyborem, aby uprościć podświetlanie zamienionych liczb. Dobra robota!
Arnauld,

9

PHP, 248 bajtów

Nudne wygrywanie w 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 bajtów sposobem z array_slice i min

zmodyfikowane wyjście I Xzamiast*~~*

<?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 bajtów

<?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";}

Jak to działa

Szuka minimum w tablicy i bierze to na pierwszej pozycji. Szukaj minimum bez pierwszej pozycji .... i tak dalej. Jeśli wartość jest podwójna, pierwsza wartość zostanie zamieniona

Przykład wyjściowy

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

Zamiast tego echo$t."\n";możesz użyć echo"$t\n";i zapisać bajt.
Ismael Miguel

@ IsmaelMiguel Zapraszam do edytowania moich postów, jeśli znajdziesz coś do ulepszenia
Jörg Hülsermann

7
Edycje kodu w postach są zwykle niezadowolone, z czym całkowicie się zgadzam.
Ismael Miguel

3

Haskell, 165 164 162 bajtów

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=""
([]#)

To wizualizuje sortowanie według wyboru. Przykład użycia:

*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]
                                         |

Jak to działa:

s % cto funkcja pomocnicza, która tworzy length (show s) - 2kopie postaci c. Służy do odstępów przed |jednym c == ' 'i drugim razem c == '-'.

Główna funkcja #przyjmuje listę, pktóra jest posortowaną częścią listy, a xktóra jest jeszcze częścią do posortowania. Dopasowanie wzorca (h,t:s)<-span(/=minimum x)xdzieli listę xprzy minimalnym elemencie i wiąże hsię z częścią przed minimum, tz samym minimum i sczęścią po minimum. Reszta to formatowanie dwóch wierszy: 1) listy w jej obecnym stanie ( p++x) i 2) |----|części, po której następuje rekurencyjne wywołanie #z tdopisanym do pi nagłówkiemh wstawiony między ogonem hi s.

PS: działa również z liczbami ujemnymi i / lub zmiennoprzecinkowymi:

*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]
                |

Edycja: @BlackCap zapisał 2 bajty. Dzięki!


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

1

Python 2, 267 bajtów

Działa również z liczbami dziesiętnymi i ujemnymi.

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))

Przykład:

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

Używanie n * n porównuje, ale (uważam) minimalną liczbę zamian. A pozycje zamiany są bardziej zmienne w porównaniu do nudnego rodzaju bąbelków.

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)

Mniej golfa i, mam nadzieję, bardziej zrozumiałe

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

Test

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>


0

Java 7, 256 241 282 bajtów

Dzięki @Geobits i @Axelh za oszczędność 15 bajtów

 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();}}

Nie golfił

 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();        

}
}

wynik

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 

4
Nadal brakuje deklaracji out, musisz umieścić coś PrintStream out=System.out;w kodzie.
Loovjo,

2
Po ustaleniu importu / deklaracji outnależy użyć trójki zamiast, if/elsejeśli zamierzasz drukować na obu gałęziach. Coś jak out.print(a>b?a:b);zamiastif(a>b)out.print(a);else out.print(b);
Geobits 10.10.16

Możesz zmniejszyć if else liek to: if(j==i|j==m)out.print(a[j]);out.print(" ");lub jeszcze lepiej za pomocą trójskładnika, out.print((j==i|j==m?a[j]:" ")+" ");a następnie możesz usunąć {} z pętli PS: Używam statycznego importu dla instancji
wyjściowej

Hmm, poza wskazówkami golfowymi od innych, wynik jest niepoprawny .. Oto ideone z twoim kodem wklejonym w kopie (i dodanym System.przed outs), i brakuje w nim 2i 3na dwóch ostatnich liniach wymiany.
Kevin Cruijssen

@KevinCruijssen Poprawiłem. Właściwie mieszam zmienną i ze zmienną j (powinno być i) w tym wierszufor(j=0;j<=m&i!=l-1;j++)
Numberknot

0

Galaretka , 36 bajtów

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

Wypróbuj online!

Wyjaśnienie

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

Przykład pokazany w łączu TIO jest szczególnie trudny dla tego programu; ;0blisko początku jest konieczne w celu zapewnienia, że pętla kończy się właśnie w momencie, gdy wejście zostanie posortowana. Zwykle nie jest to konieczne (ponieważ zakończy się po kolejnej iteracji), ale jeśli ostatnia zamiana dotyczy pierwszych dwóch elementów (jak pokazano tutaj), kolejna iteracja nie nastąpi i uniemożliwi ukończenie lista konsekwentnie. W związku z tym musimy upewnić się, że nie zamieniamy niczego podczas ostatniej iteracji pętli.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.