这是一个clojure程序,用于从文件中读取整数并计算反转次数,即在序列中较小的数字之前出现较大数字的次数。它实现了一个O(n ^ 2)算法,并且在大小为100,000的输入上运行大约需要30分钟。
(defn count-inversions
[file]
(let [int-list (vec (map #(Integer/parseInt %)
(clojure.string/split (slurp file) #"\r\n")))]
(loop [c 0
t-list int-list]
(let [size (count t-list)]
(if (empty? t-list)
c
(recur (reduce #(if (< %2 (first t-list)) (inc %1) %1) c (subvec t-list 1 (dec size)))
(subvec t-list 1 (dec size))))))))
使用Java实现此算法只需几秒钟即可完成。为什么这么大的差异?
答案 0 :(得分:5)
看起来对我来说可能很慢的事情(虽然你必须确定基准以确定......)
(set! *unchecked-math* true)
提高整数运算的性能(显然,如果可能发生溢出,你需要更加小心)。如果我想让它在Clojure中运行得非常快,我可能会使用原始数组并使用原始索引进行循环:
(set! *unchecked-math* true)
(defn count-inversions [coll]
(let [^ints integers (int-array coll)
size (long (count integers))]
(loop [c (long 0)
i (long 0)]
(if (>= i size)
c
(recur
(loop [c (long c)
v (aget integers i)
j (inc i)]
(if (>= j size)
c
(recur (long (if (> v (aget integers j)) (inc c) c)) v (inc j))))
(inc i))))))
(time (count-inversions (for [i (range 100000)] (rand-int 100))))
"Elapsed time: 16036.651863 msecs"
即。这段代码在我的机器上大约16秒内计算100,000个整数的所有反转(使用Clojure 1.3)