bash(awk递归)N阶【斐波那契数列】多种实现(含递归解析图)

【版权所有】转载请说明作者【Jev Tes】
       【本文导航】
       零、关于斐波那契数列
       一、输入参数合法性判断
       二、TYP 1:常规累加法
       三、TYP 2:数组传递法
       四、TYP 3:递归法
           1、shell递归
           2、awk优化递归
       五、效率比较

   


零、关于斐波那契数列
    斐波那契数列又称黄金分割数列,因数学家列昂纳多·斐波那契以兔子繁殖为例子而引入,故又称为“兔子数列”,指的是这样一个数列: 0、 1、 1、 2、 3、 5、 8、 13、 21、 34、 ……,这个数列从第3项开始,每一项都等于前两项之和。
    斐波纳契数列以如下被以递归的方法定义: F(0)=0, F(1)=1, F(n)=F(n-1)+F(n-2)( n≥2)


一、输入参数合法性判断

    编写脚本/函数时,对输入参数合法性的判断非常重要,可以规避很多不必要的麻烦,特别是调试递归函数时!

#--------------------------------输入参数合法性判断--------------------------------
if ! echo $1 | egrep "^[0-9]+$"  &> /dev/null ; #如果输入不是0或正整数,执行下面语句
then
    echo "-Fib 119:error token is \""$1"\"!"   #回显错误信息
    exit 110                     #退出脚本
fi
#------------------------------------------------------------------------------

二、TYP 1:常规累加法
    整体思路:从第3阶开始计算F3=F2+F1=1+1=2、F4=F3+F2=2+1=3…依次计算到第N阶;
    主体代码跟分析如下:

#--------------------------------累加算法--------------------------------
fib()                             #定义函数
 { 
local i=2                         #本地变量,做计数用
local Fib0=0                      #本地变量,记录传递F(n-2)的值,初始值为F0的值
local Fib1=1                      #本地变量,记录传递F(n-1)的值,初始值为F1的值
local $Fibn                       #本地变量,记录传递F(n)的值
[ $1 -eq 0  ] && echo "F(0)=0" && return 0  #如果$1值为0,直接回显F(0)=0,退出函数
[ $1 -eq 1  ] && echo "F(1)=1" && return 1  #如果$1值为1,直接回显F(1)=1,退出函数
until  [ $i -gt $1  ] ; do        #当$i大于$1(计算阶数)时,退出循环
Fibn=$[Fib1+Fib0]                 #Fn=F(n-1) +F(n-2),n为此时$i的值
Fib0=$Fib1                        #将当前F(n-1)的值,即为下轮F(n-2)的值
Fib1=$Fibn                        #将当前F(n)的值,即为下轮F(n-1)的值
i=$[i+1]                          #对$i进行累加1
done 
echo  "F("$1")=$Fibn"             #退出循环后,输出Fn的值
 }
fib $1                            #引用函数

三、TYP 2:数组传递法
    整体思路:跟常规累加传递法类似,从第3阶开始计算,依次计算到第N阶,但这方法奇妙在于用数组来储存整个数列,可以将整个数列完整保存下来;
    主体代码跟分析如下:

#--------------------------------数组传递法--------------------------------
fib()                        #定义函数
{
declare -a Fib               #定义数组Fib
Fib[0]=0                     #赋值F0=0
Fib[1]=1                     #赋值F1=1
Fib[2]=1                     #赋值F1=1
case $1 in
0)
    echo ${Fib[0]}           #如果$1值为0,直接回显F(0)=0
    ;; 
1)
    echo ${Fib[1]}           #如果$1值为0,直接回显F(0)=0
    ;;
*)
    for i in `seq 2 $1`;do   #$i在2-$1时进行循环
    Fib[$i]=$[${Fib[$i-1]}+${Fib[$i-2]}]  #Fib[$i]的值为前两项的值之和
    done
    echo ${Fib[$1]}          #退出循环后,输出Fn的值
    ;;
esac
}
fib $1                       #引用函数


四、TYP 3:递归法
   整体思路:跟以上俩种思路相反,函数从N阶开始,依次向下递归展开,直到$1=1,$1=0,时停止递归,并将值回传给父函数;
   主体代码跟分析如下:
       1、shell递归 

