循环在方案中对列表进行 n 次排队
Loop to queue a list n times in scheme
我正在尝试编写一个带有两个参数的函数,一个列表和循环次数 n。我一直在尝试实现一个 let 循环来调用辅助函数,将结果保存到一个变量,然后每次循环将 n 递减 1,然后在 n 达到 0 时停止,但我不确定该怎么做。 .
这是我的代码:
; helper function to queue it once
(define (queue lst)
(if (empty? lst)
'()
(append (cdr lst) (list (car lst)))))
;main function that calls helper function
(define (queueLoop n lst)
(if (empty? lst)
'()
(let loop ((res (queue lst))
(lst (queue lst)))
(cond
[(> n 0)
((- n 1) (loop (queue res) (rest lst)))]
(else
(loop (queue res) (rest lst)))))))
请记住,在 Scheme 中,大多数操作不会 改变 变量,而是 return 修改后的新值。以此为例:
(- n 1)
上面那行不是修改n
的值,它是return一个等于n
减去的新值1,除非你将它存储在某处或将它作为参数传递给函数调用,否则该值将丢失(事实上,这就是正在发生的事情)。
更新: 现在您已经发布了示例 input/output,很清楚您打算做什么。这是使用内置过程编写解决方案的另一种简单方法,它可以处理极端情况:
(define (queueLoop n lst)
(let ((x (min n (length lst))))
(append (drop lst x)
(take lst x))))
例如:
(queueLoop 1 '())
=> '()
(queueLoop 0 '(1 2 3 4))
=> '(1 2 3 4)
(queueLoop 3 '(1 2 3 4))
=> '(4 1 2 3)
(queueLoop 5 '(1 2 3 4))
=> '(1 2 3 4)
这是我会做的:
(define (rotate-left-inc lst n)
(let-values ([(tail head) (split-at lst n)])
(append head tail)))
至于你自己的卷,使用 cons
是 O(1) 和 append
是 O(n) 的事实我会这样做:
;; rotate once in O(n) time
(define (rotate-left-once lst)
(append (cdr lst) (list (car lst))))
;; rotate n times in O(n) time
(define (rotate-left-on lst n)
(let loop ([head lst] [rtail '()] [n n])
(if (<= n 0)
(append head (reverse rtail))
(loop (cdr head) (cons (car head) rtail) (sub1 n)))))
虽然没有办法重复旋转一次并获得有效的过程:
;; rotate n times in O(n^2) time
(define (rotate-left lst n)
(let loop ([n n] [lst lst])
(if (<= n 0)
lst
(loop (sub1 n) (rotate-left-once lst)))))
使用原始版本时旋转的数字越长,这会变得非常慢,而使用 append
一次的版本要快得多:
(define lst1 (make-list 200 198))
(define lst2 (make-list 20000 19998))
(define lst3 (make-list 2000000 1999998))
(for-each (lambda (lst)
(display (car lst))
(newline)
(display "O(n) inc")
(time (rotate-left-inc lst (car lst)))
(display "O(n) roll")
(time (rotate-left-on lst (car lst)))
(display "O(n^2)")
(time (rotate-left lst (car lst))))
(list lst1 lst2 lst3))
我电脑上的输出清楚地显示指数时间需要很多时间:
198
O(n) inccpu time: 1 real time: 0 gc time: 0
O(n) rollcpu time: 0 real time: 0 gc time: 0
O(n^2)cpu time: 0 real time: 1 gc time: 0
19998
O(n) inccpu time: 1 real time: 0 gc time: 0
O(n) rollcpu time: 0 real time: 1 gc time: 0
O(n^2)cpu time: 4846 real time: 4884 gc time: 1295
1999998
O(n) inccpu time: 207 real time: 209 gc time: 160
O(n) rollcpu time: 279 real time: 282 gc time: 234
O(n^2) (didn't wait for it. Gave up after 5 minutes)
我正在尝试编写一个带有两个参数的函数,一个列表和循环次数 n。我一直在尝试实现一个 let 循环来调用辅助函数,将结果保存到一个变量,然后每次循环将 n 递减 1,然后在 n 达到 0 时停止,但我不确定该怎么做。 .
这是我的代码:
; helper function to queue it once
(define (queue lst)
(if (empty? lst)
'()
(append (cdr lst) (list (car lst)))))
;main function that calls helper function
(define (queueLoop n lst)
(if (empty? lst)
'()
(let loop ((res (queue lst))
(lst (queue lst)))
(cond
[(> n 0)
((- n 1) (loop (queue res) (rest lst)))]
(else
(loop (queue res) (rest lst)))))))
请记住,在 Scheme 中,大多数操作不会 改变 变量,而是 return 修改后的新值。以此为例:
(- n 1)
上面那行不是修改n
的值,它是return一个等于n
减去的新值1,除非你将它存储在某处或将它作为参数传递给函数调用,否则该值将丢失(事实上,这就是正在发生的事情)。
更新: 现在您已经发布了示例 input/output,很清楚您打算做什么。这是使用内置过程编写解决方案的另一种简单方法,它可以处理极端情况:
(define (queueLoop n lst)
(let ((x (min n (length lst))))
(append (drop lst x)
(take lst x))))
例如:
(queueLoop 1 '())
=> '()
(queueLoop 0 '(1 2 3 4))
=> '(1 2 3 4)
(queueLoop 3 '(1 2 3 4))
=> '(4 1 2 3)
(queueLoop 5 '(1 2 3 4))
=> '(1 2 3 4)
这是我会做的:
(define (rotate-left-inc lst n)
(let-values ([(tail head) (split-at lst n)])
(append head tail)))
至于你自己的卷,使用 cons
是 O(1) 和 append
是 O(n) 的事实我会这样做:
;; rotate once in O(n) time
(define (rotate-left-once lst)
(append (cdr lst) (list (car lst))))
;; rotate n times in O(n) time
(define (rotate-left-on lst n)
(let loop ([head lst] [rtail '()] [n n])
(if (<= n 0)
(append head (reverse rtail))
(loop (cdr head) (cons (car head) rtail) (sub1 n)))))
虽然没有办法重复旋转一次并获得有效的过程:
;; rotate n times in O(n^2) time
(define (rotate-left lst n)
(let loop ([n n] [lst lst])
(if (<= n 0)
lst
(loop (sub1 n) (rotate-left-once lst)))))
使用原始版本时旋转的数字越长,这会变得非常慢,而使用 append
一次的版本要快得多:
(define lst1 (make-list 200 198))
(define lst2 (make-list 20000 19998))
(define lst3 (make-list 2000000 1999998))
(for-each (lambda (lst)
(display (car lst))
(newline)
(display "O(n) inc")
(time (rotate-left-inc lst (car lst)))
(display "O(n) roll")
(time (rotate-left-on lst (car lst)))
(display "O(n^2)")
(time (rotate-left lst (car lst))))
(list lst1 lst2 lst3))
我电脑上的输出清楚地显示指数时间需要很多时间:
198
O(n) inccpu time: 1 real time: 0 gc time: 0
O(n) rollcpu time: 0 real time: 0 gc time: 0
O(n^2)cpu time: 0 real time: 1 gc time: 0
19998
O(n) inccpu time: 1 real time: 0 gc time: 0
O(n) rollcpu time: 0 real time: 1 gc time: 0
O(n^2)cpu time: 4846 real time: 4884 gc time: 1295
1999998
O(n) inccpu time: 207 real time: 209 gc time: 160
O(n) rollcpu time: 279 real time: 282 gc time: 234
O(n^2) (didn't wait for it. Gave up after 5 minutes)