I wrote the following Forth code for sorting a string with the Bubble Sort method.
It looks nice to my eyes, but I'd like your experienced opinion and any comments about the code you might have.
- In the
compare-and-swap-next
word, is using the return stack to save base address of string ok? - the
bubblesort
word uses2 pick
which is not so bad? A previous version had5 pick
(!), anyway ... is2 pick
fine: don't overthink about that or maybe try some more refactoring? - How would I go about adding a check for any swaps in each round and terminate the sort early? A variable? A stack cell (on TOS)? Rethink all of the implementation?
: compare-and-swap-next ( string i -- )
2dup + dup >r c@ rot rot 1 + + c@ 2dup >
if r@ c! r> 1 + c!
else r> drop 2drop
then ;
: bubblesort ( string len -- string len )
dup 1 -
begin dup 0>
while dup 0
do 2 pick i compare-and-swap-next
loop
1 -
repeat
drop ;
\ s" abracadabra" bubblesort \ cr type
\ s" The quick brown fox" bubblesort \ cr type
\ s" a quick brown fox jumps over the lazy dog." bubblesort \ cr type
Code available on github
Nitpicks welcome! Pedantism welcome!
Thank you!
1 Answer 1
To address your immediate concerns,
Using the return stack for storing your temporaries is a perfectly valid technique.
pick
is always frown upon (as well astuck
,roll
, and friends). It seems that thelen
parameter tobubblesort
does not participate in computation - except the very beginning - and mostly just stays in the way. Consider: bubblesort dup >r 1- ....
and use over
instead of 2 pick
(don't forget to r>
the length at the end).
I prefer a slightly different formatting of conditional. Consider
2dup > if
r@ c! r> 1 + c! else
r> drop 2drop then ;
Same for the loops. Consider
: bubblesort ( string len -- string len )
dup 1 - begin
dup 0> while
dup 0 do
2 pick i compare-and-swap-next
loop
1 -
repeat
drop ;
Keeping control words together with their respective conditions/actions looks more Forthy for me.
r> drop
is also known as rdrop
.
rot rot
is also known as -rot
.