递归的使用

476 阅读3分钟

递归是一种解决问题的方法(a problem-solving technology):
把大任务通过重复调用其有着同样要求的小任务而得到解决

什么是递归?

  • 一种迭代或循环的替代品(注意:有的任务只能用递归解决)
  • 使得代码更简洁更美观
  • 经常应用于递归和搜索问题中

递归的关键组成

  1. base case----也就是问题的最简单形式,经常作为递归结束的出口
  2. 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;
}

\