递归:能够解决那些难以用简单循环解决的问题

例如:八皇后问题,阶乘

递归函数: 调用自身的函数

1.阶乘:

0 !=1

1!=1

n!=n*(n-1)!

(n-1)!=(n-1)(n-2)!

假设函数factorial(n)为求n!;

如果调用到n=0的情况,函数直接返回结果,函数知道如何求解最简单的情形,称之为基本情况或者“停止条件”。如果参数大于0,函数将问题规约为求解(n-1)!的子问题。在递归中,子问题应该更简单或者更小,但是子问题和原问题具有相同的性质,可以用一个不同的参数调用本函数来求解子问题。这称之为递归调用。

#include <iostream>using namespace std;int factorial(int);int main(int argc, char *argv[])
{cout << "Enter a int number: ";int num;cin >> num;cout << num << "! = " << factorial(num) << endl;return 0;
}int factorial(int n)
{if(n==0)return 1;   // 停止条件 elsereturn n*factorial(n-1);   // 递归调用
}

函数递归调用的执行过程:

例如: 斐波那契额数列:
定义函数fib(n),求数列前n项

fib(0)=0;

fib(1) = 1;

fib(2) = fib(1)+fib(0)

fib(3) = fib(2)+fib(1)

#include <iostream>using namespace std;int fib(int);int main(int argc, char *argv[])
{cout << "Enter a int number: n" << endl;int num;cin >> num;cout << "The fib is " << fib(num) << endl;return 0;
}int fib(int n) // 求解斐波那契额数列
{if(n==0)return 0;   // 停止条件 else if(n==1)return 1; elsereturn fib(n-1)+fib(n-2);   // 递归调用
}

例如:fib(4)的调用过程。   调用栈的变化情况

利用递归判断回文字符串:

