Page 1 of 2 12>
Topic Options
#70350 - 2002-09-27 05:58 PM Super-quick iterative quicksort!!!
BrianTX Offline
Korg Regular

Registered: 2002-04-01
Posts: 895
This is faster than combsort on my system..

I'm using a quicksort algorithm iteratively with 2 stacks set up to hold pointers to the lower and upper level of each segment being sorted. The size of the stacks could be increased if you were sorting millions of items... but it probably isn't necessary.

What do you guys think? Should I add features/get rid of bad programming pieces?

code:
function qs($a)
DIM $ls[32],$us[32],$sp,$L,$U,$m,$p,$i,$j,$t
$ls[0]=0
$us[0]=UBOUND($a)
$sp=0
While $sp >=0
$l=$ls[$sp]
$u=$us[$sp]
While $L < $U
$p=$L+($U-$L)/2
$t=$a[$L]
$A[$L]=$A[$P]
$A[$P]=$t
$i=$L+1
$j=$U
:L1
While ($i<$j) AND $A[$L] > $A[$i]
$i=$i+1
Loop
While ($j>=$i) AND $A[$j] > $A[$L]
$j=$j-1
Loop
IF $i >= $j goto L2 ENDIF
$t=$A[$i]
$A[$i]=$A[$j]
$A[$j]=$t
$j=$j-1
$i=$i+1
Goto L1
:L2
$t=$a[$l]
$a[$l]=$a[$j]
$a[$j]=$t
$m=$j
If $m-$l <= $u - $m
If $m+1 < $u
$ls[$sp]=$m+1
$us[$sp]=$u
$sp=$sp+1
Endif
$u=$m-1
Else
If $m-1 > $l
$ls[$sp]=$l
$us[$sp]=$m-1
$sp=$sp+1
Endif
$l=$m+1
Endif
Loop
$sp=$sp-1
Loop
$qs=$a
Endfunction

On my system:

at 10,000 random elements:
combsort takes 90% longer
at 1,000 random elements:
combsort takes 50% longer
at 100 random elements:
combsort takes 33% longer
.....

When the number of elements is < 12, quicksort takes longer on average, but still under 20 ticks on a PIII-400/Win95 system.

Brian

P.S. .. anyone want to try to add multi-dimensional array capabilities?

Top
#70351 - 2002-09-27 07:02 PM Re: Super-quick iterative quicksort!!!
Shawn Administrator Offline
Administrator
*****

Registered: 1999-08-13
Posts: 8611
VERY NICE ... findings confirmed on my system ... well done ... put this into the UDF forum for sure ... question: is this "a" quick sort method or "the" quicksort method ? Is there more than one quicksort method ? Wow ... now your talking ... should see if you (we) can improve this algorithm even more ... or is it already optimized. Would take me a week just to understand this puppy [Wink]
Top
#70352 - 2002-09-27 07:08 PM Re: Super-quick iterative quicksort!!!
Shawn Administrator Offline
Administrator
*****

Registered: 1999-08-13
Posts: 8611
Could you post a little bit of a $variable "legend" in a seperate post (I know you kept your $variable names short cause it speeds things up) !!! Kinda like :

code:
$a  = array
$ls = lower "whatever"
$us = upper "whatever"



[ 27. September 2002, 19:09: Message edited by: Shawn ]

Top
#70353 - 2002-09-27 07:51 PM Re: Super-quick iterative quicksort!!!
BrianTX Offline
Korg Regular

Registered: 2002-04-01
Posts: 895
Hmm. I would say this is "the" quicksort method (well, I don't really know, but I'm guessing). I slightly modified an algorithm I found. I did one or two things to make it look nicer (instead of breaking out of a loop with goto) but those things actually add 2 comparisons (the AND in the while loops) in some cases, so they may slow it down a hair. I suppose I could take them out to see if performance increases. Also, if I wanted to lengthen the script a bit, I could add an insertion sort for segments smaller than 12 items to speed it up further.

