递归是一种解决问题的方法(a problem-solving technology):
把大任务通过重复调用其有着同样要求的小任务而得到解决
什么是递归?
- 一种迭代或循环的替代品(注意:有的任务只能用递归解决)
- 使得代码更简洁更美观
- 经常应用于递归和搜索问题中
递归的关键组成
- base case----也就是问题的最简单形式,经常作为递归结束的出口
- recursiom case----也就是迭代形式,可以继续进行递归,使得问题规模进一步简化
递归过程中,每次使用相同的函数,只不过函数的参数逐步减小,每一次递归过程的函数体执行被叫做---a stack frame, 作用是对当前存储的函数参数值进行调用。
最后达到最简形式,要把结果不断返回(return)给上一层递归函数直至原始函数。
所以递归必须有出口,即使void类型也要return;而且递归的参数必须符合定义,如果范围不对就会导致栈溢出,程序也会执行错误。
例子一:判断字符串是否回文
bool is_Palindrome(string s){
if(s.length()<2){
return true;
}
if(s[0]==s[s.length()-1]){
return is_Palindrome(s.substr(1,s.length()-2));
}
else{
return false;
}
}
这里其实就是两步:
首先如果字符串为空或者单个字符则return true,也就是递归的最简形式--base case
其中:s.length<2也可以写成:s==""&&s.length()==1下面的if-else就是---recursion case,比较首位两个字符,如果满足,传入去掉首尾的子串。
例子二:逆序数组
第一种----直接对原数组首尾元素交换,直至递归结束
void arr_reverse(int a[],int startIndex,int endIndex){
if(startIndex>=endIndex) return;
swap(a[startIndex],a[endIndex]);
arr_reverse(a,++startIndex,--endIndex);
}
这里的base情况就是:如果只有一个元素那么不用交换(startIndex==endIndex)
如果出现startIndex>endIndex说明交换完毕。
所以递归出口-----startIndex>=endIndex递归情况下----交换首尾,然后函数传入要把startIndex后移,endIndex前移
第二种----新开辟数组空间,用原数组对新数组赋值
void arr_reverse_helper(int a[],int b[],int k,int endIndex){
if(endIndex < 0) return;
b[k]=a[endIndex];
arr_reverse_helper(a,b,k+1,endIndex-1);
}
int* arr_aid_reverse(int a[],int n){
int* b=new int[n];
arr_reverse_helper(a,b,0,n-1);
return b;
}
arr_aid_reverse()----就是定义一个新的数组,然后返回该数组
arr_reverse_helper()----实现倒序功能
首先思考参数----两个数组,一个指向原数组末位元素的索引,一个指向开辟数组待存的索引结束标志------原数组的endIndex索引指向第一个元素之后
递归参数------每次startIndex-1;k+1由于递归对参数范围要求很严格,最好不要使用++,--的前后缀
例子三----二分查找(前提---数组排好序了)
int binary_search(int a[],int data,int startIndex,int endIndex){
int mid=(startIndex+endIndex)/2;
if(startIndex >endIndex) return -1;
//三种
if(a[mid]>data) return binary_search(a,data,startIndex,mid-1);
else if(a[mid]<data) return binary_search(a,data,mid+1,endIndex);
else return mid;
}
查找过程中:startIndex>endIndex时---说明没有找到元素,递归结束
那么递归过程三种可能:
如果a[mid]恰好等于待查元素,说明找到了,返回mid;
如果a[mid]大于待查元素,那么其后包括自己可以直接淘汰;
如果a[mid]小于待查元素,那么前一半元素,包括自己可以淘汰;
例子四--字符串逆序
/*传值*/
string str_reverse2(string s){
if(s=="") return "";
return str_reverse2(s.substr(1))+s[0];
/*每次把开头的字符串放入末位,然后对去除首位的子串进行递归*/
}
string str_reverse3(string s){
if(s=="") return "";
return s[s.length()-1]+str_reverse3(s.substr(0,s.length()-1));
/*每次把传入的字符串取末位,然后送入没有末位的子串进行递归*/
}
string str_reverse1(const string& s){//传引用,且因为不想改变变量加const
string tem=s;//引入第三方变量改变值
string rev="";
if(tem=="") return rev;
rev=str_reverse1(tem.substr(1))+tem[0];
return rev;
}
\