递归的概念

程序调用自身的编程技巧称为递归( recursion)。递归做为一种算法在程序设计语言中广泛应用。 一个过程或函数在其定义或说明中有直接或间接调用自身的一种方法,它通常把一个大型复杂的问题层层转化为一个与原问题相似的规模较小的问题来求解,递归策略只需少量的程序就可描述出解题过程所需要的多次重复计算,大大地减少了程序的代码量。

我会写先介绍递归的基本思想,然后再以后的文章中介绍一下递归的衍生算法,比如:回溯算法、分治法、DFS等。

设计递归的思路

通常我们一提到递归就立马想到了递归的两个重要部分:终止条件与循环部分。递归的设计思路是很像我门做数学题:根据已知条件找规律,利用递推式求解未知变量。但是我们作为开发者面对的是计算机,我们需要用程序语言设计出递归的算法去解决问题。下面是递归设计的四个重要要素:

  1. 接收的参数
  2. 返回值
  3. 终止条件
  4. 递归拆解:如何递归下一层

递归实例

俗话说的好:”孰能生巧“,光说不练,假把式。光用文字去解释递归如何如何让地去设计,倒不如多花时间从易到难循序渐进做大量练习,通过大量的练习,去寻找其中的规律。

实例1:n的阶乘

# 递归实现N的阶乘
def fact_resursion(n):# 终止条件if n==1:return 1else:return n*fact_resursion(n-1) # 循环部分print(fact_resursion(5))

运行结果:120

实例2:斐波那契数列

这里简单的解释一下斐波那契数列:F(0) = 0 , F(1) = 1
F(N) = F(N-1) + F(N-2) , N>1 数列前几项如下:
0 1 1 2 3 5 8 13 …

# 递归实现斐波那契数列F(N)的计算
def fun(n):# 终止条件if n <=1:return nelse:return fun(n-1) + fun(n-2) # 循环部分
print(fun(8))

运行结果:21

实例3:小青蛙跳台阶

一只青蛙一次可以跳上1级台阶,也可以跳上2级。求该青蛙跳上一个n级的台阶总共有多少种跳法。

解析:
每次跳的时候,小青蛙可以跳一个台阶,也可以跳两个台阶,也就是说,每次跳的时候,小青蛙有两种跳法。
第一种跳法:第一次我跳了一个台阶,那么还剩下n-1个台阶还没跳,剩下的n-1个台阶的跳法有f(n-1)种。

第二种跳法:第一次跳了两个台阶,那么还剩下n-2个台阶还没,剩下的n-2个台阶的跳法有f(n-2)种。

所以,小青蛙的全部跳法就是这两种跳法之和了,即 f(n) = f(n-1) + f(n-2)。至此,等价关系式就求出来了。

def func(n):if n<=2:return nreturn func(n-1) + func(n-2)
print(func(4))

运行结果:5

实例3:列表反转

# 递归实现列表反转
def rev(alist,left,right):if left >= right: # 终止条件returnrev(alist,left+1,right-1)# 循环部分alist[left],alist[right] = alist[right],alist[left]
alist = [1,2,3,4,5,6]
left = 0
right = len(alist) - 1
rev(alist,left,right)
print(alist)

运行结果:[6, 5, 4, 3, 2, 1]

实例4:字符串反转

注意:有人可能会觉得字符串反转和列表反转难道不是一样的吗?
如果用反转列表的方法去反转字符串会出现一下错误:

TypeError: ‘str’ object does not support item assignment

在python中,字符串是不可变对象,不能通过下标的方式直接赋值修改。同样的不可变对象还有:数字、字符串和元组。

直观一点举个小例子:
s = “abcd”
x = s[2]
print(x) => ‘c’

但是直接赋值:s[2] = ‘h’ 却会报错

# 递归实现字符串的反转
def rvs(s):# 终止条件if len(s) == 1:return selse:return rvs(s[1:])+s[0]  # 循环部分
print(rvs("abcdefg"))

运行结果:gfedcba

实例5:链表反转

注意:因为实现链表反转需要自己创建一个链表类和方法,比较麻烦我们就直接用leetcode的206题:链表反转。

代码:

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:def reverseList(self, head: ListNode) -> ListNode:# 方法一:双指针# pre,cur = None,head# while cur:#     next = cur.next#     cur.next = pre#     pre = cur#     cur = next# return pre# 方法二: 递归# 边界条件   和    终止条件if head == None or head.next == None:return head# 循环部分 newhead = self.reverseList(head.next)head.next.next = headhead.next = Nonereturn newhead

实例6:汉诺塔游戏

汉诺塔问题是一个经典的问题。汉诺塔(Hanoi Tower),又称河内塔,源于印度一个古老传说。大梵天创造世界的时候做了三根金刚石柱子,在一根柱子上从下往上按照大小顺序摞着64片黄金圆盘。大梵天命令婆罗门把圆盘从下面开始按大小顺序重新摆放在另一根柱子上。并且规定,任何时候,在小圆盘上都不能放大圆盘,且在三根柱子之间一次只能移动一个圆盘。问应该如何操作?

假设三根柱子分别为:A,B,C。A柱子上有n个盘子,B,C为空。请问每一步该如何移动?

# 汉诺塔
count = 1
n = 4
def move(n,a,b,c):global countif n == 1:print(count,":",a, '-->', c)count += 1else:move(n-1, a, c, b)print(count,":",a, '-->', c)count += 1move(n-1, b, a, c)
print(f'把A柱子的{n}个盘子全部移到C柱子的顺序为:')
move(n, 'A', 'B', 'C')

