如何优化Clojure图二分评分代码以提升执行效率?
图二分评分计算的代码优化建议
当前代码用于统计图二分的跨组边数,通过VisualVM采样发现性能瓶颈集中在clojure.core$empty_QMARK_和clojure.core$contains_QMARK_,以下是针对性优化建议:
1. 用reduce替代手动递归遍历,消除empty?的频繁调用
原代码通过递归手动遍历edges,每次递归都要调用empty?检查剩余序列,这会带来额外的性能开销。改用reduce可以自动处理序列遍历,无需手动判断序列是否为空,同时代码更简洁:
(defn tstBisectScore "number of edges crossing bisect" [bisect edges] (reduce (fn [count [n1 n2]] (let [in-b1? (contains? bisect n1) in-b2? (contains? bisect n2)] (if (not= in-b1? in-b2?) (inc count) count))) 0 edges))
2. 优化bisect的集合类型,提升contains?的查询效率
contains?的性能完全依赖bisect的集合类型:
- 如果bisect是普通列表或向量,
contains?会做线性扫描,速度极慢,必须转换成哈希集合(用(set bisect)或(hash-set ...)生成),哈希集合的contains?是O(1)复杂度。 - 如果节点是连续的非负整数,推荐使用
bit-set,它的contains?操作是位运算,比哈希集合更快:;; 将bisect转换为bit-set (def bisect-bit (apply bit-set bisect)) ;; 之后用(contains? bisect-bit n)查询
3. 简化条件判断逻辑,减少布尔运算开销
原代码的复合布尔判断可以简化为直接比较两个节点是否在同一组,等价逻辑更简洁且减少运算步骤:
原条件:
(or (and inb1 inb2) (and (not inb1) (not inb2)))
简化后等价逻辑:
(= inb1 inb2)
当该条件为false时,说明边跨组,需要计数。
4. 预转换edges为非惰性序列(如果适用)
如果edges是惰性序列,遍历过程中会有额外的惰性求值开销,可以提前将其转换为向量((vec edges)),提升遍历效率。
内容的提问来源于stack exchange,提问作者rikb
相关产品推荐
相关产品推荐

