Sorting Vectors
The Array class has a great function: sortOn(). It does a fast sort based on a property of each element of the array. Unfortunately, there is no equivalent in the Vector class. Below are some attempts to get around that limitation and preserve as much of the speed of sortOn() as possible.
First things first, nothing’s going to beat sortOn() here. You simply can’t beat native code with ActionScript, even if it is AS3. You can implement the fastest sorts straight out of the textbook and they will pale in comparison. I an ActionScript implementation of a quick sort and a shell sort and made up a test against sortOn() and sort(). Here is that test:
package { import flash.text.*; import flash.display.*; import flash.geom.*; import flash.utils.*; public class SortingVectors extends Sprite { public function SortingVectors() { var logger:TextField = new TextField(); logger.autoSize = TextFieldAutoSize.LEFT; addChild(logger); function log(msg:*): void { logger.appendText(msg+"\n"); } const NUM_ELEMENTS:uint = 500000; var v:Vector.<Point> = new Vector.<Point>(NUM_ELEMENTS); var v2:Vector.<Point> = new Vector.<Point>(NUM_ELEMENTS); var v3:Vector.<Point> = new Vector.<Point>(NUM_ELEMENTS); var a:Array = new Array(NUM_ELEMENTS); for (var i:int = 0; i < NUM_ELEMENTS; i++) { v[i] = v2[i] = v3[i] = a[i] = new Point(Math.random()*NUM_ELEMENTS, 0); } // Vector via sort() var startTime:int = getTimer(); v.sort(f); log("Vector via sort(): " + (getTimer()-startTime)); // 1642 startTime = getTimer(); v.sort(f); log("Vector via sort() on ordered elements: " + (getTimer()-startTime)); // 1262 // Array via sortOn() startTime = getTimer(); a.sortOn("x", Array.NUMERIC); log("Array via sortOn(): " + (getTimer()-startTime)); // 649 startTime = getTimer(); a.sortOn("x", Array.NUMERIC); log("Array via sortOn() on ordered elements: " + (getTimer()-startTime)); // 504 // Vector via quickSort() startTime = getTimer(); quickSort(v2, 0, NUM_ELEMENTS-1); log("Vector via quickSort(): " + (getTimer()-startTime)); // 5234 startTime = getTimer(); quickSort(v2, 0, NUM_ELEMENTS-1); log("Vector via quickSort() on ordered elements: " + (getTimer()-startTime)); // 3615 // Vector via shellSort() startTime = getTimer(); shellSort(v3); log("Vector via shellSort(): " + (getTimer()-startTime)); // 7406 startTime = getTimer(); shellSort(v3); log("Vector via shellSort() on ordered elements: " + (getTimer()-startTime)); // 4148 } // http://www.valveblog.com/2009/06/as3-sorting-algorithm-faster-than-native-sorting.html private function shellSort(data:Vector.<Point>): void { var n:int = data.length; var inc:int = int(n/2); while (inc) { for (var i:int = inc; i < n; i++) { var temp:Point= data[i], j:int = i; while (j >= inc && data[int(j - inc)].x > temp.x) { data[j] = data[int(j - inc)]; j = int(j - inc); } data[j] = temp } inc = int(inc / 2.2); } } private function f(p1:Point, p2:Point): int { return p1.x - p2.x; } // http://www.kirupa.com/developer/actionscript/quickSort.htm private function quickSort(arrayInput:Vector.<Point>, left:int, right:int): void { var i:int = left; var j:int = right; var pivotPoint:Point = arrayInput[Math.round((left+right)*.5)]; // Loop while (i<=j) { while (arrayInput[i].x < pivotPoint.x) { i++; } while (arrayInput[j].x > pivotPoint.x) { j--; } if (i <= j) { var tempStore:Point = arrayInput[i]; arrayInput[i] = arrayInput[j]; i++; arrayInput[j] = tempStore; j--; } } // Swap if (left < j) { quickSort(arrayInput, left, j); } if (i < right) { quickSort(arrayInput, i, right); } } } }
And here is a summary of the results on a 3.0 Ghz Intel Core 2 Duo running Windows XP:
Method | Unsorted | Pre-Sorted |
---|---|---|
Vector via sort() | 1603 | 1190 |
Array via sortOn() | 644 | 350 |
Vector via quickSort() | 3960 | 3027 |
Vector via shellSort() | 6142 | 3455 |
Vector via Array.sortOn() | 925 | 468 |
As we see, Array.sortOn() achieves an unbeatable time of 644 milliseconds. The closest any Vector competitor can come to this is to first convert to an Array then use Array.sortOn(), which incurs a 50% performance penalty as well as requiring the allocation and (probably) freeing of a potentially large Array. This extra memory allocation will require the creation of garbage for the garbage collector to collect, which will cause a performance hit later on in the program’s execution. Unfortunately, we don’t know when this will be and therefore can’t include it in the test results. As for approaches that don’t involve the creation of a lot of garbage, the next-closest competitor is Vector.sort() at 1603 milliseconds, about a 3x slowdown! The quickSort and shellSort approaches only slow this down further. Unfortunately, this is one area where Arrays dominate Vectors in performance. If one of your principle uses of the collection is to sort it, I strongly recommend against using a Vector as you will incur a huge penalty in that main case. If you rarely sort it or only sort it when performance is not critical, then it doesn’t really matter which one you use.
Keep this difference in mind when you’re considering which collection class to use. Vectors are not always faster.
#1 by Eugene on September 26th, 2009 ·
You Have really strange results here.
I’ve made some tests myself in the past:
http://blog.inspirit.ru/?p=271
In my tests using QuickSort and other sorting algos is faster
#2 by jackson on September 26th, 2009 ·
I think my results are correct, but that we’re testing two slightly different things. You’re testing sorting of a primitive type like Number and I’m testing sorting of a class type like Point. I’m essentially trying to make up for the lack of a Vector.sortOn(). I’ve read your blog post and admire all the lengths you’ve gone to; it’s definitely the most comprehensive list of alternative sorts for AS3. I’ve also noted your comment that you could split primitives (like triangles in 3D) out into separate vectors and sort those. I wonder: have you benchmarked that to see if the overhead of splitting out and using an indices vector is actually faster than using an Array with sortOn()? I’d be really interested to know! Thanks for the link and your sorting research.
#3 by Promethe on October 8th, 2009 ·
I’m using the Vector class to sort Face object on their depth property :
http://blog.promethe.net/2009/10/07/quake-2-3d-models-in-flash-10/
In my benchmarks, Array.sortOn is dramatically slower than Vector.sort !
#4 by jackson on October 8th, 2009 ·
That’s very interesting to hear. If you run my test above, do you get the same results I do? Perhaps there is something different in the way you and I have done our tests. Could you post your test? Just wrap it in a code block if you do:
<pre lang="actionscript3">
// code…
</pre>
#5 by Valentin on October 31st, 2009 ·
Array sort is indeed much slower than manual sort functions implementations on numbers.
#6 by jloa on March 9th, 2010 ·
omg, guys, why do u complicate yr life with such code?! O_O.
To do a Vector.sortOn u need only 5 code lines.
http://chargedweb.com/labs/2010/02/20/vector-sorton/
#7 by jackson on March 9th, 2010 ·
For CPU and memory performance. Converting to a temporary Array requires twice the memory and creates garbage to be collected right away. I can’t imagine it’s a very fast solution either, even disregarding the allocation and GC time. Have you performance tested it?
By the way, you could improve the performance of your implementation by using the new Array(size) constructor since you know how much many elements you need before doing the copy.
#8 by jloa on April 7th, 2010 ·
Well, all you have to do is to call the System.gc after the sorting operation, the gc will clean up the memory as the array is local-based.
Speaking of performance, nope, sincerely, i haven’t tested the performance, but still if you r making a web site and have a vector of 1000 elements eg will u care about the performance? :)
Yeap, i will test it and post the results.
#9 by jackson on April 7th, 2010 ·
In practice the Vector would probably not be local to the function but instead stored long-term as a field of an object. Even so, System.gc() only works in the debug version of Flash Player, which most people don’t have installed. As for caring about performance, it’s true that most Flash apps won’t care much about 1000 elements of a Vector, but larger, more resource-intensive ones can’t afford to ignore that kind of extra memory usage in many places before the app is too heavy for some users.
#10 by eco_bach on May 13th, 2010 ·
Jack
when you say ‘You simply can’t beat native code with ActionScript, ‘ I disagree. I the case of searching a large array with indexOf() vs a binary search, I believe the latter is always faster(as long as the array is sorted first).
http://stackoverflow.com/questions/1987163/binary-search-from-java-to-actionscript
#11 by jackson on May 13th, 2010 ·
It’s not really fair to compare the generalized indexOf that works with all arrays to a function that works only with sorted arrays. For example, it’d be just as unfair if I made a search function that only worked with arrays that only have two elements:
I’m sure that’s much faster than the binary search or indexOf… as long as you meet the special conditions. But that doesn’t mean I’ve “beaten” the native code.
#12 by bwhiting on July 29th, 2010 ·
have you tried just using an array for the sort then using that to build your vector?
http://blog.bwhiting.co.uk/?p=34
#13 by jackson on July 29th, 2010 ·
This post was about a year old and needed some updating to my new performance article format, so I did that and took the opportunity to integrate your suggestion (also the suggestion of jloa above). While your approach does create a large Array that the garbage collector may have to collect, it’s possible to have this pre-allocated and re-used so as to avoid the penalty. Under those conditions—where we don’t have to count the GC time—your approach is about 2x faster than Vector.sort(), the next-fastest Vector sorting approach.
Thanks for the tip!
#14 by Benjamin Guihaire on August 13th, 2013 ·
>You simply can’t beat native code with ActionScript, even if it is AS3.
Its possible, with flashSort, read this post:
http://guihaire.com/code/?p=894
I think its possible to go even faster with a good Radix implementation.
#15 by benjamin guihaire on August 19th, 2013 ·
Checkout this even faster As3 sort function !
http://guihaire.com/code/?p=681