Sorting algorithms/Gnome sort

From Rosetta Code
Revision as of 17:15, 24 June 2009 by rosettacode>Kevin Reid (add E example)
Task
Sorting algorithms/Gnome sort
You are encouraged to solve this task according to the task description, using any language you may know.
This page uses content from Wikipedia. The original article was at Sorting algorithms/Gnome sort. The list of authors can be seen in the page history. As with Rosetta Code, the text of Wikipedia is available under the GNU FDL. (See links for details on variance)

Gnome sort is a sorting algorithm which is similar to Insertion sort, except that moving an element to its proper place is accomplished by a series of swaps, as in Bubble Sort.

The pseudocode for the algorithm is:

 function gnomeSort(a[0..size-1]) {
  i := 1
  j := 2
  while i < size
    if a[i-1] <= a[i] # for descending sort, reverse the comparison to >=
        i := j
        j := j + 1 
    else
        swap a[i-1] and a[i]
        i := i - 1
        if i = 0
          i := j
          j := j + 1
 }

Task: implement the Gnome sort in your language to sort an array (or list) of numbers.

ALGOL 68

Works with: ALGOL 68 version Standard - no extensions to language used
Works with: ALGOL 68G version Any - tested with release mk15-0.8b.fc9.i386
Works with: ELLA ALGOL 68 version Any (with appropriate job cards AND formatted transput statements removed) - tested with release 1.8.8d.fc9.i386

<lang algol>MODE SORTSTRUCT = CHAR;

PROC inplace gnome sort = (REF[]SORTSTRUCT list)REF[]SORTSTRUCT: BEGIN

 INT i:=LWB list + 1, j:=LWB list + 2;
 WHILE i <= UPB list DO
   IF list[i-1] <= list[i] THEN
     i := j; j+:=1
   ELSE
     SORTSTRUCT swap = list[i-1]; list[i-1]:= list[i]; list[i]:= swap;
     i-:=1;
     IF i=LWB list THEN i:=j; j+:=1 FI
   FI
 OD;
 list

END;

PROC gnome sort = ([]SORTSTRUCT seq)[]SORTSTRUCT:

 in place gnome sort(LOC[LWB seq: UPB seq]SORTSTRUCT:=seq);

[]SORTSTRUCT char array data = "big fjords vex quick waltz nymph"; print((gnome sort(char array data), new line))</lang> Output:

     abcdefghiijklmnopqrstuvwxyz

AutoHotkey

contributed by Laszlo on the ahk forum <lang AutoHotkey> MsgBox % GnomeSort("") MsgBox % GnomeSort("xxx") MsgBox % GnomeSort("3,2,1") MsgBox % GnomeSort("dog,000000,xx,cat,pile,abcde,1,cat,zz,xx,z")

