今天我们来认识一下------------------递归!

看看这个你会更快的理解:当你往镜子前面一站,镜子里面就有-一个你的像。 但你试过两面镜子一起照吗?如果A、B两面镜子相互面对面放着,你往中间- -站,嘿,两面镜子里都有你的千百个“化身”。为什么会有这么奇妙的现象呢?原来,A镜子里有B镜子的像,B镜子里也有A镜子的像,这样反反复复,就会产生-连串的“像中像”。这是一种递归现象.

1.程序调用自身的编程技巧称为递归。递归是算法在设计语言中广泛使用。通常把一个大型的问题层层转换为一个与原问题相似的规模较小的问题来求解,递归策略只需要少量的程序就可描述出解题的过程所需要的多次重复计算,减少了代码量。递归的能力在于用于有限的语句定义对象无线的集合。一般情况,递归需要有边界条件,递归前进段和递归反回段,当边界条件不满足时,递归前进,当边界条件满足时,递归返回。

  • 递归的表现:函数调用函数自己
  • 递归的用处:将大型复杂问题化解为若干小问题进行求解
  • 递归的好处:代码量少
  • 递归的弊端:占空间,函数是基于栈内存运行的

那么我们看看递归的引用:

1.求和 1+2+3+4+.....................+(n-1)+(n);

前n项的和 f(n) = 1+2+3+4+.....n;

则 f(100)= f(99) +100 , f(3) = f(2)+3;   特殊的  f(1)  = 1;

public int Nsum(int n){if(n = 1){return 1;}else{return Nsum(n-1) +n;}}

2.n的阶乘

设函数f(n) = n * f(n- 1);

则 f(3) = 3 * f(2);

特殊 f(1) = 1;

public int Njie(int n){if(n == 1){return 1;}else{return Njie(n-1) * n;}}

3.斐波那契数列前20项:1,1,2,3,5,8,13,21.......................(递归编程 对于 这个数 分支 随着 数 越来越大  分支多。导致  时间过程  显得 递归不适用)

设函数f(n) = f(n -1) + f(n-2)

则 f(4) = f(3) + f(2) , f(3) = f(2) + f(1)

特殊的f(1) = 1, f(2) = 1

解法1:递归

public int fbnqsl(int n){if(i == 2 || i == 1){return 1;}else{return fbnqsl( n-1) + fbnqsl( n-2);}
}

解法2:迭代(相比之下,和递归相比,速度快了许多)

public int  ddfbqnsl(int n){int n =1;int m = 1;int out =0;for(int i = 1 ; i <= n ; i++){if(i == 1 || i == 2)System.out.println("1");}else{out = n+ m;System.out.println(out);n = m;m = out;}}

4.汉诺塔问题

将最左边的盘子移动 最 指定的盘子上。( 条件不能将 大的放在 小的上面)

那么先简单看看 3 个如何移动

第一步

第二步:

第3步:

第4步

 第5步:

第6步

最后:

 那么想一想: 100个   50 个   20 个   10  个    5 个   1个

其实实质都是大化小去解决的。

首先思想是 , 如何理解 怎么处理 盘子的移动问题 , 那么我们用 这样的思想 ,去思考 我们只靠率 从哪到哪就行(自己规定就可以了)。

那么怎么决定  移动的方向----》

接下来 用递归问题,就是 考虑边界问题, 那么边界是 :  剩最后一个盘子 从 哪  移动  到 哪  就结束了。

那么 看这个 3 个的就可以看出  最后只用 从 开始的地方(x)  移动  要去的地方(y)。

既然要用大划小来处理问题,那么 就问你 。

