Scheme 更好更快的方案功能?

Scheme 更好更快的方案功能?,scheme,complexity-theory,racket,time-complexity,asymptotic-complexity,Scheme,Complexity Theory,Racket,Time Complexity,Asymptotic Complexity,因此,如果列表中有n个元素,则查找列表中的最大元素会增加时间复杂性。我试图实现一个看起来更快的算法 (define (clever-max lst) (define (odd-half a-list) (cond ((null? a-list) (list)) ((null? (cdr a-list)) (cons (car a-list) (list))) (else (cons (car a-li

因此,如果列表中有n个元素,则查找列表中的最大元素会增加时间复杂性。我试图实现一个看起来更快的算法

(define (clever-max lst)
  (define (odd-half a-list)
    (cond ((null? a-list) (list))
          ((null? (cdr a-list))
           (cons (car a-list) (list)))
          (else
           (cons (car a-list)
                 (odd-half (cdr (cdr a-list)))))))
  (define (even-half a-list)
    (if (null? a-list)
        (list)
        (odd-half (cdr a-list))))
  (cond ((null? lst) (error "no elements in list!"))
        ((null? (cdr lst)) (car lst))
        (else
         (let ((l1 (even-half lst))
               (l2 (odd-half lst)))
           (max (clever-max l1) (clever-max l2))))))

这真的更快吗?!您认为渐近时间复杂度是严格限制的吗?

给定一个您一无所知的数据列表,如果不检查每个元素并因此占用时间,就无法找到最大元素,因为如果不检查它,您可能会错过它。所以,不,您的算法并不比日志n上的算法快,因为您基本上只是在运行merge-sort

这里有更多的数据

我想了想,意识到我可能应该做点什么,而不仅仅是把这说成是事实。所以我编写了一个快速速度测试。现在完全公开,我不是一个Scheme程序员,所以这是在Common Lisp中,但我认为我忠实地转换了您的算法

;; Direct "iteration" method -- theoretical O(n)
(defun find-max-001 ( list )
  (labels ((fm ( list cur )
             (if (null list) cur
               (let ((head (car list))
                     (rest (cdr list)))
                 (fm rest (if (> head cur) head cur))))))
    (fm (cdr list) (car list))))

;; Your proposed method  
(defun find-max-002 ( list )
  (labels ((odd-half ( list )
             (cond ((null list) list)
                   ((null (cdr list)) (list (car list)))
                   (T (cons (car list) (odd-half (cddr list))))))
           (even-half ( list )
             (if (null list) list (odd-half (cdr list)))))
    (cond ((null list) list)
          ((null (cdr list)) (car list))
          (T (let ((l1 (even-half list))
                   (l2 (odd-half list)))
               (max (find-max-002 l1) (find-max-002 l2)))))))

;; Simplistic speed test              
(let ((list (loop for x from 0 to 10000 collect (random 10000))))
  (progn
    (print "Running find-max-001")
    (time (find-max-001 list))
    (print "Running find-max-002")
    (time (find-max-002 list))))
现在你可能会问自己,为什么我只使用10000作为列表大小,因为对于渐近计算来说,这是相当小的。事实上,sbcl认识到第一个函数是尾部递归的,因此将其抽象为一个循环,而第二个函数则没有,因此,在不破坏堆栈的情况下,这是我能得到的最大值。虽然从下面的结果可以看出,这足以说明这一点

"Running find-max-001"
Evaluation took:
  0.000 seconds of real time
  0.000000 seconds of total run time (0.000000 user, 0.000000 system)
  100.00% CPU
  128,862 processor cycles
  0 bytes consed

"Running find-max-002"
Evaluation took:
  0.012 seconds of real time
  0.012001 seconds of total run time (0.012001 user, 0.000000 system)
  [ Run times consist of 0.008 seconds GC time, and 0.005 seconds non-GC time. ]
  100.00% CPU
  27,260,311 processor cycles
  2,138,112 bytes consed
即使在这个水平上,我们也在谈论大规模的经济放缓。在直接检查每个项目一次的方法降低到算法的10k评估之前,需要增加到大约一百万个项目

 (let ((x (loop for x from 0 to 1000000 collect (random 1000000))))
   (time (find-max-001 x)))

Evaluation took:
  0.007 seconds of real time
  0.008000 seconds of total run time (0.008000 user, 0.000000 system)
  114.29% CPU
  16,817,949 processor cycles
  0 bytes consed
最后的想法和结论

所以接下来要问的问题是,为什么第二种算法真的要花那么长的时间。在不深入细节的情况下,有几件事真的很突出


第一个是犯人。现在是的,cons是O1,但这仍然是系统要完成的另一个操作。它要求系统分配和释放内存,并启动垃圾收集器。第二件真正让人吃惊的事情是,你基本上是在运行一个合并排序,除了抓取列表的下半部分和上半部分之外,你还要抓取奇偶节点,这也需要更长的时间,因为你每次都要迭代来构建列表。这里的算法充其量是一个On log n算法请注意,它是一种合并排序算法,非常适合排序,但它会带来很多额外的开销。

给定一个您一无所知的数据列表,如果不检查每个元素,就无法找到最大元素,因此需要花费时间,因为如果您不检查它,你可能会错过它。所以,不,您的算法并不比日志n上的算法快,因为您基本上只是在运行merge-sort

这里有更多的数据

我想了想,意识到我可能应该做点什么,而不仅仅是把这说成是事实。所以我编写了一个快速速度测试。现在完全公开,我不是一个Scheme程序员,所以这是在Common Lisp中,但我认为我忠实地转换了您的算法

;; Direct "iteration" method -- theoretical O(n)
(defun find-max-001 ( list )
  (labels ((fm ( list cur )
             (if (null list) cur
               (let ((head (car list))
                     (rest (cdr list)))
                 (fm rest (if (> head cur) head cur))))))
    (fm (cdr list) (car list))))

;; Your proposed method  
(defun find-max-002 ( list )
  (labels ((odd-half ( list )
             (cond ((null list) list)
                   ((null (cdr list)) (list (car list)))
                   (T (cons (car list) (odd-half (cddr list))))))
           (even-half ( list )
             (if (null list) list (odd-half (cdr list)))))
    (cond ((null list) list)
          ((null (cdr list)) (car list))
          (T (let ((l1 (even-half list))
                   (l2 (odd-half list)))
               (max (find-max-002 l1) (find-max-002 l2)))))))

;; Simplistic speed test              
(let ((list (loop for x from 0 to 10000 collect (random 10000))))
  (progn
    (print "Running find-max-001")
    (time (find-max-001 list))
    (print "Running find-max-002")
    (time (find-max-002 list))))
现在你可能会问自己,为什么我只使用10000作为列表大小,因为对于渐近计算来说,这是相当小的。事实上,sbcl认识到第一个函数是尾部递归的,因此将其抽象为一个循环,而第二个函数则没有,因此,在不破坏堆栈的情况下,这是我能得到的最大值。虽然从下面的结果可以看出,这足以说明这一点

"Running find-max-001"
Evaluation took:
  0.000 seconds of real time
  0.000000 seconds of total run time (0.000000 user, 0.000000 system)
  100.00% CPU
  128,862 processor cycles
  0 bytes consed

"Running find-max-002"
Evaluation took:
  0.012 seconds of real time
  0.012001 seconds of total run time (0.012001 user, 0.000000 system)
  [ Run times consist of 0.008 seconds GC time, and 0.005 seconds non-GC time. ]
  100.00% CPU
  27,260,311 processor cycles
  2,138,112 bytes consed
即使在这个水平上,我们也在谈论大规模的经济放缓。在直接检查每个项目一次的方法降低到算法的10k评估之前,需要增加到大约一百万个项目

 (let ((x (loop for x from 0 to 1000000 collect (random 1000000))))
   (time (find-max-001 x)))

Evaluation took:
  0.007 seconds of real time
  0.008000 seconds of total run time (0.008000 user, 0.000000 system)
  114.29% CPU
  16,817,949 processor cycles
  0 bytes consed
最后的想法和结论

所以接下来要问的问题是,为什么第二种算法真的要花那么长的时间。在不深入细节的情况下,有几件事真的很突出


第一个是犯人。现在是的,cons是O1,但这仍然是系统要完成的另一个操作。它要求系统分配和释放内存,并启动垃圾收集器。第二件真正让人吃惊的事情是,你基本上是在运行一个合并排序,除了抓取列表的下半部分和上半部分之外,你还要抓取奇偶节点,这也需要更长的时间,因为你每次都要迭代来构建列表。这里的算法充其量是一个On log n算法,请注意,这是一种合并排序,非常适合排序,但它会带来很多额外的开销。

据我所知,您刚刚将On算法变成了On log n算法?是什么让你认为它会更快?除非你知道列表是如何排序的,否则max算法必须查看每个元素,这不能比On更好。据我所知,你刚刚把On算法变成了On log n算法?什么妈妈 你觉得会更快吗?除非您知道列表是如何排序的,否则max算法必须查看每个元素,这不会比On更好。