递归与循环
有如下代码:
public static void main(String[] args)
{
for (int i = 0; i <10 ; i++)
{
System.out.println(i);
}
}
循环打印0-9.若是采用递归形式便是,可以定义函数print,利用if循环打印出n的值。
public static void print(int n)
{
if (n>=0)
{
print(n-1);
System.out.println(n);
}
}
public static void main(String[] args)
{
print(9);
}
关键是找到相似性。
print方法还可以这样写,if只执行一条语句,可以这样写(C语言)
public static void print(int n)
{
if (n>0) print(n-1);
System.out.println(n);
}
方法二:用户角度出发定义begin 和end代表起止
public static void print(int begin,int end)
{
if (begin>end) return;//判断起是否大于止
System.out.println(begin); //打印begin
print(begin+1,end);//实现begin+1
}
public static void main(String[] args)
{
print(0,9);//输入起止
}
递归是一种灵活的写法,并非只有一种写法。
改用递归关键是发现逻辑的相似性,不要忘记递归的出口!
递归与数学上的递推公式相似,如果没有相似性,需要主动构造。不能相似的原因很可能是缺少参数。 (大量练习,找到感觉)
例2:求数组之和
有一个数组,现在需要求数组之和。
不难想到遍历数组,再每项相加。但我们不妨定义一个add方法将操作都放在方法之内。main方法负责数组的定义与结果的输出,可以得到有如下代码:
public class Test2
{
public static int add(int[] a)
{
int x = 0;
for (int i = 0; i < a.length; i++) x += a[i];
return x;
}
public static void main(String[] args)
{
int[] a = {2, 3, 4, 5, 6, 7};
System.out.println(add(a));
}
}
但上述代码貌似与递归毫无关系,如果要使用递归满足需求,不妨考虑二分法,或者踢皮球的思想。
我们可以定义一个add方法传入数组a和起始值begin,当begin与a.length的长度相等时,返回一个0,使结果不会失真。
public static int add(int[] a, int begin)
{
if (begin == a.length) return 0;//求a数组中,从begin到结束的元素之和。返回一个0为了使最终值不失真
int x = add(a, begin + 1);//定义x存储结果
return x + a[begin];
}
public static void main(String[] args)
{
int[] a = {2, 3, 4, 5, 6, 7};
int sum = add(a, 0);//并非是初始值为0,而是说从第0项开始(数组下标第一项是0)
System.out.println(sum);
}
tip:还可以通过如下三种解法获取到结果
1.a[begin]+(begin+1+…+end)
2.(a[0]+…+end-1)+a[end]
3.折半求和:mid=(begin+end)/2,[begin,mid)+[mid,end]
例3:比较两个字符串是否相同
不难想到Java自带的equals去比较两个字符串是否相等,再返回一个布尔值
public class Test3
{
public static boolean compare(String s1,String s2)
{
return s1.equals(s2);
}
public static void main(String[] args)
{
System.out.println(compare("123","abc"));
}
}
但如上所述,我们还是可以定义一个方法去比较二者是否相等,以取代Java自带的equals函数。代码如下:
public static boolean compare(String s1, String s2)
{
if (s1.length() != s2.length()) return false;
if (s1.length() == 0 && s2.length() == 0) return true;//此处可以只判断一个字符串是否为空,如果不是则第一个循环已经返回false
if (s1.charAt(0) != s2.charAt(0)) return false;//判断首字符是否相同
return compare(s1.substring(1), s2.substring(1));
}
public static void main(String[] args)
{
// System.out.println(compare("123", "abc"));
System.out.println(compare("123","123"));
}
递归调用:仅仅是被调函数恰巧为主调函数,且调用的层次不同
注意:每次返回的次序,每次分配的形参并非同一个变量
递归总的来说就是本代码调用本代码,因为栈结构是先进后出。
任何循环都是可以改成递归,需要找到相似性(可构造),注意递归的“出口”。