递归算法解决汉诺塔,真值表等问题总结整理

                                                        递归算法

了解递归算法
在编程中,要保证易读性和正确性的最有效手段就是函数。执行一个逻辑操作(可以是非常长和复杂的操作)的一组指令可以用函数组织起来。
函数的名称和它的变量可以看成是一个新的可用在其他程序中的指令。已知一个函数的输入和输出,我们甚至都不用知道它到底是如何完成任务的,只需知道可以用这样一个函数,这样的函数定义意味着它被调用,执行然后将控制权还给调用它的那个程序的适当位置。
在这里,函数有可能在结束执行之前调用它们自身(直接递归),或者调用其他反过来有可能调用它自身的函数(间接递归)。
递归算法实现汉诺塔问题
汉诺塔问题描述
汉诺塔问题发源于古老的梵天寺之塔仪式。传说但世界诞生的时候,有一座摞了64个黄金的碟子的钻石塔(记为A)。碟子按从小到大的次序自底向上地摞在塔上。除此之外,还有两个钻石塔(记为B和C)。从世界诞生之时起,梵天寺的僧侣就在通过塔B将碟子从塔A挪到塔C。因为碟子都非常重,一次只能挪一块。另外,然后时候都不能大碟子在上小碟子在下。根据传说,当僧侣完成任务的时候就是世界的末日。在这里插入图片描述
这个问题可以通过递归来解决,假设碟子数是n,为了将最大的碟子挪到C上,我们需要将剩下的n-1个碟子先挪到塔B,然后再将最大的碟子挪到塔C,最后将剩下的n-1个碟子挪到塔C最大碟子的上面,这样就可以实现所有碟子由A到C了。下面我们需要解决的是如何将塔B上的n-1个碟子挪到塔C上。此时,塔C上的碟子是最大碟子,因此不影响任何碟子置于其上。于是,我们将问题转换成了如何将塔B上的n-1个碟子通过塔A,全部挪到塔C上,通过相同的方法,变为塔A上的n-2个碟子如何通过塔B挪到塔C。依次递进,直到一个碟子如何到另一个塔。

import java.util.Scanner;
public class Main {
	public static void main(String[] args) {
		int n;                                                                                       //输入n值
		String A="A";
		String B="B";
		String C="C";
		Scanner sc=new Scanner(System.in);
		n=sc.nextInt();
		HanNt(n,'A','B','C');                                                                 //调用递归函数
		
	}
	public static void HanNt(int n,char A,char B,char C) {
		if(n==1){
			move(A,C);            //执行A到C,传进来的AC不确定,A可能是B,也可能是C,C也如此。在此参照形参与实参。
		}else {
			HanNt(n-1,A,C,B);     //改变ABC位置,使得即便移动的是"A"和"C",变为了移动A和B
			move(A,C);
			HanNt(n-1,B,A,C);     //改变ABC位置,使得即便移动的是"A"和"C",变为了移动B和C
		}
	}
	public static void  move(char A,char C) {
		System.out.println(A+"-->"+C);
	}

}

