数据结构与算法(三)——递归

news2024/9/23 19:26:25

一、递归的概念

递归就是方法自己调用自己,每次调用时传入不同的变量。
递归有助于编程者解决复杂的问题,同时可以让代码变得简洁。

1.1 递归机制

在这里插入图片描述

递归调用规则:
1>当程序执行到一个方法时,就会开辟一个独立的空间(栈)
2>每个空间的数据(局部变量)是独立的

打印问题

在这里插入图片描述

阶乘问题

在这里插入图片描述

1.2 递归需要遵守的重要规则

1、执行一个方法时,就创建一个新的受保护的独立空间(栈空间)
2、方法的局部变量是独立的,不会相互影响
3、如果方法中使用的是引用类型变量(比如数组),就会共享该引用类型的数据
4、递归必须向推出递归的条件逼近,否则就是无限递归
5、当一个方法执行完毕,或者遇到 return, 就会返回。谁调用就将结果返回给谁,同事当方法执行完毕或者返回时,该方法也就执行完毕。

二、 递归应用实例

1、各种数学问题,如 8皇后问题、汉诺塔、阶乘、迷宫等
2、各种算法中也会使用到递归,如快排、归并排序、二分查找、分治算法等
3、将用栈解决的问题 -> 递归代码比较简洁

2.1 迷宫回溯问题

主函数

def main(args: Array[String]): Unit = {
    //先创建一个二维数组模拟迷宫
    //地图
    val map = Array.ofDim[Int](8, 7)
    new Array[Int](2)
    //使用1表示墙
    //上下全部置为1
    for (i <- map(0).indices) {
      map(0)(i) = 1
      map(7)(i) = 1
    }
    //左右全部置为1
    for (i <- map.indices) {
      map(i)(0) = 1
      map(i)(6) = 1
    }
    //设置挡板
    map(3)(1) = 1
    map(3)(2) = 1

    //输出地图
    for (i <- map.indices) {
      for (j <- map(i).indices) {
        print(s"${map(i)(j)}\t")
      }
      println()
    }

    //使用递归回溯给小球找路
    setWay(map, 1, 1)

    //输出新的地图,小球走过,并标识过的递归
    println("======小球走过,并标识过的地图======")
    for (i <- map.indices) {
      for (j <- map(i).indices) {
        print(s"${map(i)(j)}\t")
      }
      println()
    }
  }

方法

使用递归回溯来给小球找路

说明:

  1. map表示地图
  2. i,j表示从那个位置开始(1,1)
  3. 如果小球能到map[6,5]则表示小球通路找到
  4. 约定:当map[i,j]
    为 0 表示该点没有走过
    为 1 表示墙
    为 2 表示通路可以走
    为 3 表示该点已经走过,但是走不通
  5. 在走迷宫时,需要确定一个策略(方法) 下=>右=>上=>左 // 如果该点走不通,再回溯
  /**
   *
   * @param map 地图
   * @param i   从哪个位置开始找
   * @param j   从哪个位置开始找
   * @return 如果找到通路,就返回true,否则返回false
   */
  def setWay(map: Array[Array[Int]], i: Int, j: Int): Boolean = {
    if (map(6)(5) == 2) true //通路已经找到
    else {
      if (map(i)(j) == 0) { //如果当前这个点还没有走过
        //按照策略 下=>右=>上=>左 走
        map(i)(j) = 2 //假定该点可以走通
        map(i)(j) match {
          case _ if setWay(map, i + 1, j) => true //向下走
          case _ if setWay(map, i, j + 1) => true //向右走
          case _ if setWay(map, i - 1, j) => true //向上走
          case _ if setWay(map, i, j - 1) => true //向左走
          case _ => { //说明该点走不通,是死路
            map(i)(j) = 3
            false
          }
        }
      } else { //如果map(i)(j) != 0,可能是1,2,3
        false
      }
    }
  }

在这里插入图片描述

最短路径

说明:
1、小球得到的路径,和设置的找路策略有关。即 找路的上下左右顺序有关。
2、修改找路的策略,改成 上=>右=>下=>左
3、那么得到最短路径,我们可以把所有的策略用数组的方式表示出来,把每一个策略得到的节点进行统计,最少的集合就是最短的路径。

2.2 八皇后问题(回溯问题)

问题介绍:

在 8 × 8 格的国际象棋上摆放8个皇后,使其不能互相攻击,即:任意两个皇后都不能处于同一行、同一列或者统一斜线上,问有多少种摆法。

思路分析:

1、第一个皇后先放第一行第一列
2、第二个皇后放在第二行第一列、然后判断是否ok,如果不ok,继续放在第二列、第三列、依次把所有列都放完,找到一个合适
3、继续第三个皇后,第一列、第二列……直到第8个皇后也能放在一个不冲突的位置
4、得到一个正确解时,在栈回退到上一个栈时,就会开始回溯,即将第一个皇后,放到第一列的所有正确解,全部得到。
5、然后回头继续第一个皇后放第二列,继续循环执行1,2,3步骤
【说明】理论上应该创建一个二维数组来表示棋盘,但是实际上用一个一维数组即可解决问题。