Back to the question of whether or not it is "the" quicksort method, hmm. Well, according to the documentation I was reading, the recursive method is called quicksort and the iterative is called qsort.... So, I'm not sure if that was a distinction made by just the author or what, but I'll just call it iterative quicksort. I've looked at several different versions of quicksort, and this one seems to be the best I've found that is not recursive.

Naw.. it wouldn't take you that long:
$a - array
$ls - lower index stack
$us - upper index stack
$sp - stack pointer
$L - lower index
$U - upper index
$i - counter moving from lower index to the right
$j - counter moving from upper index to the left
$p - value of pivot
$t - temp variable for swapping elements
$m - stores either lower or upper index of unsorted segment of the array

If you want to understand the algorithm, it works like this:
1. choose a pivot point
2. swap the elements so that all the elements greater than the pivot are on the right, and all the elements less than are on the left. The pivot point will end up in its correct final position.
3. There will be an unsorted array to the left and right of the pivot, so sort the smaller of the two and put the lower and upper bound of the larger array on the stacks.
4. Continue until each segment is sorted, pulling the lower and upper bound of the unsorted segments of the array off the stack in sequence.

......

There are some nuances to the procedure, but this is the general idea.

Brian

Top
#70354 - 2002-09-27 08:29 PM Re: Super-quick iterative quicksort!!!
Lonkero Administrator Offline
KiX Master Guru
*****

Registered: 2001-06-05
Posts: 22346
Loc: OK
wait a sec...

no $-var used there... how's that?
_________________________
!

download KiXnet

Top
#70355 - 2002-09-27 08:40 PM Re: Super-quick iterative quicksort!!!
NTDOC Administrator Offline
Administrator
*****

Registered: 2000-07-28
Posts: 11624
Loc: CA
Thanks for the post Brian.

Using this script to read registry data, your script is a little faster on my system.

The CombSort time is: 631 msec
The QS Sort time is: 541 msec

My system has almost 200 software installs on the keys being read into the array.

code:
Break on
$aStart=@ticks

;******************************************

;$software = combsort(getinstalledsoftware)
$software = qs(getinstalledsoftware)

;*******************************************


$aStop=@ticks
? "Running Time is: " $aStop-$aStart
Return

function GetInstalledsoftware
Dim $softwarekey, $index
dim $temparray[10]

