Scheme - 将列表拆分为两个相等的列表

时间:2014-10-21 02:58:55

标签: list split scheme equals

问题:

编写一个函数(split l),它接受一个列表并将其分成两个相等大小(在一个内)的列表,并返回一个汽车是第一个列表且其cdr是第二个列表的对。

我的代码:

(define split list)
  (let ((half (/ (length list) 2)
    (cons (car half list)
          (cdr half list))))

2 个答案:

答案 0 :(得分:6)

这是使用tortoise and hare算法的另一种可能的实现方式:

(define (split lst)
  (let loop ((tortoise lst) (hare lst) (acc '()))
    (if (or (null? hare) (null? (cdr hare)))
        (cons (reverse acc) tortoise)
        (loop (cdr  tortoise) 
              (cddr hare) 
              (cons (car tortoise) acc)))))

上述解决方案的优点是只遍历列表一次,注意我们不需要知道列表的长度来进行拆分。它被称为“龟”和“野兔”。因为我们在列表上保留了两个指针:一个缓慢前进,一次一个元素("乌龟")另一个更快,一次两个元素("野兔" )。当野兔到达输入列表的末尾时,算法停止。

或者,我们可以使用内置过程实现更惯用(尽管更慢)的解决方案。假设您的口译员可以使用takedrop程序(如果没有,请从SRFI-1导入),这更接近您的想法:

(define (split lst)
  (let ((half (quotient (length lst) 2)))
    (cons (take lst half)
          (drop lst half))))

无论哪种方式,它都按预期工作:

(split '(1 2 3 4))   
=> ((1 2) 3 4)

(split '(1 2 3 4 5)) 
=> ((1 2) 3 4 5)

答案 1 :(得分:0)

尝试:

(define (splitAt n lst)
    (let loop ((acc '()) (n n) (lst lst))
        (if (or (= n 0) (null? lst)) (cons (reverse acc) lst)
            (loop (cons (car lst) acc) (- n 1) (cdr lst)))))

(define (split lst) (splitAt (quotient (length lst) 2) lst))

它的工作原理如下:

(split '(1 2 3 4))   => ((1 2) 3 4)
(split '(1 2 3 4 5)) => ((1 2) 3 4 5)

希望这有帮助。