输出皇后摆放位置

  //写一个方法,可以将皇后摆放的位置输出
  def print(): Unit = {
    for (i <- array.indices) {
      printf(s"${array(i)}\t")
    }
    println()
  }

判断皇后是否和之前的冲突

//查看当我们放置第n个皇后,就去检测该皇后是否和前面已经摆放的皇后冲突
  /**
   *
   * @param n 表示第n个皇后
   * @return
   */
  def judge(n: Int): Boolean = {
    for (i <- 0 until n) {
      //说明
      //1. array(n) == array(i) 表示判断 第n个皇后是否和前面的n-1个皇后在同一列
      //2. Math.abs(n - i) == Math.abs(array(n) - array(i)) 表示判断第n个皇后是否和第i皇后在同意斜线
      //3. 判断是否在同一行,没有必要,n每次都在递增
      if (array(n) == array(i) || Math.abs(n - i) == Math.abs(array(n) - array(i)))
        return false
    }
     true
  }

放置第n个皇后

//编写一个方法,放置第n个皇后
  //注意:check 是 每一次递归时,进入到check中都有 for (i <- 0 until  max)
  def check(n: Int): Unit = {
    if (n == max) { //n=8,8个皇后已经放好
      count += 1
      print()
      return
    }
    //依次放入皇后,并判断是否冲突
    for (i <- 0 until max) {
      //先把当前皇后n放到该行的第1列
      array(n) = i
      //判断是否冲突
      if (judge(n)) {
        check(n + 1) //不冲突,开始递归
        //如果冲突,就继续执行arr(n)=i,即将第n个皇后 放置在本行的后移的一个位置
      }
    }
  }

主函数

  //定义一个max表示共有多少个皇后
  val max = 8
  //定义数组array,保存皇后放置位置的结果,比如 arr={0,4,7,5,2,6,1,3}
  val array: Array[Int] = new Array[Int](max)
  var count = 0

  def main(args: Array[String]): Unit = {
    check(0)
    println(s"一共有 ${count} 种解法")
  }

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1019891.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

软件测试技术之地图导航的测试用例

外观测试 屏幕显示不能有花屏、黑点和闪屏&#xff0c;清晰度、亮度、颜色要正常。 检测所有按键都能起到相应作用&#xff0c;是否手感不良。 UI显示状态、颜色、清晰度、效果。 控制&#xff1a;放大&#xff0c;缩小&#xff0c;音量调节功能测试。 交叉路口查询测试&am…

无涯教程-JavaScript - MULTINOMIAL函数

