diff --git a/goldfish/liii/sort.scm b/goldfish/liii/sort.scm new file mode 100644 index 0000000..50beef8 --- /dev/null +++ b/goldfish/liii/sort.scm @@ -0,0 +1,22 @@ +; +; Copyright (C) 2024 The Goldfish Scheme Authors +; +; Licensed under the Apache License, Version 2.0 (the "License"); +; you may not use this file except in compliance with the License. +; You may obtain a copy of the License at +; +; http://www.apache.org/licenses/LICENSE-2.0 +; +; Unless required by applicable law or agreed to in writing, software +; distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +; WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +; License for the specific language governing permissions and limitations +; under the License. +; + +(define-library (liii sort) +(export list-sorted? vector-sorted? + list-merge list-sort list-stable-sort vector-merge vector-sort vector-stable-sort + list-merge! list-sort! list-stable-sort! vector-merge! vector-sort! vector-stable-sort!) +(import (srfi srfi-132))) + diff --git a/goldfish/srfi/srfi-132.scm b/goldfish/srfi/srfi-132.scm new file mode 100644 index 0000000..d887677 --- /dev/null +++ b/goldfish/srfi/srfi-132.scm @@ -0,0 +1,110 @@ +; +; Copyright (C) 2024 The Goldfish Scheme Authors +; +; Licensed under the Apache License, Version 2.0 (the "License"); +; you may not use this file except in compliance with the License. +; You may obtain a copy of the License at +; +; http://www.apache.org/licenses/LICENSE-2.0 +; +; Unless required by applicable law or agreed to in writing, software +; distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +; WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +; License for the specific language governing permissions and limitations +; under the License. +; + +(define-library (srfi srfi-132) +(export list-sorted? vector-sorted? + list-merge list-sort list-stable-sort vector-merge vector-sort vector-stable-sort + list-merge! list-sort! list-stable-sort! vector-merge! vector-sort! vector-stable-sort!) +(import (liii list) + (liii error) + (scheme case-lambda)) +(begin + + (define (list-sorted? less-p lis) + (if (null? lis) + #t + (do ((first lis (cdr first)) + (second (cdr lis) (cdr second)) + (res #t (not (less-p (car second) (car first))))) + ((or (null? second) (not res)) res)))) + + ; TODO optional parameters + (define (vector-sorted? less-p v) + (let ((start 0) + (end (length v))) + (do ((first start (+ 1 first)) + (second (+ 1 start) (+ 1 second)) + (res #t (not (less-p (vector-ref v second) (vector-ref v first))))) + ((or (>= second end) (not res)) res)))) + + (define (list-merge less-p lis1 lis2) + (let loop + ((res '()) + (lis1 lis1) + (lis2 lis2)) + (cond + ((and (null? lis1) (null? lis2)) (reverse res)) + ((null? lis1) (loop (cons (car lis2) res) lis1 (cdr lis2))) + ((null? lis2) (loop (cons (car lis1) res) lis2 (cdr lis1))) + ((less-p (car lis2) (car lis1)) (loop (cons (car lis2) res) lis1 (cdr lis2))) + (else (loop (cons (car lis1) res) (cdr lis1) lis2))))) + + ; this list-merge! violates SRFI 132, since it does not satisfy the constant running space constraint specified in SRFI 132, and does not work "in place" + (define list-merge! list-merge) + + (define (list-stable-sort less-p lis) + (define (sort l r) + (cond + ((= l r) '()) + ((= (+ l 1) r) (list (list-ref lis l))) + (else + (let* ((mid (quotient (+ l r) 2)) + (l-sorted (sort l mid)) + (r-sorted (sort mid r))) + (list-merge less-p l-sorted r-sorted))))) + (sort 0 (length lis))) + + (define list-sort list-stable-sort) + (define list-sort! list-stable-sort) + (define list-stable-sort! list-stable-sort) + + (define vector-stable-sort + (case-lambda + ((less-p v) + (list->vector (list-stable-sort less-p (vector->list v)))) + ((less-p v start) + (list->vector (list-stable-sort less-p (subvector->list v start (vector-length v))))) + ((less-p v start end) + (list->vector (list-stable-sort less-p (subvector->list v start end)))))) + + (define vector-sort vector-stable-sort) + + (define (vector-sort! . r) (???)) + (define (vector-stable-sort! . r) (???)) + + (define (subvector->list v start end) + (do ((r '() (cons (vector-ref v p) r)) + (p start (+ 1 p))) + ((>= p end) (reverse r)))) + + (define vector-merge + (case-lambda + ((less-p v1 v2) + (list->vector (list-merge less-p (vector->list v1) (vector->list v2)))) + ((less-p v1 v2 start1) + (list->vector (list-merge less-p (subvector->list v1 start1 (vector-length v1)) (vector->list v2)))) + ((less-p v1 v2 start1 end1) + (list->vector (list-merge less-p (subvector->list v1 start1 end1) (vector->list v2)))) + ((less-p v1 v2 start1 end1 start2) + (list->vector (list-merge less-p (subvector->list v1 start1 end1) (subvector->list v2 start2 (vector-length v2))))) + ((less-p v1 v2 start1 end1 start2 end2) + (list->vector (list-merge less-p (subvector->list v1 start1 end1) (subvector->list v2 start2 end2)))))) + + (define (vector-merge! . r) (???)) + +) ; end of begin +) ; end of library + diff --git a/liii_sort.tmu b/liii_sort.tmu new file mode 100644 index 0000000..7d14c63 --- /dev/null +++ b/liii_sort.tmu @@ -0,0 +1,474 @@ +> + +> + +<\body> + + + + + <\scm-chunk|goldfish/liii/sort.scm|false|true> + ; + + ; Copyright (C) 2024 The Goldfish Scheme Authors + + ; + + ; Licensed under the Apache License, Version 2.0 (the "License"); + + ; you may not use this file except in compliance with the License. + + ; You may obtain a copy of the License at + + ; + + ; http://www.apache.org/licenses/LICENSE-2.0 + + ; + + ; Unless required by applicable law or agreed to in writing, software + + ; distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + + ; WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + + ; License for the specific language governing permissions and limitations + + ; under the License. + + ; + + \; + + + <\scm-chunk|goldfish/srfi/srfi-132.scm|false|true> + ; + + ; Copyright (C) 2024 The Goldfish Scheme Authors + + ; + + ; Licensed under the Apache License, Version 2.0 (the "License"); + + ; you may not use this file except in compliance with the License. + + ; You may obtain a copy of the License at + + ; + + ; http://www.apache.org/licenses/LICENSE-2.0 + + ; + + ; Unless required by applicable law or agreed to in writing, software + + ; distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + + ; WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + + ; License for the specific language governing permissions and limitations + + ; under the License. + + ; + + \; + + + <\scm-chunk|tests/goldfish/liii/sort-test.scm|false|true> + ; + + ; Copyright (C) 2024 The Goldfish Scheme Authors + + ; + + ; Licensed under the Apache License, Version 2.0 (the "License"); + + ; you may not use this file except in compliance with the License. + + ; You may obtain a copy of the License at + + ; + + ; http://www.apache.org/licenses/LICENSE-2.0 + + ; + + ; Unless required by applicable law or agreed to in writing, software + + ; distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + + ; WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + + ; License for the specific language governing permissions and limitations + + ; under the License. + + ; + + \; + + + + + <\scm-chunk|goldfish/liii/sort.scm|true|false> + (define-library (liii sort) + + (export list-sorted? vector-sorted? + + \ \ \ \ \ \ \ \ list-merge \ list-sort \ list-stable-sort \ vector-merge \ vector-sort \ vector-stable-sort + + \ \ \ \ \ \ \ \ list-merge! list-sort! list-stable-sort! vector-merge! vector-sort! vector-stable-sort!) + + (import (srfi srfi-132))) + + \; + + + <\scm-chunk|goldfish/srfi/srfi-132.scm|true|true> + (define-library (srfi srfi-132) + + (export list-sorted? vector-sorted? + + \ \ \ \ \ \ \ \ list-merge \ list-sort \ list-stable-sort \ vector-merge \ vector-sort \ vector-stable-sort + + \ \ \ \ \ \ \ \ list-merge! list-sort! list-stable-sort! vector-merge! vector-sort! vector-stable-sort!) + + (import (liii list) + + \ \ \ \ \ \ \ \ (liii error) + + \ \ \ \ \ \ \ \ (scheme case-lambda)) + + (begin + + \; + + + <\section> + 实现 + + + + + 判断 list 或 vector 是否有序。 尚未实现可选参数 start 和 end。 + + <\scm-chunk|goldfish/srfi/srfi-132.scm|true|true> + \ \ (define (list-sorted? less-p lis) + + \ \ \ \ (if (null? lis) + + \ \ \ \ \ \ #t + + \ \ \ \ \ \ (do ((first lis (cdr first)) + + \ \ \ \ \ \ \ \ \ \ \ (second (cdr lis) (cdr second)) + + \ \ \ \ \ \ \ \ \ \ \ (res #t (not (less-p (car second) (car first))))) + + \ \ \ \ \ \ \ \ ((or (null? second) (not res)) res)))) + + \; + + \ \ ; TODO optional parameters + + \ \ (define (vector-sorted? less-p v) + + \ \ \ \ (let ((start 0) + + \ \ \ \ \ \ \ \ \ \ (end (length v))) + + \ \ \ \ \ \ (do ((first start (+ 1 first)) + + \ \ \ \ \ \ \ \ \ \ \ (second (+ 1 start) (+ 1 second)) + + \ \ \ \ \ \ \ \ \ \ \ (res #t (not (less-p (vector-ref v second) (vector-ref v first))))) + + \ \ \ \ \ \ \ \ ((or (\= second end) (not res)) res)))) + + \; + + + + + 归并排序。需要注意 不必修改原 list,但 要保证修改原 vector。 + + <\scm-chunk|goldfish/srfi/srfi-132.scm|true|true> + \ \ (define (list-merge less-p lis1 lis2) + + \ \ \ \ (let loop + + \ \ \ \ \ \ ((res '()) + + \ \ \ \ \ \ \ (lis1 lis1) + + \ \ \ \ \ \ \ (lis2 lis2)) + + \ \ \ \ \ \ (cond + + \ \ \ \ \ \ \ \ ((and (null? lis1) (null? lis2)) (reverse res)) + + \ \ \ \ \ \ \ \ ((null? lis1) (loop (cons (car lis2) res) lis1 (cdr lis2))) + + \ \ \ \ \ \ \ \ ((null? lis2) (loop (cons (car lis1) res) lis2 (cdr lis1))) + + \ \ \ \ \ \ \ \ ((less-p (car lis2) (car lis1)) (loop (cons (car lis2) res) lis1 (cdr lis2))) + + \ \ \ \ \ \ \ \ (else (loop (cons (car lis1) res) (cdr lis1) lis2))))) + + \; + + \ \ ; this list-merge! violates SRFI 132, since it does not satisfy the constant running space constraint specified in SRFI 132, and does not work "in place" + + \ \ (define list-merge! list-merge) + + \; + + \ \ (define (list-stable-sort less-p lis) + + \ \ \ \ (define (sort l r) + + \ \ \ \ \ \ (cond + + \ \ \ \ \ \ \ \ ((= l r) '()) + + \ \ \ \ \ \ \ \ ((= (+ l 1) r) (list (list-ref lis l))) + + \ \ \ \ \ \ \ \ (else + + \ \ \ \ \ \ \ \ \ \ (let* ((mid (quotient (+ l r) 2)) + + \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ (l-sorted (sort l mid)) + + \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ (r-sorted (sort mid r))) + + \ \ \ \ \ \ \ \ \ \ \ \ (list-merge less-p l-sorted r-sorted))))) + + \ \ \ \ (sort 0 (length lis))) + + \; + + \ \ (define list-sort list-stable-sort) + + \ \ (define list-sort! list-stable-sort) + + \ \ (define list-stable-sort! list-stable-sort) + + \; + + + + + 无副作用时调用 list 相关函数实现。原地排序尚未实现。 + + <\scm-chunk|goldfish/srfi/srfi-132.scm|true|true> + \ \ (define vector-stable-sort + + \ \ \ \ (case-lambda + + \ \ \ \ \ \ ((less-p v) + + \ \ \ \ \ \ \ (list-\vector (list-stable-sort less-p (vector-\list v)))) + + \ \ \ \ \ \ ((less-p v start) + + \ \ \ \ \ \ \ (list-\vector (list-stable-sort less-p (subvector-\list v start (vector-length v))))) + + \ \ \ \ \ \ ((less-p v start end) + + \ \ \ \ \ \ \ (list-\vector (list-stable-sort less-p (subvector-\list v start end)))))) + + \; + + \ \ (define vector-sort vector-stable-sort) + + \; + + \ \ (define (vector-sort! . r) (???)) + + \ \ (define (vector-stable-sort! . r) (???)) + + \; + + \ \ (define (subvector-\list v start end) + + \ \ \ \ (do ((r '() (cons (vector-ref v p) r)) + + \ \ \ \ \ \ \ \ \ (p start (+ 1 p))) + + \ \ \ \ \ \ ((\= p end) (reverse r)))) + + \; + + \ \ (define vector-merge + + \ \ \ \ (case-lambda + + \ \ \ \ \ \ ((less-p v1 v2) + + \ \ \ \ \ \ \ (list-\vector (list-merge less-p (vector-\list v1) (vector-\list v2)))) + + \ \ \ \ \ \ ((less-p v1 v2 start1) + + \ \ \ \ \ \ \ (list-\vector (list-merge less-p (subvector-\list v1 start1 (vector-length v1)) (vector-\list v2)))) + + \ \ \ \ \ \ ((less-p v1 v2 start1 end1) + + \ \ \ \ \ \ \ (list-\vector (list-merge less-p (subvector-\list v1 start1 end1) (vector-\list v2)))) + + \ \ \ \ \ \ ((less-p v1 v2 start1 end1 start2) + + \ \ \ \ \ \ \ (list-\vector (list-merge less-p (subvector-\list v1 start1 end1) (subvector-\list v2 start2 (vector-length v2))))) + + \ \ \ \ \ \ ((less-p v1 v2 start1 end1 start2 end2) + + \ \ \ \ \ \ \ (list-\vector (list-merge less-p (subvector-\list v1 start1 end1) (subvector-\list v2 start2 end2)))))) + + \; + + \ \ (define (vector-merge! . r) (???)) + + \; + + + + + <\scm-chunk|tests/goldfish/liii/sort-test.scm|true|false> + (import (liii check) + + \ \ \ \ \ \ \ \ (liii sort)) + + \; + + (check-set-mode! 'report-failed) + + \; + + (define (pair-\ x y) + + \ \ (\ (car x) (car y))) + + \; + + (define (pair-full-\ x y) + + \ \ (cond + + \ \ \ \ ((not (= (car x) (car y))) (\ (car x) (car y))) + + \ \ \ \ (else (\ (cdr y) (cdr x))))) + + \; + + (check-false (list-sorted? \ '(1 5 1 0 -1 9 2 4 3))) + + (check-false (vector-sorted? \ #(1 5 1 0 -1 9 2 4 3))) + + \; + + (check-true (list-sorted? \ (list-sort \ '(1 5 1 0 -1 9 2 4 3)))) + + (check-true (list-sorted? \ (list-stable-sort \ '(1 5 1 0 -1 9 2 4 3)))) + + (check-true (list-sorted? pair-\ (list-merge pair-\ '((1 . 1) (1 . 2) (3 . 1)) '((1 . 3) (2 . 1) (3 . 2) (4 . 1))))) + + (check (list-merge pair-\ '((1 . 1) (1 . 2) (3 . 1)) '((1 . 3) (2 . 1) (3 . 2) (4 . 1))) + + \ \ \ \ \ \ \ =\ '((1 . 1) (1 . 2) (1 . 3) (2 . 1) (3 . 1) (3 . 2) (4 . 1))) + + (check-true (list-sorted? pair-full-\ (list-merge pair-full-\ '((1 . 2) (1 . 1) (3 . 1)) '((1 . 3) (2 . 1) (3 . 2) (4 . 1))))) + + (check (list-merge pair-full-\ '((1 . 2) (1 . 1) (3 . 1)) '((1 . 3) (2 . 1) (3 . 2) (4 . 1))) + + \ \ \ \ \ \ \ =\ '((1 . 3) (1 . 2) (1 . 1) (2 . 1) (3 . 2) (3 . 1) (4 . 1))) + + \; + + (check-true (vector-sorted? \ (vector-sort \ #(1 5 1 0 -1 9 2 4 3)))) + + (check-true (vector-sorted? \ (vector-stable-sort \ #(1 5 1 0 -1 9 2 4 3)))) + + (check-true (vector-sorted? pair-\ (vector-merge pair-\ #((1 . 1) (1 . 2) (3 . 1)) #((1 . 3) (2 . 1) (3 . 2) (4 . 1))))) + + (check (vector-merge pair-\ #((1 . 1) (1 . 2) (3 . 1)) #((1 . 3) (2 . 1) (3 . 2) (4 . 1))) + + \ \ \ \ \ \ \ =\ #((1 . 1) (1 . 2) (1 . 3) (2 . 1) (3 . 1) (3 . 2) (4 . 1))) + + (check-true (vector-sorted? pair-full-\ (vector-merge pair-full-\ #((1 . 2) (1 . 1) (3 . 1)) #((1 . 3) (2 . 1) (3 . 2) (4 . 1))))) + + (check (vector-merge pair-full-\ #((1 . 2) (1 . 1) (3 . 1)) #((1 . 3) (2 . 1) (3 . 2) (4 . 1))) + + \ \ \ \ \ \ \ =\ #((1 . 3) (1 . 2) (1 . 1) (2 . 1) (3 . 2) (3 . 1) (4 . 1))) + + \; + + (check-report) + + \; + + + + + <\scm-chunk|goldfish/srfi/srfi-132.scm|true|false> + ) ; end of begin + + ) ; end of library + + \; + + + +<\initial> + <\collection> + + + + + +<\references> + <\collection> + > + > + > + > + > + > + > + > + > + > + > + > + > + > + > + > + > + > + > + + + +<\auxiliary> + <\collection> + <\associate|toc> + |math-font-series||font-size||1(liii sort)> |.>>>>|> + + |math-font-series||1许可证> |.>>>>|> + + |math-font-series||2接口> |.>>>>|> + + |math-font-series||3实现> |.>>>>|> + + |3.1list-sorted?, vector-sorted? |.>>>>|> > + + |3.2list-merge, list-sort, list-stable-sort |.>>>>|> > + + |3.3vector-merge, vector-sort, vector-stable-sort |.>>>>|> > + + |math-font-series||4测试> |.>>>>|> + + |math-font-series||5结尾> |.>>>>|> + + + diff --git a/tests/goldfish/liii/sort-test.scm b/tests/goldfish/liii/sort-test.scm new file mode 100644 index 0000000..e46f4c7 --- /dev/null +++ b/tests/goldfish/liii/sort-test.scm @@ -0,0 +1,52 @@ +; +; Copyright (C) 2024 The Goldfish Scheme Authors +; +; Licensed under the Apache License, Version 2.0 (the "License"); +; you may not use this file except in compliance with the License. +; You may obtain a copy of the License at +; +; http://www.apache.org/licenses/LICENSE-2.0 +; +; Unless required by applicable law or agreed to in writing, software +; distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +; WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +; License for the specific language governing permissions and limitations +; under the License. +; + +(import (liii check) + (liii sort)) + +(check-set-mode! 'report-failed) + +(define (pair-< x y) + (< (car x) (car y))) + +(define (pair-full-< x y) + (cond + ((not (= (car x) (car y))) (< (car x) (car y))) + (else (< (cdr y) (cdr x))))) + +(check-false (list-sorted? < '(1 5 1 0 -1 9 2 4 3))) +(check-false (vector-sorted? < #(1 5 1 0 -1 9 2 4 3))) + +(check-true (list-sorted? < (list-sort < '(1 5 1 0 -1 9 2 4 3)))) +(check-true (list-sorted? < (list-stable-sort < '(1 5 1 0 -1 9 2 4 3)))) +(check-true (list-sorted? pair-< (list-merge pair-< '((1 . 1) (1 . 2) (3 . 1)) '((1 . 3) (2 . 1) (3 . 2) (4 . 1))))) +(check (list-merge pair-< '((1 . 1) (1 . 2) (3 . 1)) '((1 . 3) (2 . 1) (3 . 2) (4 . 1))) + => '((1 . 1) (1 . 2) (1 . 3) (2 . 1) (3 . 1) (3 . 2) (4 . 1))) +(check-true (list-sorted? pair-full-< (list-merge pair-full-< '((1 . 2) (1 . 1) (3 . 1)) '((1 . 3) (2 . 1) (3 . 2) (4 . 1))))) +(check (list-merge pair-full-< '((1 . 2) (1 . 1) (3 . 1)) '((1 . 3) (2 . 1) (3 . 2) (4 . 1))) + => '((1 . 3) (1 . 2) (1 . 1) (2 . 1) (3 . 2) (3 . 1) (4 . 1))) + +(check-true (vector-sorted? < (vector-sort < #(1 5 1 0 -1 9 2 4 3)))) +(check-true (vector-sorted? < (vector-stable-sort < #(1 5 1 0 -1 9 2 4 3)))) +(check-true (vector-sorted? pair-< (vector-merge pair-< #((1 . 1) (1 . 2) (3 . 1)) #((1 . 3) (2 . 1) (3 . 2) (4 . 1))))) +(check (vector-merge pair-< #((1 . 1) (1 . 2) (3 . 1)) #((1 . 3) (2 . 1) (3 . 2) (4 . 1))) + => #((1 . 1) (1 . 2) (1 . 3) (2 . 1) (3 . 1) (3 . 2) (4 . 1))) +(check-true (vector-sorted? pair-full-< (vector-merge pair-full-< #((1 . 2) (1 . 1) (3 . 1)) #((1 . 3) (2 . 1) (3 . 2) (4 . 1))))) +(check (vector-merge pair-full-< #((1 . 2) (1 . 1) (3 . 1)) #((1 . 3) (2 . 1) (3 . 2) (4 . 1))) + => #((1 . 3) (1 . 2) (1 . 1) (2 . 1) (3 . 2) (3 . 1) (4 . 1))) + +(check-report) +