调试Clojure中执行缓慢的函数

调试Clojure中执行缓慢的函数,clojure,clojure-core.logic,Clojure,Clojure Core.logic,我正在尝试实现一个解决方案,用于在clojure中对数组进行排序所需的最小交换 代码可以工作,但是需要大约一秒钟的时间来求解7元素向量,这与Java中的类似解决方案相比非常糟糕。(编辑) 我已经尝试过提供显式类型,但似乎没有什么不同 我尝试使用瞬变,但在我的解决方案中使用的subvec有一个开放性错误- 有关于如何优化解决方案的建议吗 ;; Find minimumSwaps required to sort the array. The algorithm, starts by iterati

我正在尝试实现一个解决方案,用于在clojure中对数组进行排序所需的最小交换

代码可以工作,但是需要大约一秒钟的时间来求解7元素向量,这与Java中的类似解决方案相比非常糟糕。(编辑) 我已经尝试过提供显式类型,但似乎没有什么不同 我尝试使用瞬变,但在我的解决方案中使用的subvec有一个开放性错误-

有关于如何优化解决方案的建议吗

;; Find minimumSwaps required to sort the array. The algorithm, starts by iterating from 0 to n-1. In each iteration, it places the least element in the ith position. 

(defn minimumSwaps [input]
  (loop [mv input, i (long 0), swap-count (long 0)]
    (if (< i (count input))
       (let [min-elem (apply min (drop i mv))]
        (if (not= min-elem (mv i))
          (recur (swap-arr  mv i min-elem),
                 (unchecked-inc i),
                 (unchecked-inc swap-count))
          (recur mv,
                 (unchecked-inc i),
                 swap-count)))
      swap-count)))

(defn swap-arr [vec x min-elem]
  (let [y (long (.indexOf vec min-elem))]
    (assoc vec x (vec y) y (vec x))))

(time (println (minimumSwaps [7 6 5 4 3 2 1])))
;;查找排序数组所需的最小交换数。该算法从0到n-1迭代开始。在每次迭代中,它将最少的元素放置在第i个位置。
(定义最小交换[输入]
(环路[mv输入,i(长0),交换计数(长0)]
(如果(
在算法和效率方面,您的解决方案中有一些地方可以改进。主要的改进是在搜索向量时记住向量中的最小元素及其位置。这允许您不再使用.indexOf搜索最小元素

这是我修改后的解决方案,速度快了约4倍:

(defn swap-arr [v x y]
  (assoc v x (v y) y (v x)))

(defn find-min-and-position-in-vector [v, ^long start-from]
  (let [size (count v)]
    (loop [i start-from, min-so-far (long (nth v start-from)), min-pos start-from]
      (if (< i size)
        (let [x (long (nth v i))]
          (if (< x min-so-far)
            (recur (inc i) x i)
            (recur (inc i) min-so-far min-pos)))
        [min-so-far min-pos]))))

(defn minimumSwaps [input]
  (loop [mv input, i (long 0), swap-count (long 0)]
    (if (< i (count input))
      (let [[min-elem min-pos] (find-min-and-position-in-vector mv i)]
        (if (not= min-elem (mv i))
          (recur (swap-arr mv i min-pos),
                 (inc i),
                 (inc swap-count))
          (recur mv,
                 (inc i),
                 swap-count)))
      swap-count)))
(定义交换阵列[v x y]
(助理律师x(y)y(x))
(定义查找向量[v]中的最小值和位置,^long start from]
(让[大小(计数v)]
(循环[我从开始,最小到目前为止(长(第n个v从开始)),最小位置从开始]
(如果(
要了解程序中的性能瓶颈在哪里,最好使用而不是猜测

注意我是如何从您的代码中删除
未选中-*
内容的。这在这里并不重要,而且很容易出错。如果要使用它们提高性能,请确保使用反编译器检查生成的字节码:

java中的类似实现,运行时间几乎为一半


这对Clojure来说实际上相当好,因为您使用的是不可变向量,而在Java中可能使用数组。将Clojure解决方案重写到阵列后,性能几乎相同。

我怀疑
indexOf
。你需要它吗?如果将索引直接传递给
交换arr
,则不必进行昂贵的线性搜索,因为向量通过索引具有近似常数
get
。最明显的是
(应用最小子arr)
,它在
If/recur
中被双重调用。这一个相当昂贵,将其结果移动到
使性能加倍。谢谢,很好的捕获@leetwinski。我更新了代码,但这并没有起到作用。我能够稍微优化它,在“subvec”(返回一个持久向量)上使用“drop”(返回一个惰性序列)
大约一秒钟的时间
-你确定吗?在我的电脑上需要4毫秒-如何启动此代码?谢谢!剖析器真的很有帮助。是的,你是对的,当使用不可变时,我不应该期望像数组一样的性能。