Added counting-sort

If you have the opportunity to use a counting sort, you should.
1 files changed, 28 insertions(+), 0 deletions(-)

A => counting-sort.scm
A => counting-sort.scm +28 -0
@@ 0,0 1,28 @@ 
+;; PUBLIC DOMAIN or CC0 - whatever fits your use-case or jurisdiction best
+;;
+;; sort-u8 sorts a list of unsigned bytes using a simple counting sort.
+;; about 30x faster than guile's built in sort for one million random bytes.
+;; For additional speedup you can make a sort-u8! that overwrites the list
+;; in place.
+(use-modules ((srfi srfi-43) #:select (vector-fold)))
+
+(define (sort-u8 ls <?)
+  (define vec (make-vector 256 0))
+  ;; populate the vector with the contents of ls
+  (let loop ((ls ls))
+    (unless (null? ls)
+      (vector-set! vec (car ls) (+ (vector-ref vec (car ls)) 1))
+      (loop (cdr ls))))
+
+  ;; turn vec into an alist of (index . count) and sort by index
+  (let* ((ls (vector-fold (lambda (i state val) (cons (cons i val) state)) '() vec))
+         (ls (sort ls (lambda (l r) (<? (car l) (car r))))))
+    ;; build a list from the alist
+    (let outer ((ls ls))
+      (if (null? ls)
+          '()
+          (let ((byte (caar ls)))
+            (let inner ((n (cdar ls)))
+              (if (zero? n)
+                  (outer (cdr ls))
+                  (cons byte (inner (- n 1))))))))))