我正在用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
,并返回一个对应于lst
中最早数字的int * int选项,该选项将{{1}除以}。那将是元组的第一个坐标;第二个坐标将返回素数列表中该素数n
的索引。 x
将获取一个int列表和索引,并将位于索引处的数字加1。所有这些帮助器功能都会不断创建列表,传递列表等。实际上,我经常觉得我在函数式编程中正在这样做。我经常觉得我不必要遍历列表,而在命令式语言中,我会写效率更高的代码。也许这只是在我的脑海,用命令式语言编写时,我很少会注意到我使用的某些列表操作中有多少资源。但是,如果我错过了一些可能阻止重复扫描列表的重要技术,我很想听到它。
问题:要编写此功能,是否有必要重复创建和遍历列表?
答案 0 :(得分:2)
如果最终为列表建立索引,或者使用不超过固定大小的默认元素填充列表,则列表很可能是错误的数据结构。对于素因数分解,您可能需要一个稀疏数组的实现。与固定大小的列表相比,地图将是更好(甚至不是最佳)的实现。