#-------------------------------shell递归---------------------------------
Fib()                         #定义函数 
{ if [ $1 -eq 0 ]  ;
then   echo 0                   #当$1值为0,回显0
elif [ $1 -eq 1 ]  ;then   echo 1     #当$1值为0,回显1
else   echo $[$(Fib $[$1-1])+$(Fib $[$1-2])]    
 #递归展开Fn=F(n-1)+F(n-2)直到$[$1-1]=1,$[$1-2]=0,递归终止fi} 
Fib $1                       #引用函数

       2、awk优化递归 

#--------------------------------awk递归算法--------------------------------
awk -v i=$1  'function Fib(i){
if(i==0){ return 0}               #当$i值为0,返回0
else if(i==1){return 1}           #当$i值为0,返回0
else{return Fib(i-1)+Fib(i-2)}    #展开递归,计算Fib(i-1)+Fib(i-2)的值
}BEGIN{ print Fib(i)}'

简单递归思路解析:(以4阶为例,即$1=4)
F4=F3+F2 

    =(F2+F1)+(F1+F0)      
    =[(F1+F0)+F1]+(F1+F0) 
    =3F1+2F0 
    =3
   递归解析图如下:(以4阶为例,即$1=4)
   递归-兔子数列.png

五、效率比较
   测试环境
   虚拟平台:VMware
   虚拟机系统:centos6.8
   虚拟机配置:CPU*2(宿主主机CPUI56300),内存1664MB
简单测试结果如下
     常规累加法
   递归-兔子数列1.png
     数组传递法
   递归-兔子数列2.png
     shell递归
   递归-兔子数列3.png
     awk优化递归
   递归-兔子数列4.png
   从这个简单的测试可以得出:
    从算法角度来说,直接累加运算效率最高,数组传递算法略逊些,由于递归比较耗资源,效益最低;
    从计算速度来讲awk计算高于bash计算;
注:递归计算时间资源消耗都随着阶数的变化呈指数性增长
    

     

【点击返回页首】

【版权所有】转载请说明作者【Jev Tes】

原创文章,作者:Jev Tse,如若转载,请注明出处:http://www.178linux.com/60651

(0)
Jev TseJev Tse
上一篇 2016-11-24
下一篇 2016-11-24

相关推荐

  • Linux运维实战之一:初识计算机组成及Linux系统

    本次博文是Linux运维实战的开山篇,主要内容如下: 计算机的组成及其功能; Linux的不同发行版之间的联系与区别; Linux的哲学思想; Linux系统上命令的适用格式及一些常用命令的使用; Linux系统上如何获得帮助信息; Linux发行版的基础目录名称命名法则及功用规定; 一、计算机的组成及其功能: 问题引入:互联网时代,计算机是我们每天都要使用…

    Linux干货 2016-10-31
  • 马哥教育网络班20期+第2周课程练习

    1、Linux上的文件管理类命令有:cp复制, mv剪切, rm移除 使用方法: cp复制  cp [OPTION]… [-T] SOURCE DEST  常用选项: -i:交互式 -r: 递归复制目录及内部的所有内容 -a: 归档 演示: SRC是文件,会将/etc/fstab 中内容覆盖到/bin/po…

    Linux干货 2016-06-23
  • Zabbix介绍、安装配置

    Zabbix介绍、安装配置 我们为什么需要监控? 常用的开源监控系统有哪些? Zabbix架构 Zabbix的安装和配置 总结 前言 本篇文章转自我的个人博客 http://anyisalin.com 欢迎大家访问 我们为什么需要监控? 没有监控就将系统上线, 就是在耍流氓; 在生产环境中, 监控是必不可少的, 因为我们需要实时了解业务的…

    2016-05-13
  • linux文件权限管理和用户,组管理常用命令应用实例

    用户和组概念简述 用户一般指使用计算机的人,GNU/linux通过用户和用户组实现对计算机的文件访问和设备使用控制。 用户分类1.管理员root(类似皇帝,权力最大)2.普通用户:分为系统用户和普通登录用户。系统用户不登录,常用于发起一些进程提供服务,防止进程被劫持带来的风险,所以尽量减少以root身份发起进程对外提供服务。3.用户标识UID。管理员的UID…

    2017-10-05
  • Linux计划任务和进程

    一、进程管理 1.进程简介 一个程序对应多个进程;一个进程对应一个程序。 2.进程状态的查看与控制 查看进程状态 w 查看个别用户的进程 eg: w userName list-info JCPU: PCPU: WAHT: from: IDLE: 用户空闲时间 load average: ps -aux -a: 显示所有用户的进程 -u:显示用户名和启动时间…

    2017-09-09
  • Nginx负载均衡

    基于Nginx的负载均衡以及高可用简单应用 一、负载均衡配置 1、Nginx负载均衡配置 前面配置好的Nginx,可以访问之后,克隆4台,统一配置为512M,因为我的电脑内存是4G的。一台用来访问,一台用来做调度器(Director),两台web服务器(real server),Nginx前面已经介绍过了,故在此简单介绍一下那台Director的配置。 2、…

    Linux干货 2016-12-29