непроверенная. Обратите внимание, что процедура append-list
, которую я определил, на самом деле возвращает список, заканчивающийся sos2
. Это уместно (и правильно делать) здесь, но не в целом.
(define cart-product
(lambda (sos1 sos2)
(if (null? sos1) '()
(append-list
(cart-prod-sexpr (car sos1) sos2)
(cart-product (cdr sos1) sos2)))))
(define cart-prod-sexpr
(lambda (s sos)
(if (null? sos) '()
(cons
(list s (car sos))
(cart-prod-sexpr s (cdr sos))))))
(define append-list
(lambda (sos1 sos2)
(if (null? sos1) sos2
(cons
(car sos1)
(append-list (cdr sos1) sos2)))))
Обратите внимание, что если списки имеют размер n, то потребуется время O (n 3 ) для создания списка размера O (n 2 ). Использование обычного append
взяло бы O (n 4 ). Я просто реализовал обычный append
, не осознавая этого. Если вы хотите взять O (n 2 ) ты должен быть умнее. Как в этом непроверенном коде.
(define cart-product
(lambda (sos1 sos2)
(let cart-product-finish
(lambda (list1-current list2-current answer-current)
(if (null? list2-current)
(if (null? list1-current)
answer-current
(cart-product-finish (car list1-current) sos2 answer-current))
(cart-product-finish list1-current (car sos2)
(cons (cons (cdr list1-current) (cdr list2-current)) answer-current))))
(cart-product-finish list1 '() '())))
В случае, если у меня есть ошибка, идея состоит в том, чтобы рекурсивно перебрать все комбинации элементов в первой и второй, при этом каждая из них заменяет answer-current
на cons
еще одной комбинацией, а затем все остальное уже нашли. Благодаря оптимизации хвостового вызова это должно быть эффективным.