【发布时间】:2019-10-26 10:06:21
【问题描述】:
我正在用 OCaml 编写,试图给出一个(有点)有效的素数分解实现。我认为数字 2 或更多的最佳表示是在指数列表中。为简单起见,我将按质数降序进行。所以 2 是 [1],3 是 [1;0],4 是 [2],5 [1;0;0]。
我正在考虑使用筛子的想法来获取一个数字 n 并查找 2 和 sqrt(n) 之间的所有可能除数。然后除以任何除数并递归。但是,我能想到的每个实现似乎都涉及重复搜索列表,这似乎不必要地低效。这段代码最好地说明了我的解决方案的大纲
let rec pf n =
if (n=2) then ([1], 0)
else let sq = int_of_float ( (float_of_int n) ** 0.5 ) in
let primes = getPrimes sq in
match earliestDiv n primes with
| None -> n::(zero_list (n-1))
| Some (x, i) -> let subproblem pf (n/x) in
increment subproblem i
这里的辅助函数是:
-
getPrimes接受一个 int 并返回一个包含所有小于或等于它的素数的列表。 -
earliestDiv接受一个整数n和整数列表lst,返回一个 int*int 选项,该选项对应于lst中最早的数字,该数字除以n。那将是元组的第一个坐标;第二个坐标将返回素数列表中素数x的索引。 -
increment将采用 int 列表和索引,并将位于索引处的数字加 1。
所有这些辅助函数都在不断地创建列表、传递列表等等。事实上,我经常觉得我在函数式编程中这样做。我经常觉得我在不必要地迭代列表,而在命令式语言中我会编写更高效的代码。也许它只是在我的脑海中,当用命令式语言编写时,我很少注意到我使用的一些列表操作中有多少资源。但是,如果我遗漏了一些可以防止重复扫描列表的重要技术,我会很想知道的。
问题:为了编写这个函数,是否有必要反复创建和迭代列表?
【问题讨论】:
-
@Ken White 问题是是否有必要重复创建和迭代列表。这对我来说听起来像是一个编程问题。
-
@KenWhite 问题已更新。
-
作为旁注,您可能想尝试编写代码来将表示中的两个数字相乘。我的主张是排列相应的素数会很麻烦。如果列表以指数 2 开头,则对齐是自动的。
-
作为另一个旁注,遍历列表并不比遍历数组慢。只有当您需要随机访问时才会有所不同。
-
您还可以考虑您的表示对于 100 位素数(例如)的样子。
标签: functional-programming ocaml primes prime-factoring