尝试实现背包问题的直观动态规划算法。显然,这种方法使用了大量内存,因此我正在尝试优化所使用的内存。我只是简单地尝试在内存中仅存储表格的前一行,以便计算下一行等。起初,我认为我的实现很稳固,但它仍然会耗尽内存,就像一个设计用于存储整个表格的实现一样。所以接下来我想也许我需要使用
因此,我有两个具体的问题:
1. 是什么导致我的代码使用了所有的内存?我认为使用fold是很聪明的,因为我假设只有累加器的当前值会被存储在内存中。 2. 实现我的目标的正确方法是什么?即仅在内存中存储最近的一行?我不一定需要代码,也许只需要一些有用的函数和数据类型。更普遍地说,了解Haskell中内存使用的技巧和技术有哪些?
以下是我的实现:
在我的理解中,这段代码的作用是将第一行初始化为(0,[])...如有必要,则重复此过程,然后启动折叠操作,其中下一行是基于提供的行计算得出的,并且此值成为累加器。我没有看到越来越多的内存被消耗的地方...
随机想法:如果我在累加器上使用\\操作符会怎样?
foldl'
而不是foldr
,但这并没有产生任何区别。我的程序继续占用内存,直到我的系统用完为止。因此,我有两个具体的问题:
1. 是什么导致我的代码使用了所有的内存?我认为使用fold是很聪明的,因为我假设只有累加器的当前值会被存储在内存中。 2. 实现我的目标的正确方法是什么?即仅在内存中存储最近的一行?我不一定需要代码,也许只需要一些有用的函数和数据类型。更普遍地说,了解Haskell中内存使用的技巧和技术有哪些?
以下是我的实现:
data KSItem a = KSItem { ksItem :: a, ksValue :: Int, ksWeight :: Int} deriving (Eq, Show, Ord)
dynapack5 size items = finalR ! size
where
noItems = length items
itemsArr = listArray(1,noItems) items
row = listArray(1,size) (replicate size (0,[]))
computeRow row item =
let w = ksWeight item
v = ksValue item
idx = ksItem item
pivot = let (lastVal, selections) = row ! w
in if v > lastVal
then (v, [idx])
else (lastVal, selections)
figure r c =
if (prevVal + v) > lastVal
then (prevVal + v, prevItems ++ [idx])
else (lastVal, lastItems)
where (lastVal, lastItems) = (r ! c)
(prevVal, prevItems) = (r ! (c - w))
theRest = [ (figure row cw) | cw <- [(w+1)..size] ]
newRow = (map (row!) [1..(w-1)]) ++
[pivot] ++
theRest
in listArray (1,size) newRow
finalR = foldl' computeRow row items
在我的理解中,这段代码的作用是将第一行初始化为(0,[])...如有必要,则重复此过程,然后启动折叠操作,其中下一行是基于提供的行计算得出的,并且此值成为累加器。我没有看到越来越多的内存被消耗的地方...
随机想法:如果我在累加器上使用\\操作符会怎样?
foldl'
在每一步都对累加器进行 WHNF 求值。但这是否足够取决于累加器中存储的值。看起来它是一个包含大量元组的数组。这些必须是普通的箱式数组,因此强制其中一个进行 WHNF 将确保分配该数组并初始化每个单元格 - 以指向(可能未求值的)thunk 的指针。 - Carl