Lisp中的嵌套列表问题

时间:2016-10-30 02:10:21

标签: scheme lisp

所以我必须编写一个方法,它接受一个像(嵌套'(4 5 2 8))的列表并返回(4(5()2)8)。

我认为我需要编写3种支持方法来实现这一目标。第一个得到列表的大小:

(define (sizeList L)
   (if (null? L) 0
      (+ 1 (sizeList (cdr L)))))

 input : (sizeList '(1 2 3 4 5 6 7))
 output: 7

列表中的第二个元素:

 (define (drop n L)
   (if (= (- n 1) 0) L
      (drop (- n 1) (cdr L))))

 input : (drop 5 '(1 2 3 4 5 6 7))
 output: (5 6 7)

第三个删除列表的最后一个元素:

 (define (remLast E)
     (if (null? (cdr E)) '()
        (cons (car E) (remLast (cdr E)))))

 input : (remLast '(1 2 3 4 5 6 7))
 output: (1 2 3 4 5 6)

对于嵌套方法,我认为我需要做第一个元素的汽车,然后用drop递归,然后删除最后一个元素,但对于我的生活,我无法弄清楚如何做或者也许我只是不断弄乱括号?有什么想法吗?

1 个答案:

答案 0 :(得分:0)

各种递归解决方案都是可能的,但问题在于更直观的解决方案具有非常糟糕的性能,因为它们的成本取决于输入列表大小的平方。

考虑这个简单的解决方案:

; return a copy of list l without the last element
(define (butlast l)
  (cond ((null? l) '())
        ((null? (cdr l)) '())
        (else (cons (car l) (butlast (cdr l))))))

; return the last element of list l
(define (last l)
  (cond ((null? l) '())
        ((null? (cdr l)) (car l))
        (else (last (cdr l)))))

; nest a linear list
(define (nested l)
  (cond ((null? l) '())
        ((null? (cdr l)) l)
        (else (list (car l) (nested (butlast (cdr l))) (last l)))))

nested的每次递归调用中,都会调用butlast并调用last:这意味着对于列表前半部分中的每个元素,我们必须扫描列表的两倍,这需要许多次序O的操作(n 2 )。

是否有可能找到一个递归解决方案,其中包含许多与列表大小呈线性增长的操作?答案是肯定的,这个解决方案的关键是反转列表,并在列表及其反向上并行工作,通过一个辅助函数从两个列表中获取一个元素并在cdr上重现并且在考虑两个列表的前半部分时同时使用计数器来停止处理。以下是此算法的可能实现:

(define (nested l)
  (define (aux l lr n)
    (cond ((= n 0) '())
          ((= n 1) (list (car l)))
          (else (list (car l) (aux (cdr l) (cdr lr) (- n 2)) (car lr)))))
  (aux l (reverse l) (length l)))

请注意,参数n(length l)开始,并在每次递归时减少2:这允许管理具有偶数或奇数元素的列表的情况。 reverse是反转列表的原始函数,但是如果你不能使用这个原始函数,你可以用以下方式用递归算法实现它:

(define (reverse l)
  (define (aux first-list second-list)
    (if (null? first-list)
        second-list
        (aux (cdr first-list) (cons (car first-list) second-list))))
  (aux l '()))