我想知道如何使用bash中只有1个变量的递归来打印斐波那契数列。
从我所做的事情来看:
fib()
{
i=$1
if (( $i <= 1 ))
then echo 0
elif (( $i == 2 ))
then echo 1
else
echo $(( $(fib $(($i - 1)) ) + $(fib $(($i - 2)) ) ))
fi
}
echo $(fib $1)
我得到了最终迭代的正确输出,例如,如果输入10,我将得到34,但是我想打印整个数字序列,即所有迭代。我该如何实现?
我尝试的另一种方法是:
#!/bin/bash
arr[0]=0
arr[1]=1
for (( i=0; i<=10; i++ ))
do
echo -n "${arr[0]} "
arr[0]=$((${arr[0]} + ${arr[1]} ))
arr[1]=$((${arr[0]} - ${arr[1]} ))
done
echo ""
但是很明显,我在这里使用了for循环,但是我不想使用另一个变量。
答案 0 :(得分:3)
bash
中的变量默认为全局变量。您需要明确地将i
设为本地。
fib () {
local i
i=$1
if (( i <= 1 )); then
echo $i
else
echo $(( $(fib $((i-1)) ) + $(fib $((i - 2)) ) ))
fi
}
(此外,如果您从0开始,您的基本情况就有些差了,而2不必是基本情况; fib 2
可以从基本情况fib 0
和{{1 }}。
答案 1 :(得分:3)
只是出于(我的一种)乐趣,此代码使用不使用变量的递归函数将斐波那契数从0排到第92(按Fibonacci number - Wikipedia的定义):
#! /bin/bash
function fib
{
echo ${3-0}
(($1 > 0)) && fib $(($1-1)) ${3-0} $((${2-1}+${3-0}))
}
fib 92
有人可能会说使用位置参数($1
,$2
,$3
)是作弊行为,但是其他解决方案可以说是使用两个变量({{ 1}}和$i
)。
在我(旧的)Linux计算机上运行该代码需要不到0.01秒的时间。
在任何平台上的Bash版本3或更高版本中,代码都可以使用最大为92的数字。参见Bash Number Limit?。大于93的数字会由于算术溢出而导致代码产生垃圾结果。
答案 2 :(得分:1)
如果要将每个斐波那契值从1打印到$ n,我建议:
fib_r() {
local i=$1
if (( i < 0 )); then
echo "Error: negative numbers not allowed" >&2
exit 1
elif (( i <= 1 )); then
echo $i
else
echo $(( $($FUNCNAME $((i - 1)) ) + $($FUNCNAME $((i - 2)) ) ))
fi
}
fib() {
local i
for (( i = 1; i <= $1; i++ )); do
fib_r $i
done
}
fib 10
输出
0
1
1
2
3
5
8
13
21
34
它仍然是一个变量,尽管每个函数一个。
我在递归函数中使用bash变量$ FUNCNAME,因此您不必在内部使用硬编码函数名。重命名该函数时,我没有更新该行。
当然,如果您缓存结果,您的性能将会大大提高:“ fib 16”在我的VM上大约需要3.5秒而不进行缓存,而大约需要0.03秒。
fib_r() {
local i=$1
if (( i < 0 )); then
echo "Error: negative numbers not allowed" >&2
exit 1
elif [[ -n ${fib_cache[i]} ]]; then
echo "${fib_cache[i]}"
elif (( i <= 1 )); then
echo $i
else
echo $(( $( $FUNCNAME $((i - 1)) ) + $( $FUNCNAME $((i - 2)) ) ))
fi
}
fib_cache=()
fib() {
local i
for ((i=1; i<=$1; i++)); do
fib_cache[i]=$(fib_r $i)
echo "${fib_cache[i]}"
done
}