描述 MULTINOMIAL函数返回值之和的阶乘与阶乘积之比。 语法 MULTINOMIAL (number1, [number2] ...)争论 Argument描述Required/OptionalNumber11 to 255 values for which you want the multinomial.Requirednumber2, ...Optional Notes 多项式为- $$MULTINOMIAL\left(a_…

插件化原理

插件化技术和热修复技术都属于动态加载&#xff0c;从普及率的角度来看&#xff0c;插件化技术还没有热修复的普及率高&#xff0c;主要原因是占大多数的中小型应用很少也没有必要去采用插件化技术。 Android P preview&#xff08;Android 9&#xff09;开始限制调用隐藏 API…

在qml中将一个16进制表示的颜色加上透明度

在qml中&#xff0c;我们在指定控件的颜色时&#xff0c;可以直接通过16进制的字符串来表示&#xff0c;比如"#ff0000"; 这种方式也比较符合UI设计人员的使用习惯。 但是假如要在此颜色的基础上&#xff0c;加个透明度的话&#xff0c;就要重新计算一番&#xff0c;比…

Nginx学习记录一揽子:学会配置Nginx

前言 在配置我的网站的过程中&#xff0c;深觉自己功力尚浅&#xff0c;不由黯然伤神&#xff0c;遂有奋进之意&#xff0c;针对这个过程中的不自然优雅的操作&#xff0c;得加强学习。在配置整个虚拟网络的过程中&#xff0c;由于对Nginx的了解不深&#xff0c;使用起来也捉襟…

LeetCode 周赛上分之旅 #46 经典二分答案与质因数分解

⭐️ 本文已收录到 AndroidFamily&#xff0c;技术和职场问题&#xff0c;请关注公众号 [彭旭锐] 和 BaguTree Pro 知识星球提问。 学习数据结构与算法的关键在于掌握问题背后的算法思维框架&#xff0c;你的思考越抽象&#xff0c;它能覆盖的问题域就越广&#xff0c;理解难度…

C++ 算法学习 之 string find

这里写目录标题 String的查找方法 find使用&#xff1a;返回值&#xff1a;输出结果 更多string方法 参考于 c手册 String的查找方法 find 使用&#xff1a; std::string str ("There are two needles in this haystack with needles."); std::string str2 ("…

Pytorch搭建循环神经网络RNN(简单实战)

Pytorch搭建循环神经网络RNN&#xff08;简单实战&#xff09; 去年写了篇《循环神经网络》,里面主要介绍了循环神经网络的结构与Tensorflow实现。而本篇博客主要介绍基于Pytorch搭建RNN。 通过Sin预测Cos import torch import torch.nn as nn import numpy as np from matp…

医学影像相关开源数据集资源汇总

CT 医学图像 下载链接&#xff1a;http://suo.nz/2tQehH 该数据集旨在允许测试不同的方法来检查与使用对比度和患者年龄相关的 CT 图像数据的趋势。基本思想是识别与这些特征密切相关的图像纹理、统计模式和特征&#xff0c;并可能构建简单的工具&#xff0c;在这些图像被错误…

MyEclipse项目导入与导出

一、项目导出 1、右键选择项目名称&#xff0c;弹出菜单中选择“export”&#xff0c;如下图所示 2、选择“恶心“export”&#xff0c;弹出菜单如下&#xff1b;在“General“选项中&#xff0c;选择“File System”选项 3、点击“next”&#xff0c;进入保存位置选择界面&am…

异步FIFO设计的仿真与综合技术(5)

概述 本文主体翻译自C. E. Cummings and S. Design, “Simulation and Synthesis Techniques for Asynchronous FIFO Design 一文&#xff0c;添加了笔者的个人理解与注释&#xff0c;文中蓝色部分为笔者注或意译。前文链接&#xff1a; 异步FIFO设计的仿真与综合技术&#xf…

小目标检测高效解决方案汇总,附19篇原论文&开源代码

目标检测发展至今&#xff0c;涌现出了许多非常实用的方法&#xff0c;但在小目标检测领域&#xff0c; 由于小目标经常存在图片模糊、信息少、分辨率低等问题&#xff0c;性能水平仍然难以提升。 不过在近几年间&#xff0c;已经有许多有效的解决方法被提出&#xff0c;我今天…

前端录入音频并上传

目录 纯 js 实现&#xff08;有问题&#xff09;使用插件 recorder-core &#xff08;没问题&#xff09; 纯 js 实现&#xff08;有问题&#xff09; 上传音频文件时 blob 数据中 size 一直是0&#xff0c;导致上传之后音频不可播放&#xff08;本地录制后本地是可以播放的&am…

什么是CORS(跨源资源共享)?如何解决前端中的CORS问题?

聚沙成塔每天进步一点点 ⭐ 专栏简介⭐ CORS&#xff08;跨源资源共享&#xff09;⭐ 解决前端中的CORS问题的方法⭐ 写在最后 ⭐ 专栏简介 前端入门之旅&#xff1a;探索Web开发的奇妙世界 欢迎来到前端入门之旅&#xff01;感兴趣的可以订阅本专栏哦&#xff01;这个专栏是为…

【前端知识】Three 学习日志(三)—— 光源对物体表面的影响

Three 学习日志&#xff08;三&#xff09;—— 光源对物体表面的影响 一、设置材质为受光照影响 //MeshLambertMaterial受光照影响 const material new THREE.MeshLambertMaterial();此时&#xff0c;场景中一片漆黑&#xff0c;无法看到原来的物体&#xff0c;需要设置光源…

24v转5v稳压芯片-5A大电流输出ic

这款24V转5V5A汽车充电芯片具有以下特性和参数&#xff1a; - 宽输入电压范围&#xff1a;4.5V至36V - 最大输出电流&#xff1a;5.0A - 高达92%的转换效率 - 恒流/恒压模式控制 - 最大占空比100% - 可调输出电压 - 2%的输出电压精度 - 集成40mΩ高侧开关 - 集成18mΩ低侧开关 …

网络安全深入学习第六课——热门框架漏洞(RCE— Weblogic反序列化漏洞)

文章目录 一、Weblogic介绍二、Weblogic反序列化漏洞历史三、Weblogic框架特征1、404界面2、登录界面 四、weblogic常用弱口令账号密码五、Weblogic漏洞介绍六、Weblogic漏洞手工复现1、获取账号密码&#xff0c;这是一个任意文件读取的漏洞1&#xff09;读取SerializedSystemI…

K8s(Kubernetes)学习(六)——Ingress

第六章 Ingress 什么是 IngressIngress 和 Service 区别Ingress 控制器 Traefik 使用Ingress Route的定义 1 简介 https://kubernetes.io/zh-cn/docs/concepts/services-networking/ingress/ Ingress 是一种 Kubernetes 资源类型&#xff0c;它允许在 Kubernetes 集群中暴露…

浏览器报错内容:Provisional headers are shown

浏览器报错内容&#xff1a;Provisional headers are shown 如下图&#xff1a; 解决方法&#xff1a;nginx 443 启用HTTP/2模式&#xff0c;如下图&#xff1a; server {listen 443 ssl http2;server_name callcenterda.umworks.com;client_max_body_size 200M;ssl_session_…

Idea注释相关配置模板

设置-编辑器-实时模板。 这里可以自己建立一个文件夹&#xff0c;建立自己的模板 1、普通多行注释 2、方法注释 我的方法注释模板文本&#xff1a; ** *$param$$return$ **/ 点击编辑变量&#xff1a; 两个默认值分别为&#xff1a; groovyScript("if(\"${…