差分リストを作ることを試してみた。
全部実装していないけど。ベンチマークに必要な分だけ実装。
差分リストについて
差分リストはリストのようなもの。appendがO(1)でできるのがlistとの違い
データ構造 | cons | snoc | append | listから変換 | listに変換 |
リスト | O(1) | O(N) | O(N) | - | - |
差分リスト | O(1) | O(1) | O(1) | O(N) | O(N) |
ただし、リストに変換する時にはO(N)のコスト
snocはconsの逆
(snoc '(1 2) 3) => '(1 2 3)
impl
;; definition (define (DL undl) (lambda () undl)) (define (list->dl xs) (fold-right dlcons (dlempty) xs)) (define (dl->list dl) ((dl) '())) (define (dlempty) (DL identity)) (define (dlcons x xs) (DL (compose (cut cons x <>) (xs)))) (define (dlsnoc xs x) (DL (compose (xs) (cut cons x <>)))) (define (dlappend xs ys) (DL (compose (xs) (ys)))) ;; how to use (dl->list (dlempty)) ; => () (dl->list (dlcons 1 (dlempty))) ; => (1) (dl->list (dlcons 2 (dlcons 1 (dlempty)))) ; => (2 1) (define xs (dlcons 2 (dlcons 1 (dlempty)))) (define ys (dlcons 'a (dlcons 'b (dlempty)))) (dl->list (dlappend xs ys)) ; => (2 1 a b) (dl->list (dlsnoc xs 3)) ; => (2 1 3)
benchmark
ちなみにgaucheのversionは0.9.1
gosh -V Gauche scheme shell, version 0.9.1 [utf-8,pthreads], x86_64-pc-linux-gnu
;; bench (use srfi-1) ;iota ;; list (let1 xs (iota 10000) (time (dotimes (i 1000) (append xs xs))) (equal? (append xs xs) (append xs xs))) ;; difference list (let* ((xs (iota 10000)) (xs* (list->dl xs))) (time (dotimes (i 1000) (dlappend xs* xs*))) (equal? (append xs xs) (dl->list (dlappend xs* xs*))))
appendは早い。
gosh> ;(time (dotimes (i 1000) (append xs xs))) ; real 0.307 ; user 0.300 ; sys 0.000 ;(time (dotimes (i 1000) (dlappend xs* xs*))) ; real 0.001 ; user 0.000 ; sys 0.000 #t
ただ、変換する部分の処理で時間はかかる。
(time (begin (iota 100000) #t)) (time (begin (list->dl (iota 100000)) #t))
;(time (begin (iota 100000) #t)) ; real 0.014 ; user 0.010 ; sys 0.000 ;(time (begin (list->dl (iota 100000)) #t)) ; real 0.197 ; user 0.160 ; sys 0.030 #t
!
関数をたくさん作るのでメモリ消費がすごいです。(1000万個の要素を作った時にメモリが枯渇しました)