#include <iostream>
#include <string>using namespace std;bool  isPalindrome(const string& s)
{// 基本情况分为两种 1.首尾字符不相同,return false 2. 字符串长度为1或者0 return true if(s[0]!=s[s.size()-1])return false;else if(s.size()<=1)return true;elsereturn isPalindrome(s.substr(1,s.size()-2));   // 获得子串,递归判断 }int main(int argc, char *argv[])
{cout << "Enter a string: " << endl;string ss;getline(cin, ss);if(isPalindrome(ss))cout << "The string is Palindrome" << endl;elsecout << "The string is not Palindrome" << endl;return 0;
}

递归辅助函数

给类似原问题的问题定义一个递归函数.(这句话有点绕),得到原问题的求解方案,这种新的函数叫做递归辅助函数

对isPalindrome()函数的改进。

#include <iostream>
#include <string>using namespace std;// 为了避免每次递归都要创建新的字符串,这里传入了参数low和high,指出上下界的范围
// 重载isPalindrome()函数作为辅助函数
// 定义一个辅助函数接受额外的参数
// 递归方案中有字符串和数组,递归辅助函数是非常有用的bool isPalindrome(const string& s, int low, int high)
{// 基本情况分为两种 1.首尾字符不相同,return false 2. 字符串长度为1或者0 return true if(s[low]!=s[high])return false;else if(low>=high)return true;elsereturn isPalindrome(s, low+1, high-1);   // 获得子串,递归判断 }// 函数重载
bool isPalindrome(const string& s)
{return isPalindrome(s, 0, s.size()-1);
}int main(int argc, char *argv[])
{cout << "Enter a string: " << endl;string ss;getline(cin, ss);if(isPalindrome(ss))cout << "The string is Palindrome" << endl;elsecout << "The string is not Palindrome" << endl;return 0;
}

递归的方法实现选择排序,对字符串进行排序:

#include <iostream>
#include <string>using namespace std;// 定义一个辅助函数接受额外的参数
// 递归方案中有字符串和数组,递归辅助函数是非常有用的
void sort(string& s, int high)   //递归辅助函数
{if(high>0){int max_index = 0;char max_char = s[0];for(int i=0; i<=high; i++){if(s[i]>max_char){max_char = s[i];max_index = i;}}s[max_index] = s[high];s[high] = max_char;sort(s, high-1);  // 递归调用 }
} void sort(string& s)
{sort(s, s.size()-1);
}int main(int argc, char *argv[])
{cout << "Enter a string: " << endl;string ss;getline(cin, ss);sort(ss);cout << "The String After sorted: " << ss << endl;return 0;
}

递归实现二分搜索:

#include <iostream>
#include <string>using namespace std;// 定义一个辅助函数接受额外的参数
// 递归方案中有字符串和数组,递归辅助函数是非常有用的
int binary_search(const int list[], int key, int low, int high)
{if(low>high)  // 未找到return -low-1;int mid = (low+high)/2;if(key<list[mid])return binary_search(list, key, low, mid-1);else if(key==list[mid])return mid;elsereturn binary_search(list, key, low+1, high);
} int binary_search(const int list[], int key, int size)
{return binary_search(list, key, 0, size-1);
}int main(int argc, char *argv[])
{int list[] = {2,3,4,5,6,7,8,9,12,14,16,18,19,20,34};int i = binary_search(list, 4, 15);int j = binary_search(list, 9, 15);int k = binary_search(list, 20, 15);int m = binary_search(list, 11, 15);cout << "binary_search(list, 4, 15) return" << i << endl;cout << "binary_search(list, 9, 15) return" << j << endl;cout << "binary_search(list, 20, 15) return" << k << endl;cout << "binary_search(list, 11, 15) return" << m << endl;return 0;
}

运行结果:

汉诺塔问题:

汉诺塔问题的递归特点:

此问题的基本情况(停止条件)是:n==1时,将唯一一个盘子从A移动到B.

原问题分解为三个子问题:

1.将n-1个盘子从A->C, B作为辅助

2.将最下面的第n个盘子从A->B.

3.将n-1个盘子从C->B,A作为辅助

#include <iostream>
#include <string>using namespace std;void moveDisk(int n, char fromTower, char toTower, char auxTower)
{if(n==1)cout << "Move disk " << n << " from " << fromTower << " to " << toTower << endl;else{moveDisk(n-1, fromTower, auxTower, toTower);cout << "Move disk " << n << " from " << fromTower << " to " << toTower << endl;moveDisk(n-1, auxTower, toTower, fromTower); }} int main(int argc, char *argv[])
{cout << "Enter number of disks:  ";int diskNumber;cin >> diskNumber;moveDisk(diskNumber, 'A', 'B', 'C');   return 0;   //
}

运行结果:

八皇后问题:

#include <iostream>
#include <string>using namespace std;// 定义数组queen[8]
// queen[i]=j   代表i行j列的皇后
const int NUMBER_OF_QUEENS = 8;
int queen[NUMBER_OF_QUEENS];// 判断解的合法性
bool isValid(int row, int column)
{for(int i=1; i<=row; i++){if(queen[row-i]==column || queen[row-i]==column-i || queen[row-i]==column+i)return false;} return true;
} //
bool search(int row)
{if(row==NUMBER_OF_QUEENS)  //停止条件 return true;for(int column=0; column<NUMBER_OF_QUEENS; column++){queen[row] = column;if(isValid(row, column) && search(row+1))return true;}return false;
}// display the chessboard
void display()
{cout << "\n-----------------\n";for(int row=0; row<NUMBER_OF_QUEENS; row++){for(int column=0; column<NUMBER_OF_QUEENS; column++){cout << ((column==queen[row])?"|Q":"| ");}    cout << "|\n-----------------\n";}
}
int main(int argc, char *argv[])
{search(0);display();   return 0;   //
}

递归有着严重的额外开销,每当程序进行函数调用时,系统必须为所有的局部变量和参数分配内存空间,需要消耗相当大的内存,可能造成栈溢出(stack overflow)的错误。

尾递归

尾递归可以有效地减少堆栈空间。

注:(书本)

尾递归是可取的,因为当最后一次递归调用结束时,函数就结束了,所以没有必要存储在堆栈中的中间调用,有些编译器可以优化尾递归来减少堆栈空间。

一个非为尾递归的函数可以通过使用辅助参数转换为一个尾递归函数。

c++学习笔记(16) 递归相关推荐

  1. cocos2d-x学习笔记16:记录存储1:CCUserDefault

    cocos2d-x学习笔记16:记录存储1:CCUserDefault 一.简述 CCUserDefalt作为NSUserDefalt类的cocos2d-x实现版本,承担了cocos2d-x引擎的记录 ...

  2. SpringBoot学习笔记(16)----SpringBoot整合Swagger2

    Swagger 是一个规范和完整的框架,用于生成,描述,调用和可视化RESTful风格的web服务 http://swagger.io Springfox的前身是swagger-springmvc,是 ...

  3. Hadoop学习笔记—16.Pig框架学习

    Hadoop学习笔记-16.Pig框架学习 一.关于Pig:别以为猪不能干活 1.1 Pig的简介 Pig是一个基于Hadoop的大规模数据分析平台,它提供的SQL-LIKE语言叫Pig Latin, ...

  4. 台大李宏毅Machine Learning 2017Fall学习笔记 (16)Unsupervised Learning:Neighbor Embedding

    台大李宏毅Machine Learning 2017Fall学习笔记 (16)Unsupervised Learning:Neighbor Embedding

  5. Linux 学习笔记16 信号量

    Linux 学习笔记16 信号量Semaphore 信号量概念 信号量(或信号灯)是一种用于提供不同进程间或一个给定进程的不同线程间同步手段的原语. 信号量是控制进程(或线程)同步(谁先执行,谁后执行 ...

  6. Netty网络框架学习笔记-16(心跳(heartbeat)服务源码分析)

    Netty网络框架学习笔记-16(心跳(heartbeat)服务源码分析_2020.06.25) 前言: Netty 作为一个网络框架,提供了诸多功能,比如编码解码等,Netty 还提供了非常重要的一 ...

  7. 区块链学习笔记16——ETH交易树和收据树

    区块链学习笔记16--ETH交易树和收据树 学习视频:北京大学肖臻老师<区块链技术与应用> 笔记参考:北京大学肖臻老师<区块链技术与应用>公开课系列笔记--目录导航页 交易树和 ...

  8. 【论文学习笔记-16】立体匹配:360SD-net

    [论文学习笔记-16]立体匹配:360SD-net Contribution RelatedWork Method Experiment 本文利用两张360°摄像机获得的球形图片进行立体匹配,与双目立 ...

  9. Python学习笔记16:实操案例十三(编写程序实现乐手弹奏乐器,设计自定义类表达出租车和家用轿车信息)

    Python学习笔记16:实操案例十三(编写程序实现乐手弹奏乐器,设计自定义类表达出租车和家用轿车信息) 1.编写程序实现乐手弹奏乐器 注意Python的多态是"鸭子类型",只要有 ...

最新文章

  1. 选 Offer 的 5 个维度
  2. linux用冒泡排序程序,利用双向走动法改进冒泡排序算法C语言源代码[黑盟核心成员]...
  3. 单选按钮android服务器,android – 如何在radiogroup中将单选按钮设置...
  4. Visual Studio 选择相同变量高亮
  5. python计算存款_python入门教程NO.8 用python写个存款利息计算器
  6. Spring-tx-TransactionAttributeSource接口
  7. linux 超好用的命令行工具
  8. 浙大计算机学硕名额,浙大计算机学硕复试线399分,专硕375,不愧被称为“炸大”...
  9. 关于液晶触摸屏的信号传递?
  10. Python中的多线程是假的多线程?
  11. 5G NR协议栈及功能2 - MAC RLC PDCP SDAP
  12. vue中如何加入横线_vue
  13. 【520521】程序员中的“芳心纵火犯”, 这就是面向对象编程吗?
  14. 三维图像专业处理软件Dragonfly 应用-如何计算面孔隙率
  15. 验厂中首当其冲的BSCI是什么
  16. Matlab之魔方阵magic
  17. AppStore搜索不到已上架应用问题
  18. 如何将swf格式转换为MP4格式
  19. Android:相对布局RelativeLayout常用属性
  20. QCC51XX---Earbud peer pair与handset pair

热门文章

  1. Netty工作笔记0011---Channel应用案例2
  2. 将Notepad++配置为Ruby编译器
  3. 使用string定义一个变量如何输出
  4. 微型计算机原理设计存储系统,微机原理存储器设计讨论报告
  5. 随想录(关于dsp)
  6. 一步一步写算法(之“数星星”)
  7. linux远程测试题,linux内训考试题及答案
  8. php跳转到safari打开,新手教程: 如何重新打开关闭的Safari标签
  9. java web启动socket_javaweb启动时启动socket服务端代码实现
  10. java 线程安全性_i++是线程安全的吗?如何解决线程安全性?