GnomeSort(var) {  ; SORT COMMA SEPARATED LIST

  StringSplit a, var, `,                ; make array, size = a0
  i := 2, j := 3
  While i <= a0 {                       ; stop when sorted
     u := i-1
     If (a%u% < a%i%)                   ; search for pairs to swap
        i := j, j := j+1
     Else {                             ; swap
        t := a%u%, a%u% := a%i%, a%i% := t
        If (--i = 1)                    ; restart search
           i := j, j++
     }
  }
  Loop % a0                             ; construct string from sorted array
     sorted .= "," . a%A_Index%
  Return SubStr(sorted,2)               ; drop leading comma

}</lang>

BASIC

Works with: QuickBasic version 4.5
Translation of: C

<lang qbasic>dim a(0 to n-1) as integer '...more code... sort: i = 1 j = 2

while(i < ubound(a) - lbound(a))

 if a(i-1) <= a(i) then
   i = j
   j = j + 1
 else 
   swap a(i-1), a(i)
   i = i - 1
   if i = 0 then
      i = j
      j = j + 1
   end if
 end if

wend</lang>

C

This algorithm sorts in place modifying the passed array (of n integer numbers).

<lang c>#define swap_(I,J) do { int t_; t_ = a[(I)]; \

     a[(I)] = a[(J)]; a[(J)] = t_; } while(0)

void gnome_sort(int *a, int n) {

 int i=1, j=2;

 while(i < n) {
   if ( a[i-1] <= a[i] ) {
     i = j; j++;
   } else {
     swap_(i-1, i);
     i--;
     i = (i==0) ? j++ : i;
   }
 }

}

  1. undef swap_</lang>

E

<lang e>def gnomeSort(array) {

   var size := array.size()
   var i := 1
   var j := 2
   while (i < size) {
       if (array[i-1] <= array[i]) {
           i := j
           j += 1
       } else {
           def t := array[i-1]
           array[i-1] := array[i]
           array[i] := t
           i -= 1
           if (i <=> 0) {
               i := j
               j += 1
           }
       }
   }

}</lang>

<lang e>? def a := [7,9,4,2,1,3,6,5,0,8].diverge()

  1. value: [7, 9, 4, 2, 1, 3, 6, 5, 0, 8].diverge()

? gnomeSort(a) ? a

  1. value: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9].diverge()</lang>

Fortran

Works with: Fortran version 90 and later

<lang fortran>program example

 implicit none

 integer :: array(8) = (/ 2, 8, 6, 1, 3, 5, 4, 7 /)
 call Gnomesort(array)
 write(*,*) array

contains

subroutine Gnomesort(a)

 integer, intent(in out) :: a(:)
 integer :: i, j, temp
 i = 2
 j = 3
 do while (i <= size(a))
   if (a(i-1) <= a(i)) then
     i = j
     j = j + 1
   else
     temp = a(i-1)
     a(i-1) = a(i)
     a(i) = temp
     i = i -  1
     if (i == 1) then
       i = j
       j = j + 1
     end if
   end if
 end do

end subroutine Gnomesort

end program example</lang>

Java

Translation of: C

<lang java>public static void gnomeSort(int[] a) {

 int i=1;
 int j=2;

 while(i < a.length) {
   if ( a[i-1] <= a[i] ) {
     i = j; j++;
   } else {
     int tmp = a[i-1];
     a[i-1] = a[i];
     a[i--] = tmp;
     i = (i==0) ? j++ : i;
   }
 }

}</lang>

Metafont

<lang metafont>def gnomesort(suffix v)(expr n) = begingroup save i, j, t;

 i := 1; j := 2;
 forever: exitif not (i < n);
   if v[i-1] <= v[i]:
     i := j; j := j + 1;
   else:
     t := v[i-1];
     v[i-1] := v[i];
     v[i] := t;
     i := i - 1;
     i := if i=0: j; j := j + 1 else: i fi;
   fi
 endfor

endgroup enddef;</lang>

<lang metafont>numeric a[]; for i = 0 upto 9: a[i] := uniformdeviate(40); message decimal a[i]; endfor message char10;

gnomesort(a, 10); for i = 0 upto 9: message decimal a[i]; endfor end</lang>

Pascal

<lang pascal>procedure gnomesort(var arr : Array of Integer; size : Integer); var

  i, j, t	: Integer;

begin

  i := 1;
  j := 2;
  while i < size do begin
     if arr[i-1] <= arr[i] then
     begin

i := j; j := j + 1

     end
     else begin

t := arr[i-1]; arr[i-1] := arr[i]; arr[i] := t; i := i - 1; if i = 0 then begin i := j; j := j + 1 end

     end
  end;

end;</lang>

Perl

<lang perl>use strict;

sub gnome_sort {

   my @a = @_;
   my $size = scalar(@a);
   my $i = 1;
   my $j = 2;
   while($i < $size) {

if ( $a[$i-1] <= $a[$i] ) { $i = $j; $j++; } else { @a[$i, $i-1] = @a[$i-1, $i]; $i--; if ($i == 0) { $i = $j; $j++; } }

   }
   return @a;

}</lang>

<lang perl>my @arr = ( 10, 9, 8, 5, 2, 1, 1, 0, 50, -2 ); print "$_\n" foreach gnome_sort( @arr );</lang>

Python

<lang python>>>> def gnomesort(a): i,j,size = 1,2,len(a) while i < size: if a[i-1] <= a[i]: i,j = j, j+1 else: a[i-1],a[i] = a[i],a[i-1] i -= 1 if i == 0: i,j = j, j+1 return a

>>> gnomesort([3,4,2,5,1,6]) [1, 2, 3, 4, 5, 6] >>> </lang>

Ruby

<lang ruby>class Array

 def gnomesort!
   i, j = 1, 2
   while i < length
     if self[i-1] <= self[i]
       i, j = j, j+1
     else
       self[i-1], self[i] = self[i], self[i-1]
       i -= 1
       if i == 0
         i, j = j, j+1
       end
     end
   end
   self
 end

end ary = [7,6,5,9,8,4,3,1,2,0] ary.gnomesort!

  1. => [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

</lang>

Smalltalk

<lang smalltalk>Smalltalk at: #gnomesort put: nil.

"Utility" OrderedCollection extend [

 swap: a with: b [ |t|
     t := self at: a.
     self at: a put: b.
     self at: b put: t
 ]

].

"Gnome sort as block closure" gnomesort := [ :c |

 |i j|
 i := 2. j := 3.
 [ i <= (c size) ]
   whileTrue: [
      (c at: (i-1)) <= (c at: i)
         ifTrue: [
            i := j copy.
            j := j + 1.
         ]
         ifFalse: [
            c swap: (i-1) with: i.
            i := i - 1.
            i == 1
              ifTrue: [
                 i := j copy.
                 j := j + 1
              ]
         ]
   ]

].</lang>

Testing

<lang smalltalk>|r o| r := Random new. o := OrderedCollection new.

1 to: 10 do: [ :i | o add: (r between: 0 and: 50) ].

gnomesort value: o.

1 to: 10 do: [ :i | (o at: i) displayNl ].</lang>

Tcl

Uses struct::list package from

Library: tcllib

<lang tcl>package require Tcl 8.5 package require struct::list

proc gnomesort {a} {

   set i 1
   set j 2
   set size [llength $a]
   while {$i < $size} {
       if {[lindex $a [expr {$i - 1}]] <= [lindex $a $i]} {
           set i $j
           incr j
       } else {
           struct::list swap a [expr {$i - 1}] $i
           incr i -1
           if {$i == 0} {
               set i $j
               incr j
           }
       }
   }
   return $a

}

puts [gnomesort {8 6 4 2 1 3 5 7 9}] ;# => 1 2 3 4 5 6 7 8 9</lang>