bash脚本数组来记住斐波那契序列

时间:2018-11-09 12:04:56

标签: linux bash dynamic-programming fibonacci memoization

无法将斐波那契值保存到关联数组以进行单数化。该脚本以斐波那契索引作为参数,并返回关联的值序列值。在每次执行脚本时,都会生成一个从1到参数值的新序列。备忘录会减少整体运行时间。

fab.sh

Tsmart

如果fab.sh是使用if [ -f log.txt ]; then rm log.txt fi # initialize SAVED array SAVED=() # populate saved with $1 of 0's for i in $(eval echo {0..$(($1-1))}); do SAVED[i]=0 done fib () { local currentIndex=$1 if [ "$currentIndex" -eq 0 ] then echo 0 elif [ "$currentIndex" -eq 1 ] ; then echo 1 elif [[ ${SAVED[$currentIndex]} -ne 0 ]]; then echo 'MEMOIZED' >> log.txt echo ${SAVED[$currentIndex]} else SAVED[$currentIndex]=$((`fib $[$currentIndex - 1]`+`fib $[$currentIndex - 2]`)) echo ${SAVED[@]} >> log.txt echo ${SAVED[$currentIndex]} fi } if [[ $1 -eq 0 ]] then echo "Sequence limit must be at least 1" elif [[ $1 -gt 0 ]] then fib $(($1 - 1)) fi 运行的:

$ source fab.sh 5

它正在打印正确的值,但记忆功能不起作用。

log.txt文件输出为:

$ 3

似乎已重置“ SAVED”数组或分配的值未持久。由于SAVED数组是全局变量,因此我认为这会起作用。它可能与bash如何处理递归函数有关。

任何见解将不胜感激。

1 个答案:

答案 0 :(得分:3)

代替

SAVED[$currentIndex]=$((`fib $[$currentIndex - 1]`+`fib $[$currentIndex - 2]`))

您可能想写

SAVED[currentIndex]=$((`fib $((currentIndex - 1))` + `fib $((currentIndex - 2))`))

但是,这不能解决实际问题。正如我们从您的日志中看到的那样,备忘录数组始终始终只有一个条目。如何填充最后一个条目,但计算该最后一个条目所需的条目为0?答案是»subshel​​ls«

使用子外壳$(fib ...)调用函数时,函数对变量所做的更改仅在子外壳内部。 要解决此问题,您必须使用文件进行记忆,或者找到一种无需子shell即可调用函数的方法。

如果我被迫使用您当前的方法,那么这就是我写该笔录的方式。请注意,有更好的方法来计算斐波那契数和更好的语言来对这些计算进行编程。

#! /bin/bash
memo=(0 1)
fib() {
        >&2 printf %s "fib($1) memo=(${memo[*]}) => "
        local n="$1"
        if [ "${memo[n]+x}" ]; then
                >&2 echo lookup
                return
        fi
        >&2 echo compute
        fib "$((n-1))"
        fib "$((n-2))"
        ((memo[n]=memo[n-1]+memo[n-2]))
}
fib "$1"
echo "${memo[$1]}"

>&2开头的行仅用于打印调试信息。您可以删除它们。要取消调试输出,请以script.sh 12 2> /dev/null身份运行脚本。

改进:

  • 要变通解决subshel​​l问题,请不要回显函数结果并使用var=$(fib ...)来存储它,而是保持沉默并将结果直接存储在指定的全局变量中。在这里,我们不需要新变量,因为我们已经有了备忘录数组。我们首先调用fib x以确保存在数组条目x,然后使用memo[x]访问该条目。
  • 使用stderr将调试信息打印到>&2 echo,而不是打印到日志。
  • 通过将fib(0)=0存储在备忘录数组中,我们不必使用索引偏移量。
  • 将小案例0和1直接嵌入到记忆数组中。
  • 请勿使用0初始化数组。
    仅当${memo[n]}+x已被记忆时,x才会扩展为fib(n)