【问题标题】:Define a scheme function that computes the trace of a square matrix定义一个计算方阵轨迹的方案函数
【发布时间】:2017-04-24 18:48:28
【问题描述】:

例子

(trace '((1 2 3) (4 5 6) (7 8 9))) 应计算为 15 (1+5+9)。 提示:使用map 获得可以递归应用跟踪的较小矩阵。矩阵应该是平方的。

我试着做,但我似乎做不到,我试着先得到对角线。

define (diagonals m n)

(append

(for/list ([slice (in-range 1 (- (* 2 n) 2))])
 (let ((z (if (< slice n) 0 (add1 (- slice n)))))
   (for/list ([j (in-range z (add1 (- slice z)))])
     (vector-ref (vector-ref m (sub1 (- n j))) (- slice j))))

有没有办法使用map 以非常简单的递归方式解决这个问题。

我试图这样解决它。

define (nth n l)
(if (or (> n (length l)) (< n 0))
(if (eq? n 0) (car l)
(nth (- n 1) (cdr l)))))

(+ (nth 3 '(3 4 5)) (nth 2 '(3 4 5)) (nth 3 '(3 4 5)))

但它也没有用。

【问题讨论】:

  • 请将您的代码从评论移至问题并正确格式化。使用“编辑”按钮。
  • 好的,我会这样做
  • 谢谢。现在请修复括号和缩进并删除不必要的 cmets(我将删除我的)
  • 你看,我不是lisp专业的,所以不擅长缩进
  • Emacs 可以按照我们期望的方式为您缩进代码 :-)

标签: scheme lisp


【解决方案1】:

虽然我不认为回答家庭作业问题一般来说是一个好主意,但我无法抗拒这一点,因为它既说明了 Lisp 程序的美妙之处,也说明了它的可怕之处。

有什么好看的:

  • 递归算法几乎与归纳的数学证明相同,而且非常漂亮和聪明;

有什么可怕的:

  • 矩阵不是语义嵌套列表,假装它们只是这种可怕的双关语(我不确定我使用 firstrest 是使其变得更好或更糟);
  • 它只是无缘无故地发疯了;
  • 我很确定它的时间复杂度是 n^2,而它可能是 n。

当然,Lisp 程序不必如此糟糕。

计算矩阵的迹:

  • 如果矩阵为空,则迹为0;
  • 否则,将左上角的元素添加到通过删除第一行和第一列获得的矩阵的轨迹中。

或者:

(define (awful-trace m)
  (if (null? m)
      ;; the trace of the null matrix is 0
      0
      ;; otherwise the trace is the top left element added to ...
      (+ (first (first m))
         ;; the trace of the matrix without its first row and column which
         ;; we get by mapping rest over the rest of the matrix
         (awful-trace (map rest (rest m))))))

你可能会认为下面的函数更好,但它在上述所有方面都一样糟糕,而且对于不精通辅助尾递归函数的人来说更难阅读 -累加器技巧:

(define (awful-trace/not-actually-better m)
  (define (awful-loop mm tr)
    (if (null? mm)
        tr
        (awful-loop (map rest (rest mm))
                    (+ tr (first (first mm))))))
  (awful-loop m 0))

【讨论】:

  • Lisp 中的列表是线性访问的,所以到达对角线只能是二次的。也就是说,map 重新构建了顶级 cons 结构,因此您获得了二次空间行为;您可以为 nth 行应用cdr n 次,以获得恒定空间(当然时间仍然是二次的)。对第 n 行调用 cdr n 次是无济于事的,这不是因为 Lisp “糟糕”,而是因为使用了数据结构。 --- 你的累积代码仍然调用map;它所实现的只是避免 O(n) 深堆栈 - 与二次空间和时间相比并不重要。
  • 我在抽什么?!当然使用 nth 而不是 n cdrs。我认为它仍然是线性的,因此总体上是二次的。 --- OTOH OP 使用vector-ref,所以也许他们的矩阵是向量列表?这会改变一些事情。
  • @WillNess:是的,它是二次的,正如你所说,没有什么比计算这种结构的轨迹更好的了(即使是 OP 将其制成向量的技术,因为这样做本身就是二次的)。累加器版本在空间上显然是线性的,假设 GC 或等效:在它们变成垃圾之前,它一次不需要超过 n 个新的 conses。我显然不认为 Lisp 很糟糕:我认为一些程序(在 Lisp 和其他语言中)很糟糕,包括这个。
  • 在“糟糕”的引语之后有一个隐含的笑脸。应该是明确的! ——至于累积版本的空间线性:你是对的。正在考虑新的 conses 数量,所以这更像是一个时间复杂度的事情。当然,一个足够智能的编译器可以只维护一堆指向原始结构的指针,而根本没有consing。从这方面来看,(第一个)代码变成了高级描述,并且漂亮的,恕我直言。 :)
【解决方案2】:

试试:

(apply + (map (lambda (index row) (list-ref row index))
             '(0 1 2)
             '((1 2 3) (4 5 6) (7 8 9))))

当然,把它变成一个函数。

要处理大于 3x3 的矩阵,我们需要更多索引。

由于map 在遍历最短的列表时会停止,所以(0 1 2) 列表可以手动填充到...您认为您可以表示的最大矩阵的最佳猜测在你毕业之前在 Scheme 中嵌套列表,再也不会看到这些东西了。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-03-18
    • 1970-01-01
    • 1970-01-01
    • 2017-08-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多