Algorithm 实施Karger';函数范式中的s最小割算法
我在任何命令式语言中实现这个算法都没有问题,但我正在努力用Clojure或任何其他函数式语言实现它。很多算法都是以处理可变数据结构和命令循环的方式来描述的,我很难将所有这些转换成函数域 以下是我使用邻接列表作为图形表示在Clojure中实现它的不完整尝试(草稿,而不是工作实现):Algorithm 实施Karger';函数范式中的s最小割算法,algorithm,graph,clojure,functional-programming,imperative-programming,Algorithm,Graph,Clojure,Functional Programming,Imperative Programming,我在任何命令式语言中实现这个算法都没有问题,但我正在努力用Clojure或任何其他函数式语言实现它。很多算法都是以处理可变数据结构和命令循环的方式来描述的,我很难将所有这些转换成函数域 以下是我使用邻接列表作为图形表示在Clojure中实现它的不完整尝试(草稿,而不是工作实现): (ns karger.core (:require [clojure.string :as string])) (defn load-data [] (zipmap (range 1 1000
(ns karger.core
(:require [clojure.string :as string]))
(defn load-data []
(zipmap
(range 1 1000)
(map rest (map read-string
(string/split (slurp "data.txt") #"\n")))))
(defn min-cut [graph]
(let [start (rand-int (count graph))
end (rand-int (graph start))
start-list (nth graph start)]
(for [x (graph end)
:when (not= x start)]
(assoc graph start (conj start-list x)))
))
(count (load-data))
谁能给我一个这个算法的参考实现(最好是用Clojure编写的)?另外,我想知道是否有人给了我一个将命令式描述的算法翻译成函数域的一般建议
提前谢谢
更新#1
这里有一个指向用Python编写的算法实现的链接:您的代码存在一些基本问题:
- 您的
绑定是一个数字,不能start list
ed to'conj
- 您正在调用
并忽略返回值,从而使其成为禁止操作assoc
- 您正在为使用
,就好像它是一个循环构造(它是一个列表理解)
- 您正在对哈希映射调用
,该操作将始终失败(nth
返回哈希映射)zipmap
一般来说,函数式编程的思想是将可变变量提升到不可变的局部绑定中,方法是将“世界状态”完全封装在函数参数中,并使用该状态的优化版本进行函数调用 下面是一个基于您发布的python解决方案和java示例使用的图形文件的从头开始的工作实现
(ns min-cut.core
(:require[clojure.java.io:as-io]
[clojure.string:作为字符串]
[clojure.pprint:请参阅[pprint]])
(defn制作地图
[文件名]
(减少(fn[图形线]
(让[[节点和边](>>行
(#(字符串/拆分%#“\W+”))
(删除#{“})
(映射读取字符串))]
(关联图形节点(设置边)))
{}
(行顺序(io/读卡器文件名)))
(德芬·卡格尔)
[图表]
(如果(你能用命令式语言提供算法吗?你能展示data.txt中的一行是什么样子的吗?如果不知道该文件中的数据是如何形成的,那么很难区分是什么意思还是什么错误。我假设通过使用read string
和rest
,每一行都是一个Clojure序列on看起来并不是非常必要。一般来说,函数编程的思想是提供将函数参数化的所有“状态”作为附加参数,并在函数的返回值中返回所有“状态更改”(然后在调用函数中使用这些新值).我开始研究该算法的纯函数clojure实现,基于解决方案,并将图形作为输入和输出传递给每个函数,但这对于现在的SO答案来说有点太多了-如果没有其他人这样做,我可能会在下一次进行翻译。此外,这里的代码远不是一个实现在该算法的基础上,被数据类型和函数的误用所困扰。这可以很容易地与核心进行并行。还原程序
,这样每个CPU都在计算尝试次数,并保留最小的尝试次数。
(ns min-cut.core
(:require [clojure.java.io :as io]
[clojure.string :as string]
[clojure.pprint :refer [pprint]]))
(defn make-maps
[filename]
(reduce (fn [graph line]
(let [[node & edges] (->> line
(#(string/split % #"\W+"))
(remove #{""})
(map read-string))]
(assoc graph node (set edges))))
{}
(line-seq (io/reader filename))))
(defn karger
[graph]
(if (<= (count (keys graph))
2)
(count (graph (apply min (keys graph))))
(let [start (rand-nth (keys graph))
finish (rand-nth (vec (graph start)))
graph (loop [g graph
[edge & edges] (seq (graph finish))]
(if-not edge
g
(recur
(if (= edge start)
g
(update-in g [start] conj edge))
edges)))
graph (loop [g graph
[edge & edges] (seq (graph finish))]
(if-not edge
g
(let [gr (update-in g [edge] disj finish)
gr (if (= edge start)
gr
(update-in gr [edge] conj start))]
(recur gr edges))))
graph (dissoc graph finish)]
(recur graph))))
(defn -main
[& [file]]
(let [file (or file "kargerAdj.txt")
graph (make-maps file)]
(println "min cut is: "
(reduce min (repeatedly 1801 #(karger graph))))))