#lang racket/base (require racket/match racket/contract racket/dict "order.rkt") ;; owned by ryanc #| reference Skip Lists: A Probabilistic Alternative to Balanced Trees by William Pugh I take the "fix the dice" approach to avoiding level jumps. Levels are indexed starting at 1, as in the paper. |# #| (require (rename-in racket/unsafe/ops [unsafe-vector-length vector-length] [unsafe-vector-ref vector-ref] [unsafe-vector-set! vector-set!])) |# (define PROBABILITY-FACTOR 4) (define MAX-LEVEL 16) (define DATA-SLOTS 2) ;; An Item is ;; - (vector key data Item/#f Item/#f ...) ;; The Level of an Item is the number of next links it has (at least 1). ;; The head is an Item with key and data #f (never examined) ;; The end of the list is represented by #f (define (item? x) (vector? x)) (define (item-level item) (- (vector-length item) DATA-SLOTS)) (define (item-key item) (vector-ref item 0)) (define (item-data item) (vector-ref item 1)) (define (item-next item level) (vector-ref item (+ (+ level DATA-SLOTS) -1))) (define (set-item-key! item key) (vector-set! item 0 key)) (define (set-item-data! item data) (vector-set! item 1 data)) (define (set-item-next! item level next) (vector-set! item (+ (+ level DATA-SLOTS) -1) next)) (define (resize-item item level) (define new-size (+ DATA-SLOTS level)) (define new-item (make-vector new-size #f)) (vector-copy! new-item 0 item 0 (min (vector-length item) new-size)) new-item) ;; search : Item Nat Key Cmp Cmp -> Item/#f ;; Returns item(R) s.t. key(R) =? key (define (search head level key =? Item ;; Returns greatest item R s.t. key(R) = level, key(item) Item ;; Returns greatest item R s.t. key(R) = level. ;; Pre: level(item) >= level, key(item) Nat ;; Returns number in [1, max] (with exp. prob. dist.) (define (pick-random-level max) (let loop ([level 1]) (if (and (< level max) (zero? (random PROBABILITY-FACTOR))) (loop (add1 level)) level))) ;; update/insert : ... -> Item/#f ;; Updates skip-list so that key |-> data ;; Returns #f to indicate update (existing item changed); ;; returns item to indicate insertion (context's links need updating) ;; Pre: level(item) >= level, key(item) = (item-level result) level)) (let ([link (item-next item level)]) (set-item-next! item level result) (set-item-next! result level link))) result)] [else (let ([next (item-next item 1)]) (cond [(and next (=? (item-key next) key)) ;; Update! (set-item-data! next data) #f] [else ;; Insert! (let ([new-item (make-vector (+ DATA-SLOTS (pick-random-level max-level)) #f)]) (set-item-key! new-item key) (set-item-data! new-item data) new-item)]))])) ;; delete : ... -> Item/#f ;; Returns item to indicate deletion (context's links need updating); ;; returns #f if not found. ;; Pre: level(item) >= level; key(item) void ;; Pre: level(*-item) >= level; key(*-item) =? t-key (set-item-next! f-item level t-item*) (delete-range f-item t-item (sub1 level) f-key t-key =? t-key (set-item-key! item (- (item-key item) delta)) (loop (item-next item 1))))))])) ;; expand! : ... -> void (define (expand! item level from to =? from (set-item-key! item (+ (item-key item) delta)) (loop (item-next item 1)))))) ;; Skip list (define (skip-list-ref s key [default (skip-list-error key)]) (define head (skip-list-head s)) (define result (search head (item-level head) key (skip-list-=? s) (skip-list- (item-level result) (item-level head)) (let ([new-head (resize-item head (item-level result))]) (set-item-next! new-head (item-level result) result) (set-skip-list-head! s new-head))))) (define (skip-list-remove! s key) (define head (skip-list-head s)) (define =? (skip-list-=? s)) (define key (define (skip-list-iterate-least/>? s key) (let* ([head (skip-list-head s)] [= key (define (skip-list-iterate-least/>=? s key) (let* ([head (skip-list-head s)] [list s) (let loop ([item (item-next (skip-list-head s) 1)]) (if item (cons (cons (item-key item) (item-data item)) (loop (item-next item 1))) null))) ;; ============================================================ (define dict-methods (vector-immutable skip-list-ref skip-list-set! #f ;; set skip-list-remove! #f ;; remove skip-list-count skip-list-iterate-first skip-list-iterate-next skip-list-iterate-key skip-list-iterate-value)) (define ordered-dict-methods (vector-immutable skip-list-iterate-least skip-list-iterate-greatest skip-list-iterate-least/>? skip-list-iterate-least/>=? skip-list-iterate-greatest/* () (order? #:key-contract contract? #:value-contract contract?) skip-list?)] [make-adjustable-skip-list (->* () (#:key-contract contract? #:value-contract contract?) adjustable-skip-list?)] [skip-list? (-> any/c boolean?)] [adjustable-skip-list? (-> any/c boolean?)] [skip-list-ref (->i ([s skip-list?] [k (s) (key-c s)]) ([d any/c]) any)] [skip-list-set! (->i ([s skip-list?] [k (s) (key-c s)] [v (s) (val-c s)]) [_r void?])] [skip-list-remove! (->i ([s skip-list?] [k (s) (key-c s)]) [_r void?])] [skip-list-count (-> skip-list? exact-nonnegative-integer?)] [skip-list-remove-range! (->i ([s skip-list?] [from (s) (key-c s)] [to (s) (key-c s)]) [_r void?])] [skip-list-contract! (->i ([s adjustable-skip-list?] [from (s) (key-c s)] [to (s) (key-c s)]) [_r void?])] [skip-list-expand! (->i ([s adjustable-skip-list?] [from (s) (key-c s)] [to (s) (key-c s)]) [_r void?])] [skip-list-iterate-first (-> skip-list? (or/c skip-list-iter? #f))] [skip-list-iterate-next (-> skip-list? skip-list-iter? (or/c skip-list-iter? #f))] [skip-list-iterate-key (->i ([s skip-list?] [i skip-list-iter?]) [_r (s) (key-c s)])] [skip-list-iterate-value (->i ([s skip-list?] [i skip-list-iter?]) [_r (s) (val-c s)])] [skip-list-iterate-greatest/<=? (->i ([s skip-list?] [k (s) (key-c s)]) [_r (or/c skip-list-iter? #f)])] [skip-list-iterate-greatest/i ([s skip-list?] [k (s) (key-c s)]) [_r (or/c skip-list-iter? #f)])] [skip-list-iterate-least/>=? (->i ([s skip-list?] [k (s) (key-c s)]) [_r (or/c skip-list-iter? #f)])] [skip-list-iterate-least/>? (->i ([s skip-list?] [k (s) (key-c s)]) [_r (or/c skip-list-iter? #f)])] [skip-list-iterate-least (-> skip-list? (or/c skip-list-iter? #f))] [skip-list-iterate-greatest (-> skip-list? (or/c skip-list-iter? #f))] [skip-list-iter? (-> any/c any)] [skip-list->list (-> skip-list? list?)])