public void move( int n , String form , String mid , String to){if(n == 1){System.out.println(form +"------------>"+to);}else{move(n -1 , from , to , mid);   //1.每一步都执行到最后一步  直到 n == 1 时 才会执行                    //第二步 (将 x - 1  移动   y上面)System.out.println(form +"------------>"+to); //第二步move(n -1 , mid , from , to);   //将 y 上面移动到 z上面}}

5.八皇后问题:

在一个8 x 8 的棋盘,放入8个皇后棋子,

要求同行、同列、同斜线不能有重复的皇后棋子

1.分析 对于棋盘上的8个棋子去判断

首先我们了解一下 这个八皇后位置不唯一对吗? 好好思考一下,与数读不一样的是, 我们所要的是只要满足条件情况,不管这八个皇后在那个位置。所以答案不唯一。 在每一行可行的棋盘下都,都是同一个数组,因为每一行的皇后唯一。

那么 每一次 都需要 从上一个基础上 从新 的开始因为每一次都有可能是八皇后的位置。 (每一从上一次基础上再去向下重新开始每一个位置的变化),再继续去变化。

意思是:

这是在第一行开始的其他情况:

这是第一行第一个中的情况 ,还有其他的所有情况未画出。

了解了八皇后问题了后,我们来看看如何编写代码?

public class eightwfwing{public staitc int count = 0; //用来定义 打印输出多少种情况public static void main (String[] args){int[][] board = new int[8][8]; //创建一个棋盘 默认值为 0 1表示皇后。eightQueue(0, board);}private static void eightQueue(int row ,int[][] board){if( row >= 8){count++;System.out,println("第"+count+"次");for(int i = 0 ; i<board.length ; i++ ){for(int j = 0; j < board[i].length ; j++){System.out.print(board[i][j] + " " );}System.out.println();}}else{//1.复制 因为 每一个起始点开始,往下都有可能的 ,为了不共享棋盘复制很方便。int[][] newboard = new int[8][8] ;for(int i = 0 ; i<board.length ; i++ ){for(int j = 0; j < board[i].length ; j++){newboard[i][j] = board[i][j];}        }//在复制后的棋盘 开始从0 位置 到  8位置 for( int col = 0 ; col < 8 ; i++){   //从复制完的这一行开始 按列去添加if(NoDanger(row , col , newboard)){  //递归的边界值//先清除当前的行for(int c = 0 ; c < 8 ; c++){  //为了处理同行中前一个写了皇后使         //下面的 行 不满足 所以从新列的开                                                //始 填入皇后前 先处理掉之前的皇后newboard[row][c] = 0;}//放皇后newboard[row][col] = 1;eightQueue(row + 1 , newboard);}}}}private staic boolean NoDanger(int row , int col , int[][] newboard){//正上for(int r=row-1;r>=0;r--){if(newBoard[r][col]==1){return false;}}//左上for(int r=row-1,c=col-1;r>=0&&c>=0;r--,c--){if(newBoard[r][c]==1){return false;}}//右上for(int r=row-1,c=col+1;r>=0&&c<8;r--,c++){if(newBoard[r][c]==1){return false;}}return true;})

添加皇后的思想:

例如:

大概过程如上------》;

------------------------------------------------------------------------------------------------------------------------------------------------------------------------

程序调用自身的编程技巧称为递归。递归是算法在设计语言中广泛使用。通常把一个大型的问题层层转换为一个与原问题相似的规模较小的问题来求解,递归策略只需要少量的程序就可描述出解题的过程所需要的多次重复计算,减少了代码量。递归的能力在于用于有限的语句定义对象无线的集合。一般情况,递归需要有边界条件,递归前进段和递归反回段,当边界条件不满足时,递归前进,当边界条件满足时,递归返回。

  • 递归的表现:函数调用函数自己
  • 递归的用处:将大型复杂问题化解为若干小问题进行求解
  • 递归的好处:代码量少
  • 递归的弊端:占空间,函数是基于栈内存运行的

对于前进段与分治算法如何理解?

当我们求解某些问题时,由于这些问题要处理的数据相当多,或求解过程相当复杂,使得直接求解方法在时间上相当长,或者根本无法直接求出。对于这类问题,我们往往先把它分解成几个子问题,找到求出这几个子问题的解法后,再找到合适的方式,把它们组合成求整个问题的解法。如果这些子问题还较大,难以解决,可以再把它们分成几个更小的子问题,以此类推,直至可以直接求出解为止。这就是分治算法的基本思想,分而治之。
分治算法应用举例--------文件夹遍历

需求:遍历一个文件夹中所有的文件

public class diguimulu {public static void main(String[] args) {String p = "E:/";   //传入一个磁盘lookmulu(p);        //调用 函数}public static void lookmulu(String path) {File file = new File(path);  //创建一个对象 用来获取磁盘中的文件String[] s = file.list();    //list() 返回夹文件夹的名字的数组//listFile() 返回文件夹对象的数组if(s != null) {           //判断文件名字符串是否为空for (String string : s) {    //遍历String nextPath = path +"/" +string;  // 组合文件夹的名字File f = new File(nextPath);          //创建一个对象 获取新文件夹对象if(f.isFile()) {                  //判断是否说文件对象System.out.println(f.getAbsolutePath());  //打印出文件的路劲}else {lookmulu(nextPath);          //如果这个文件对象不是文件是文件夹 就继续调                                //用自身}}}}
}

分治算法应用举例----二分查找

需求:在有序数组中查找指定元素。

看看如何去是实现:


public class Testerfen {public static void main(String[] args) {int[] n = {1,2,3,4,5,6,7,8,9,10,11,12};int l = 0;int r = n.length-1;int cher = 11;while(l <= r) {int mid = r+l/ 2 ;if(mid > cher) {r = mid - 1;}else if (mid < cher){l = mid+ 1;}else {System.out.println(mid);break;}}}
}

对于二分查找用循环去写,那么能迭代写的,一定能递归,能用递归写的,迭代不一定能写。

返回段与回溯算法

那么意思是 递归函数直到不能去调用函数时,往回返的过程就是回溯,简单的说就和进山洞一样,进了一层又一层,那么进到不能再进去的时候,往回走的过程就是回溯。

回溯算法实际上是一个类似枚举的搜索尝试过程,主要是在搜索尝试过程中寻找问题的解,当发现已不满足求解条件时,就“回溯”返回,尝试别的路径。回溯法是一种选优搜索法,按选优条件向前搜索,以达到目标。但当探索到某-步时,发现原先选择并不优或达不到目标,就退回一步重新选择,这种走不通就回退再走的技术称为回溯法,而满足回溯条件的某个状态的点称为“回溯”点。许多复杂的,规模较大的问题都可以使用回溯法,有“通用解题方法"的美称。

那么我们来理解下回溯的应用:

数读求解:

首先先说一下:

玩家需要根据9×9盘面上的已知数字,推理出所有剩余空格的数字,并满足每一行、每一列、每一个粗线宫(3*3)内的数字均含1-9,不重复。

数独盘面是个九宫,每一宫又分为九个小格。在这八十一格中给出一定的已知数字和解题条件,利用逻辑和推理,在其他的空格上填入1-9的数字。使1-9每个数字在每一行、每一列和每一宫中都只出现一次,所以又称“九宫格”。

那么了解了数读如何玩,我们来分析一下,怎样是满足数读要求的呢

首先 行 不能 重复 列也不能重复, 在属于自己的小九宫格不能重复出线相同的数字。

数读的解是唯一的;

那么放数字,按照行开始按顺序 依次按(1----9)去填空 如果 那个空能填写 那么就依次去填写如果填到 行的数下一个空无法在在太填写数时,那么需要回溯。就像如下情况。

那么如何处理回溯情况呢?先将此空的数清除,再接着去向此空的数向后循环填入去填。

那么先这样去填,看看如何?

在从第二行开始去填,依次类推。(必须要判断的是  行 不能重复  列 不能重复    小九宫格不能重复)

如下 : 在假设的情况下,该空不能填其他数了,那么就要回溯到该空前面的空, 将 原来数  基础上 向后 加一 ,在填入到空格中,在进行判断。 依次类推。

那么,如何填数读,差不多就了解完了。

二、编译阶段

1.分析行,列问题,填数字的问题 对于每列去填空 (列 加 1)%对 列的长度取余.(列的下标从 0 开始     0-----8 编号   9  列)

行数根据 列数 去 改变(行数也从 0---8 开始   9行)

例如  ,开始是 i = 0; 当列大于的长度 大于 9 时    int 类型  10 / 9  = = 1  此时  10/9 = 2  第二行  i = 10/9

列数一直从 0--------81  个数

row = 0;

col = 0;

row = row + (col+1)/9;   换行时;

col = (col + 1)% 9; 列加 1;

分析出   列是 一直加 的数。

数读中的元素,可以将数字事前导入进去, 将空白的地方输入成零,那么

005300000
800000020
070010500
400005300
010070006
003200080
060500009
004000030
000009700

1.首先读取一个数读

标准输入:

 public class A{public static int[][] board = new int[9][9];public static void main(String[] args){Scanner sc = new Scanner(System.in);for(int i = 0 ; i < 9 ; i++){// 005300000 String line = sc.nextLine(); //获取数读上本应有的基础的数读for(int j = 0 ; j < 9 ; j++){//将输入的字符串 中 每个字符获取到 line.charAt(j) //在用Integer.parseInt(//填字符串); //所以  line.charAt(j)+""   字符转 字符串board[i][j] = Integer.parseInt(line.charAt(j)+");}}print();   //打印出 整个数读 }//打印方法private static void print(){for(int i = 0 ; i < 9 ; i ++){for(int i = 0 ; i < 9 ; i ++){System.out.print(board[i][j]+" ");}}solve(0,0);  //开始求解数读}//填写数字private static void solve( int row , int col){if( row >= 9){print();System.exit(0); //为什么要用这样的方式去关闭 ,针对程序的关闭方式//应为递归会一直往下去执行 所以将程序关闭即可。}else{if(board[row][col] == 0){  for(int n = 1 ; n <= 9 ; n++){//判断这个空能填什么数字if(!isExist( row , col ,n)){ board[row][col] == n;//会一直执行 ,直到 不能执行时//根据 是否能填数 作为 这个递归的边界                                                   solve( row+(col+ 1) / 9 ,(col + 1) % 9); }//从if中跳出来  将这个空 清零board[ row][col] = 0;}}else{//如果 这个空有 填的数 就像下继续填solve(row+(col+ 1) / 9 ,(col + 1) % 9);}     }}private static boolean isExist(int row , int col , int n){//先看行for(int c = 0 ; c < 9 ; c++){if(board[row][c] == n){return true;}}//再看列for(int r = 0 ; r < 9 ; r++){if(board[r][col] == n){return true;}}//后看小九宫格// 1.先确定 由行决定  小九宫格 的位置  0-----2  3---5  6----8 // 2.在同样的去确定列 去判断小九宫格的 位置  0-----2  3---5  6----8// 3.因为 如果我们用 二维数组 去判断。 // 4.在行数上知道到行的最小 和最大值// 5.在列数上知道列的最小和最大   // 6.用双重for循环 去 将这个数在  属于他的小 九宫格中 去判断 是否能填 这个数 nint rowMin = 0;int rowMax = 0;int colMin = 0;int colMax = 0;if(r >= 0 && r <= 2){romMin = 0;romMax = 2;}if(r >= 3 && r <= 5){romMin = 3;romMax = 5;}if(r >= 6 && r <= 8){romMin = 6;romMax = 8;}if(c >= 0 && c <= 2){colMin = 0;colMax = 2;}if(c >= 3 && c <= 5){colMin = 3;colMax = 5;}if(c >= 6 && c <= 8){colMin = 6;colMax = 8;}for(int xr = rowMin ; xr <= rowMax ; xr ++){for(int xc = colMin ; xc <= colMax ; xc++ ){if(board[xr][[xc] == n){return true;}}}return false;}}

数读编程思路: 如何填数字

首先:对于 递归的算法需要,先进行边界考虑。(不能无限递归)

1.那么没在边界时候的考虑, 需要判断 空 是否有数字? 没数字 就考率需要填啥 ,有数字就向下递归

需要考虑到所有数字 都要判断一次  再  for循环 里   先判断 是否 1-----9 之间的数啥  填完数字 从这个空 再向下 递归 ,,直到 不能递归了,就将 回溯 一层 一层 的回溯 直到 能 向下继续递归位置 。

2. 判断空需要填啥 ,那么就 新建方法  (判断是否  行  列   小九宫格 能填 这个数字)

数据结构(五)------递归相关推荐

  1. 浅谈算法和数据结构: 五 优先级队列与堆排序

    原文:浅谈算法和数据结构: 五 优先级队列与堆排序 在很多应用中,我们通常需要按照优先级情况对待处理对象进行处理,比如首先处理优先级最高的对象,然后处理次高的对象.最简单的一个例子就是,在手机上玩游戏 ...

  2. 数据结构-二叉树[递归实现](构造,析构,先序遍历,中序遍历,后续遍历,层次遍历)

    数据结构-二叉树[递归实现] 一.二叉树概念 1.定义 二叉树(Binary Tree)是n(n不小于0)个节点组成的有限集合,且满足以下条件之一 (1)n=0时,为空二叉树(无节点) (2)n> ...

  3. 前端必会算法——线性数据结构的递归遍历

    上一篇: 前端必会算法--线性数据结构的遍历 线性数据结构的递归遍历 数组是知道长度的,最好的遍历方式的循环 var arr = [1,2,3,4]; //循环遍历数组,常见,常用 function ...

  4. 数据结构五——二叉树

    文章出处:极客时间<数据结构和算法之美>-作者:王争.该系列文章是本人的学习笔记. 1 树 1.1 概念 概念:树.根.父节点.子节点.叶子节点. 几个度:高度.深度.层.与实际生活中的这 ...

  5. [数据结构]递归树:借助树求解递归算法的时间复杂度

    文章目录 递归树与时间复杂度分析 实战一:分析快速排序的时间复杂度 实战二:分析斐波那契数列的时间复杂度 实战三:待补充,先学其他的... 递归树与时间复杂度分析 我们前面讲过,递归的思想就是,将大问 ...

  6. 数据结构 非递归实现中序遍历二叉树

    参考书籍:c++ 数据结构 之前提到用递归的方法实现中序遍历二叉树,但是递归会浪费大量的空间与时间.这时候我们就在想用没有一种方式能够不依赖递归去实现遍历二叉树.我们之前学过一种数据结构可以实现这种方 ...

  7. 蒟蒻的ACM数据结构(五)-左式堆

    左式堆 一.序 二.用处 三.基本概念 四.合并 五.代码实现 (一).结构 (二).合并 (三).插入 (四).删除 (五).样例代码 例题 (hdu 1512) Monkey King Probl ...

  8. 数据结构(五)堆排序

    1.算法流程 (1)对原始数据构建大根堆: A.从下至上,遍历每个非叶子父节点,保证每个非叶子父节点都比它的左右子节点来的大,非叶子父节点的对应索引范围为[0,n/2-1]; B.在遍历每个非叶子父节 ...

  9. 【恋上数据结构】递归(函数调用过程、斐波那契数列、上楼梯、汉诺塔、递归转非递归、尾调用)

    递归(Recursion) 什么是递归? 函数的调用过程(栈空间) 函数的递归调用过程 递归实例分析(1 + 2 + 3 + ... + 100 的和) 递归的基本思想.使用套路 斐波那契数列 fib ...

  10. 数据结构(递归及应用)

    递归是数据结构中一种常用的算法,在非线性结构中,有相当多的问题都是使用递归的方法来解决,递归也是一种"很好用"的方法. 那么什么是递归呢? 递归就是将一个复杂的问题化成若干个简单的 ...

最新文章

  1. 安装软件the error code is 2203解决方法
  2. nginx 重写 隐藏index.php
  3. 转载:由图片SEO想起
  4. suse系统关闭防火墙
  5. 【转】VS.NET2003 调试无法启动
  6. WPF简单的口算案例
  7. 一篇文章彻底说清JS的深拷贝/浅拷贝
  8. shopify在哪里填写html,[Shopify开店教程]添加嵌入代码
  9. @SpringBootApplication(exclude = {DataSourceAutoConfiguration.class}) 注解的作用
  10. C++_类和对象_C++继承_继承中的构造和析构顺序---C++语言工作笔记064
  11. AIS 2021顶级论文报告会论文征集与听众报名通知
  12. C++游戏服务器开发常用工具介绍(转载)
  13. hdu 5288 OO’s Sequence(计数)
  14. 计算机管理五大功能,操作系统五大管理功能包括哪些介绍大全
  15. 计算机视觉的一些SCI期刊
  16. 报错ImportError: cannot import name ‘webdriver‘ from partially initialized module ‘selenium‘ (most lik
  17. android 自定义软键盘
  18. mysql多表成绩查询_MySQL多表查询答案
  19. 扁平化大漠主题卡通 PPT模板
  20. matlab示波器如何反白,stc12单片机写的简易示波器代码,求大神答疑

热门文章

  1. 深度学习21_李宏毅_03_General Guidance
  2. 判断是否构成三角形,并用海伦公式计算三角形的面积
  3. 记录一次iOS App Store审核被拒5.1.1的原因
  4. LTE学习笔记六:MIMO多天线技术
  5. Oracle开发者性能课第3课(我的查询做了多少工作)实验
  6. Android日志分析
  7. 如何构建Sinatra?
  8. Unable to chmod /system/build.prop.: Read-only file system
  9. Camtasia Studio录制屏幕字迹不清晰的原因
  10. 假设机票原价为5000元,4~ 10月为旺季,旺季头等舱打9折,经济舱打6折,其他月份为淡季,淡季头等舱打5折,经济舱打4折。