汉诺塔实现总结
通过此算法,我们实现了汉诺塔的移动,在编写代码过程中,我也对64个碟子以及世界末日产生了兴趣,通过输入3,4,5等等验证了代码的正确性之后,我输入了64(其实在输入6时,我已经察觉到了);然后程序开始无限输入下去,很久都没有停止(尽管我知道等栈溢出之后它会停止)。于是我不得不强制关闭程序;然后百度,移64层的汉诺塔需2^64 -1=18,446,744,073,709,551,615步。如果是一秒一次的话,那么就是18,446,744,073,709,551,615秒。也就是584,942,417,355年26天7小时15秒(以上是百度内容)。看来这个数字是真的庞大。所以回归代码,实现这个n=64时,代码的时间复杂度(大于等于2^64)也是非常大的。回头反思一下,递归算法是不断调用自身函数的过程,而每一次函数调用,都需要在内存栈中分配空间以保存参数、返回地址以及临时变量,而往栈中压入数据和弹出数据都需要时间。递归中很多计算都是重复的,由于其本质是把一个问题分解成两个或者多个小问题,多个小问题存在相互重叠的部分,则存在重复计算,而每一次函数调用会在内存栈中分配空间,而每个进程的栈的容量是有限的,当调用的层次太多时,就会超出栈的容量,从而导致栈溢出。因此递归算法的缺陷也是显而易见的。
递归算法实现真值表
问题描述
给定n个布尔变量X1,X2,------,Xn,我们想打印出它们所有可能的赋值组合。例如,如果n=2,那么一共有四种可能:真,真; 真,假: 假,真: 假,假。
在这里插入图片描述
对于此问题,我们对结果(为了方便表述,我们假设结果有2n个)分析,总是可以将其分为两类,一类是真(T(1))开头,一类是假(F(0))开头,由此,问题分成了两部分,在真开头后,如何将真后的n-1个组合列出来。和在假开头后,如何将假开头后的n-1个组合列出来。此时,开头的真假已确定,问题进而转换为将两个n-1个组合结果列出来,我们可以再次将其分为两部分,直到最后输出真假。

import java.util.Scanner;
public class Main{
			public static void main(String[] args){
						int n;
						Scaner sc=new Scanner(System.in);
						n=sc.nextInt();                                             //输入n值
						String a[]=new String[n];                             //定义输出数组,长度为n
						int   l=0;                                                       //定义l,用来检测函数递归到了哪步
						Tf(l,n,a);
			}
			public static void Tf(int x,int y,String a[]){
						int i;
						if(x==y){                                                  //通过比较x(l),y(n)来确定是否到达输出条件
								for(i=0;i<y;i++){
										System.out.println(a[i]);        //输出顺序不变,算法中的各种赋值步骤,导致输出结果的改变
								}
								System.out.println("\n");
								return;
						}
						a[x]="T";                                                //将当前a[x]赋值为T
						Tf(x+1,y,a);                                            //x+1进入递归函数
						a[x]="F";                                                //将当前a[x]赋值为F
						Tf(x+1,y,a);                                           //x+1进入递归函数
			}
}

真值表实现总结
通过上述算法,我们得到了布尔变量为n的真值表。总结,我们刚开始问题分析的时候,说将问题分为开头为TF两部分,然后再分。直到最后。但通过我们对算法逐步追踪,以及结果分析。其结果(n=3举例)为 TTT,TTF,TFT,TFF,FTT,FTF,FFT,FFF。我们发现该算法的实现并不是简单的同步实现。也就是说实现FFF的代码执行是在FFT完成的基础上。代码运行过程中,反复的进出函数的过程远比我们想象的复杂。例如:TFT(第三个结果,分析简单一点,大家体验一下)就是实现TTF之后,代码继续执行将a[2]赋值为F,从而实现TTF,之后返回到x=1;将a[1]赋值为F,然后再进入下面的递归函数,将a[2]赋值为T,然后进入输出循环,输出TFT。而我们在想怎么解决该问题时,似乎并没发现函数运行的复杂程度。而是按照自己的想法将函数嵌套即可。这也正反应了递归算法的一大优点。在解决问题时,避免了其复杂的过程,使问题变得简单,容易实现。
递归算法的总结
通过以上两个问题,我想大家对递归算法应该有了一定的认识。总的来说,递归算法虽然使得解题过程变得简单,理论上,递归算法可以替代循环。但其执行过程却是异常复杂的,占用了大量的内存空间。在这里说一下,递归算法能解决的问题,总能找的其他算法解决。因此,我还是建议大家多思考,想出别的算法更好。毕竟递归算法对计算机不太友好,作为程序员,当然应该考虑一下自己的“女朋友”。。。。。。嘻嘻嘻。

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值