$SoftwareKey = enumkey("HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\",$Index)

while not @error
$DisplayName = readvalue("HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\$SoftwareKey","displayname")
$DisplayVersion = readvalue("HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\$SoftwareKey","DisplayVersion")
if $DisplayName
if $count > ubound($temparray)
redim preserve $temparray[ubound($temparray)+10]
endif
$temparray[$count] = $DisplayName +" "+ $DisplayVersion
$count = $count + 1
endif
$Index = $Index + 1
$SoftwareKey = enumkey("HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\",$Index)
loop
if $count > 0
redim preserve $temparray[$count-1]
else
$temparray = ""
endif
$getinstalledsoftware = $temparray
endfunction


Function CombSort($v, Optional $o)
Dim $i,$j,$m,$s,$g
$n=UBound($v)
$g = $n
If $g
While $g > 1 Or Not $s
$g=($g*1000)/1279
If $g < 1
$g = 1
EndIf
$s=1
For $i = 0 To $n-$g
$j=$i+$g
If ($v[$i] > $v[$j] And Not $o) Or ($v[$i] < $v[$j] And $o)
$m = $v[$i]
$v[$i] = $v[$j]
$v[$j] = $m
$s=0
EndIf
Next
Loop
$CombSort = $v
Else
$CombSort = 0
EndIf
EndFunction

function qs($a)
DIM $ls[32],$us[32],$sp,$L,$U,$m,$p,$i,$j,$t
$ls[0]=0
$us[0]=UBOUND($a)
$sp=0
While $sp >=0
$l=$ls[$sp]
$u=$us[$sp]
While $L < $U
$p=$L+($U-$L)/2
$t=$a[$L]
$A[$L]=$A[$P]
$A[$P]=$t
$i=$L+1
$j=$U
:L1
While ($i<$j) AND $A[$L] > $A[$i]
$i=$i+1
Loop
While ($j>=$i) AND $A[$j] > $A[$L]
$j=$j-1
Loop
IF $i >= $j goto L2 ENDIF
$t=$A[$i]
$A[$i]=$A[$j]
$A[$j]=$t
$j=$j-1
$i=$i+1
Goto L1
:L2
$t=$a[$l]
$a[$l]=$a[$j]
$a[$j]=$t
$m=$j
If $m-$l <= $u - $m
If $m+1 < $u
$ls[$sp]=$m+1
$us[$sp]=$u
$sp=$sp+1
Endif
$u=$m-1
Else
If $m-1 > $l
$ls[$sp]=$l
$us[$sp]=$m-1
$sp=$sp+1
Endif
$l=$m+1
Endif
Loop
$sp=$sp-1
Loop
$qs=$a
Endfunction


Top
#70356 - 2002-09-27 08:50 PM Re: Super-quick iterative quicksort!!!
Lonkero Administrator Offline
KiX Master Guru
*****

Registered: 2001-06-05
Posts: 22346
Loc: OK
doc...
quote:

My system has almost 200 software installs on the keys being read into the array.

are you one of those who never clean up their system nor un-installs anything... or is this machine only for testing purposes?
 
_________________________
!

download KiXnet

Top
#70357 - 2002-09-27 09:39 PM Re: Super-quick iterative quicksort!!!
BrianTX Offline
Korg Regular

Registered: 2002-04-01
Posts: 895
I'm glad I could help, doc! After further testing, the modification I made from the original algorithm seems to have sped up the function rather than slow it down:

While $a and $b
Loop

Runs faster than:

While $a
If not $b Goto out endif
Loop
:out

.....
I'm going to see if there are other changes that KiXtart would like.

Brian

Top
#70358 - 2002-09-27 09:50 PM Re: Super-quick iterative quicksort!!!
Chris S. Offline
MM club member
*****

Registered: 2002-03-18
Posts: 2368
Loc: Earth
You could change $a to just $ to lower your KiXGolf score, but it probably wouldn't be considered 'best practice.' [Big Grin]
Top
#70359 - 2002-09-27 10:02 PM Re: Super-quick iterative quicksort!!!
BrianTX Offline
Korg Regular

Registered: 2002-04-01
Posts: 895
Ha! I'm not worried about lowering the score.. I'm looking purely for speed. I'm wondering if smaller variable names would actually speed it up.... I notice that several comparisons are made prior to any elements being "swapped".. I don't really see how I can reduce them....

It would be SO nice to have a "SWAP" command in KiXtart.

Brian

Top
#70360 - 2002-09-27 10:02 PM Re: Super-quick iterative quicksort!!!
NTDOC Administrator Offline
Administrator
*****

Registered: 2000-07-28
Posts: 11624
Loc: CA
I'm a SOFTWARE Junky Lonkero.

I have that much software installed. I like to be able to run/fix/investigate a wide range of software to help both myself and others.

Top
#70361 - 2002-09-27 10:51 PM Re: Super-quick iterative quicksort!!!
Lonkero Administrator Offline
KiX Master Guru
*****

Registered: 2001-06-05
Posts: 22346
Loc: OK
doc, doesn't the system slow down as it has more soft to handle?

brian, if you are not running with goto, why you are having those ":L1" etc...

 
_________________________
!

download KiXnet

Top
#70362 - 2002-09-27 11:12 PM Re: Super-quick iterative quicksort!!!
BrianTX Offline
Korg Regular

Registered: 2002-04-01
Posts: 895
Here is a better description of the code:

Take $array=3,3,6,2,4,6,7,9,2

1. Set pivot to average index of 1st and last element to be sorted:

code:
$p=$L+($U-$L)/2

3,3,6,2,4,6,7,9,2


2. Exchange the pivot value with the lower value:

code:
$t=$a[$L]
$A[$L]=$A[$P]
$A[$P]=$t

4,3,6,2,3,6,7,9,2

3. Leave pivot point alone, and working with the other elements in the set, going from left to right, find a number greater than the pivot value.. working from right to left find a number less than the pivot value.

code:
$i=$L+1
$j=$U
:L1
While ($i<$j) AND $A[$L] > $A[$i]
$i=$i+1
Loop
While ($j>=$i) AND $A[$j] > $A[$L]
$j=$j-1
Loop

4,3,6,2,3,6,7,9,2

4. Swap these numbers.

code:
   IF $i >= $j goto L2 ENDIF
$t=$A[$i]
$A[$i]=$A[$j]
$A[$j]=$t

4,3,2,2,3,6,7,9,6

5. Continue to the right to find a larger number than the pivot, and to the left to find a smaller number. Repeat process.

code:
   $j=$j-1
$i=$i+1
Goto L1

4,3,2,2,3,6,7,9,6

6. If no other numbers to swap are found, exit loop.

code:
   IF $i >= $j goto L2 ENDIF

4,3,2,2,3,6,7,9,6

7. Swap pivot with the location the left and the right converge. Notice that the pivot is sorted and you can now split the array into two sets of numbers.

code:
   $t=$a[$l]
$a[$l]=$a[$j]
$a[$j]=$t

3,3,2,2,4,6,7,9,6

8. Set pointer to index where pivot ends up.

code:
   $m=$j

In this case $j is 4 so $m is set to 4

9. If set on the left has fewer or the same number of elements as the one on the right, put $m+1 index on the left stack and the right index on the right stack. Set upper index to the element left of the pivot. Otherwise do the reverse.

code:
   If $m-$l <= $u - $m
If $m+1 < $u
$ls[$sp]=$m+1
$us[$sp]=$u
$sp=$sp+1
Endif
$u=$m-1
Else
If $m-1 > $l
$ls[$sp]=$l
$us[$sp]=$m-1
$sp=$sp+1
Endif

3,3,2,2,4,6,7,9,6

StackL=5,0,0,0,0,0...
StackU=8,0,0,0,0,0...

Stack pointer changed to 1
Upper element of set = 3
Lower element of set = 0

3,3,2,2,4,6,7,9,6

9. Repeat process from 1 to 7. (loop)

a. swap pivot:

3,3,2,2, 4,[6,7,9,6]

2,3,3,2, 4, [6,7,9,6]

b. swap from greater than pivot from left with less than pivot from right:
2,3,3,2, 4,[6,7,9,6]

2,2,3,3, 4, [6,7,9,6]
-- no change in this case --
c. when right and left converge, swap pivot with convergence.

2,2,3,3, 4, [6,7,9,6]

Because this set is now sorted, no more swaps will take place.

10. The item on the stack is pulled off and the process is repeated until the sort is complete.

code:
While $sp >=0
$l=$ls[$sp]
$u=$us[$sp]

The set 6,7,9,6 is pointed to by the 5 and 8 of the stack pointer

The process is repeated for these:

choose pivot:
[2,2,3,3,4,] 6,7,9,6

find numbers to swap:
[2,2,3,3,4,] 7,6,9,6

[2,2,3,3,4,] 7,6,6,9

swap pivot into place where right and left meet:

[2,2,3,3,4,] 6,6,7,9

11. Sort finished:

2,2,3,3,4,6,6,7,9

Total swaps = 9
This is more efficient with larger data sets
Any questions? (I apologize.. I had pointers showing what numbers were related to what, but i had to delete them because they weren't lining up correctly.)

Brian

[ 27. September 2002, 23:20: Message edited by: BrianTX ]

Top
#70363 - 2002-09-27 11:15 PM Re: Super-quick iterative quicksort!!!
BrianTX Offline
Korg Regular

Registered: 2002-04-01
Posts: 895
To Lonkero:

I am using goto.. although I cut it out of a couple places... If you see a more graceful way for me to exit that particular loop, let me know!

Brian

Top
#70364 - 2002-09-30 11:02 PM Re: Super-quick iterative quicksort!!!
Lonkero Administrator Offline
KiX Master Guru
*****

Registered: 2001-06-05
Posts: 22346
Loc: OK
for the ones who don't know, it's now an udf in:
http://www.kixtart.org/cgi-bin/ultimatebb.cgi?ubb=get_topic;f=12;t=000273;p=1#000000
_________________________
!

download KiXnet

Top
#70365 - 2002-09-30 11:36 PM Re: Super-quick iterative quicksort!!!
Lonkero Administrator Offline
KiX Master Guru
*****

Registered: 2001-06-05
Posts: 22346
Loc: OK
I'm wondering... how should the multidimension array be sorted?

every part against it counterparts or each peace of dimension with same type of peaces?
or even all fields in all dimensions according to all fields?

then, adding there the ability for user to choose between those and say what is the sort-level...

the code would not be normal udf anymore!
it would be a collection of udf's...
 
_________________________
!

download KiXnet

Top
#70366 - 2002-09-30 11:52 PM Re: Super-quick iterative quicksort!!!
BrianTX Offline
Korg Regular

Registered: 2002-04-01
Posts: 895
Sorting on a single dimension and shuffling the data so that the other dimensions corresponded to the same data as before would be the way to go:

DIM $a[1,1]

$a[0,0]=1
$a[0,1]=0
$a[1,1]=2
$a[1,0]=3

A table:
--------2nd dimension
-------- 0 1
1st---0 1 0
------1 3 2

To sort this, you have to specify which row or column to sort. This causes a problem because there are 4 different ways to sort.

If you have more than 2 dimensions, it gets even dicier because you have to realign all of the other dimensions to the one you sort on.

(Major mindbender!!)

Brian

Top
#70367 - 2002-10-01 12:01 AM Re: Super-quick iterative quicksort!!!
Lonkero Administrator Offline
KiX Master Guru
*****

Registered: 2001-06-05
Posts: 22346
Loc: OK
eh?

that's what I mean. I can imagine one wanting to sort table parts and in such way I see a reason to sort 2dim array in some way.

but, as you get 20 dimensions, the idea probably is not anymore the same as mostlikely it's not consisting from just db/tables/fields of data but mostlikely arrays of arrays which are part of arrays inside arrays.

meaning, that the idea of multidim array is more complex than one could think.

and then, when it goes over 3/4 dimensions it is very likely to have stack overflow on every run.
thanks to some bug in kix...

so, I would leave that multidim sort out of the mind for a while... maybe in soon future it is possible anyway.
_________________________
!

download KiXnet

Top
#70368 - 2002-10-01 01:03 AM Re: Super-quick iterative quicksort!!!
BrianTX Offline
Korg Regular

Registered: 2002-04-01
Posts: 895
Hmm.. I suppose you could sort any dimension...

If you had:

DIM $a[$x,$y,$z]

You could sort any of the 3 dimensions.. (This would be a 0 index sort, kind of like starting in the corner of a rubik's cube and labelling 0 for each axis.) The problem would be that for each item in the $x dimension that you sort, $y*$z items would have to be moved as well. In addition to that, you might want to sort a different index. Unfortunately, KiXtart will not allow you to operate on a section of the array at a time. You have to assign values for each and every slot.

Brian

Top
#70369 - 2002-10-01 01:11 AM Re: Super-quick iterative quicksort!!!
Lonkero Administrator Offline
KiX Master Guru
*****

Registered: 2001-06-05
Posts: 22346
Loc: OK
eh, right... tweaks are again nice tools on this but. I quess anyway that it would still get to a point of stack overflow.

I get those with simple 2 dimensional arrays when nesting enough...

if you check the kixWeeper, you see what I mean.
so, can't even devel anything such complex before we get rid of those errors?
_________________________
!

download KiXnet

Top
Page 1 of 2 12>


Moderator:  Glenn Barnas, NTDOC, Arend_, Jochen, Radimus, Allen, ShaneEP, Ruud van Velsen, Mart 
Hop to:
Shout Box

Who's Online
0 registered and 369 anonymous users online.
Newest Members
rrosell, PatrickPinto, Raoul, Timothy, Jojo67
17877 Registered Users

Generated in 0.117 seconds in which 0.085 seconds were spent on a total of 14 queries. Zlib compression enabled.

Search the board with:
superb Board Search
or try with google:
Google
Web kixtart.org