运行结果:
把把A柱子的4个盘子全部移到C柱子的顺序为:
1 : A --> B
2 : A --> C
3 : B --> C
4 : A --> B
5 : C --> A
6 : C --> B
7 : A --> B
8 : A --> C
9 : B --> C
10 : B --> A
11 : C --> A
12 : B --> C
13 : A --> B
14 : A --> C
15 : B --> C

例子7:科赫雪花

利用python的turtle库绘制科赫雪花,如下图所示:

# 科赫雪花
# -*- coding: utf-8 -*-
import turtle
def koch(size,n):"""函数koch用递归思想绘制一段N阶曲线"""if n == 0:turtle.fd(size)     #递归基例(终止条件),0阶曲线即为一条直线else:for i in [0,60,-120,60]:    #通过改变方向,绘制四条线段turtle.left(i)koch(size/3,n-1)   # 循环部分
def main():"""定义main函数调用koch""" turtle.setup(600,600)turtle.penup()turtle.goto(-250,100)turtle.pendown()turtle.pensize(2)n = 3for i in range(0,3):koch(500,n)turtle.right(120)turtle.hideturtle()turtle.done()
main()

运行结果:

递归算法(一)递归概念与思路相关推荐

  1. XDOJ 363 输出快速排序递归算法隐含递归树的后序遍历序列 AC

    像我这样的菜鸡也没有什么能输出的,好像我写题解也不算输出. 最近期末了,写数据结构实验的时候,这个题写了挺久的,搞出来记录一下. 输出快速排序递归算法隐含递归树的后序遍历序列 描述: 快速排序递归算法 ...

  2. 算法笔记-递归算法、递归排序、递归的时间复杂度、master公式(也叫主方法)

    1. 递归排序题 通过递归算法来获取一个数组中的最大值 2. 算法思路 采用递归的思路来进行解题,那么肯定是需要自己调用自己的,这也就是递归,于是考虑怎么自己调用自己呢?我们可以采用二分法来制造递归的 ...

  3. [递归]递归问题解题思路

    递归解题三部曲 何为递归?程序反复调用自身即是递归. 我自己在刚开始解决递归问题的时候,总是会去纠结这一层函数做了什么,它调用自身后的下一层函数又做了什么-然后就会觉得实现一个递归解法十分复杂,根本就 ...

  4. 二叉树非递归dfs——简单思路搞定前中后序遍历

    前言:相信很多同学都被二叉树非递归dfs的前中后序遍历方法弄的头疼.网上的答案,什么前中后序遍历各有一套写法,还有什么一个栈的写法,两个栈的写法.看起来能理解,一闭眼自己写都记不住.今天介绍一种用一种 ...

  5. 系统权限设计 - 基本概念和思路

    点击上方"xy的技术圈",选择"设为星标" 认真写文章,用心做分享. 微信公众号:xy的技术圈 个人网站:yasinshaw.com 正文 权限系统的设计几乎是 ...

  6. java全排列算法 递归算法_Java递归实现全排列

    最近整理之前自己学习Java时的一些代码笔记,可能都是一些比较基础的Java知识,在这里只是给需要的人参考一下. 递归算法:将数据分为两部分,递归将数据从左侧移右侧实现全排列 package inte ...

  7. java中的递归算法_java递归实现

    二话不说,先上代码 Java代码 publicclassTestRecursion{ //递归方法 publicstaticvoidfun(inti){ if(i >0){ i--; fun(i ...

  8. php无限极递归概念,php无限极分类递归与普通

    1. 递归 public function getInfo(){ $data=$this->select(); $arr=$this->noLimit($data,$f_id=0,$lev ...

  9. 算法设计与分析递归概念之阶乘函数

    阶乘函数可递归地定义为: 其中: n=0 时,n!=1为边界条件 n>0 时,n!=n(n-1)!为递归方程 边界条件与递归方程是递归函数的二个要素,递归函数只有具备了这两个要素,才能在有限次计 ...

最新文章

  1. java 关键字final static
  2. 总结 贪心算法_这几道经典例题帮你轻松搞透贪心算法
  3. 【安全漏洞】黑客利用IE 0 day漏洞部署VBA恶意软件
  4. python记录程序运行时间的几种方法
  5. c语言游戏编程网盘下载,C语言游戏编程 计算器(5分下载)
  6. 前端学习(1267):axios的post传参
  7. 单点登录的原理与简单实现
  8. 【Linuxamp;Unix--open/close/write/read系统调用】
  9. linux网络子系统研究:数据收发简略流程图
  10. [BJWC2011]元素
  11. 【干货分享】数字营销与企业数字化转型.pdf(附下载链接)
  12. Tik Tok与抖音的不同有哪些
  13. CODESYS Visualization
  14. Android 10 深色模式适配
  15. Flask 创建app 时候传入的 static_folder 和 static_url_path参数理解(1ni)
  16. 开发一款桌面程序。文件转换器
  17. stm32 u8g2移植笔记
  18. ReID:常用损失函数总结
  19. 根据列名提取指定列 shell awk
  20. c++ 之动态库与静态库区别

热门文章

  1. 年月跨度_建筑结构丨国内跨度最大的张弦桁架工程——合肥滨湖国际会展中心二期首榀桁架滑移成功...
  2. mysql丢失链接_MySQL远程连接丢失问题解决方法
  3. 机械史上最复杂的巅峰之作,这才是最强大脑!
  4. 凭自己本事单的身是一种怎样的体验?你根本配不上如此优秀的我!
  5. php 版本排序,四种常见排序算法--PHP版本
  6. mysql添加字段时定义候选键_MySQL 表约束
  7. latex 1图加标题_使用VsCode编译latex心得
  8. 服务器精益改善系列,精益生产改善的内容是什么?
  9. ppt扇形图怎么显示数据_前方高能!多维数据分析的神器雷达图PPT制作教程来啦!...
  10. linux新建文件夹明率,linux新建文件和文件夹命令