递归算法

蒙娜丽莎之美——递归

送分小仙女□ 提交于 2019-12-28 19:43:26
递归是一种重要的算法思想,其实现的“简洁性”通常会让人赞美,但不加修饰的递归通常会带来栈空间的爆炸。然而,这并不阻挡人们对递归的探索。 这位作者给出了递归一些典型的案例:https://mp.weixin.qq.com/s/mJ_jZZoak7uhItNgnfmZvQ 这里面讲到了递归的三要素,以及递归的改进,让人折服。 最后,我仅仅想总结一下对于个人对于递归的一些浅显的认识:什么样的问题可以递归? 往往别人对于一个问题,可以想出递归,为何我们想不出来呢?因为我们没有认识问题的本质,而对于递归的问题,则由两个共性,这两点是十分重要的: 1. 凡是问题规模可以缩小,但问题本身并没与变化的问题,均可采用递归(例如阶乘,例如求和,例如斐波那契数列....都有这样的特性) 2. 凡是用递归可以解决的问题,一定存在其他办法,比如 递推。(原因在于递归是一种有规律的自上而下的结构,这种结构一定存在某种数学解析与之对应,或者存在一种自下而上的方式与之对应) 来源: https://www.cnblogs.com/shaonianpi/p/11000327.html

双色汉诺塔 算法 (递归)

十年热恋 提交于 2019-12-28 19:42:09
#include<stdio.h> //将n个盘子A->C借助B void move(int n,char a,char b,char c) { if(n==1) { printf("%c->%c\n",a,c); printf("%c->%c\n",a,c); } else { move(n-1,a,c,b); printf("%c->%c\n",a,c); printf("%c->%c\n",a,c); move(n-1,b,a,c); } } //根据颜色移动 void ColorTwoMove(int n,char a,char b,char c) { int i=n/2; //分两组,因为只是颜色不同,一次移动两个。 for(;i>1;i--) //下面主要是把两个颜色不一样,大小一样的分开放在两个柱子上。 { move(i-1,a,c,b); //将2*(i-1)个A->B借助C move(1,a,b,c); //将A上剩下的两个移动到C上 move(i-1,b,c,a); //将B上的2*(i-1)个 B->A借助C printf("%c->%c\n",c,b); //C上面现在是两个颜色不一样大小一样的盘子,将其中的1个C->B } //下面是最上面的两个的两个大小一样,颜色不一的最小的盘子 printf("%c->%c\n",a,c); //将第一个移动到C上

python的递归

大兔子大兔子 提交于 2019-12-28 14:28:12
递归算法是一种直接或者间接的调用自身算法的过程。 特点: 1.递归就是在过程或者函数里调用自身。 2.在使用递归策略时,必须有一个明确的递归条件,称为递归出口。 3.递归算法解题通常显得很简洁,但递归算法解题的效率较低。所以一般不倡导使用递归算法设计程序。 4.在递归调用的过程当中系统的每一层的返回点、局部变量等开辟了栈来存储。递归函数次数过多容易造成栈溢出等。 要求: 递归算法所体现的"重复"一般有三个条件: 1.每次在调用规模上都有所缩小(通常是减半)。 2.相邻两次重复之间有紧密的联系,前一次要为后一次做准备(通常前一次的输出就作为后一次的输入)。 3.在问题的规模极小时必须用直接接触解答而不再进行递归调用,因而每次递归调用都是有条件的(以规模未达到直接解答的大小为条件),无条件的递归调用将会成为死循环而不能正常结束。 简而言之,能用循环写的就别用递归 用循环写费脑子 用递归写费内存 还是费脑子好点 斐波那契数列 循环解法 1 def Fib(n): 2 fib = [1,1] 3 if n == 1: 4 return [1] 5 elif n == 2: 6 return [1, 1] 7 elif n > 2 : 8 for i in range(2,n): 9 fib.append(fib[i-2]+fib[i-1]) 10 else: 11 return [] 12

汉诺塔问题笔记(Java实现)

蹲街弑〆低调 提交于 2019-12-28 12:04:25
汉诺塔问题笔记(Java实现) 前言 这两天在B站跟着小甲鱼学习递归的时候遇到了汉诺塔问题,乍一听没想明白,动手画了画才明白过来,因为本人递归学的不太好,为了加深印象,也为了验证自己是否真的明白了,决定写一个笔记记录一下。 B站小甲鱼传送门: 小甲鱼讲解数据结构和算法 p34 汉诺塔问题 问题描述 汉诺塔(又称河内塔)问题是源于印度一个古老传说的益智玩具。大梵天创造世界的时候做了三根金刚石柱子,在一根柱子上从下往上按照大小顺序摞着64片黄金圆盘。大梵天命令婆罗门把圆盘从下面开始按大小顺序重新摆放在另一根柱子上。并且规定,在小圆盘上不能放大圆盘,在三根柱子之间一次只能移动一个圆盘。(来自百度百科) 现在抛开问题的背景,汉诺塔问题可以简单描述如下: 初始状态:有三根柱子,其中第一根柱子上堆放着任意数量(n)的圆盘,另外两根是空柱子。 圆盘在任意柱子上的摆放遵循以下原则:在上方的圆盘半径不能超过其下方的圆盘半径。(这里为了简化问题,可以给所有的圆盘编号,最大的圆盘编号最大 n,最小的圆盘编号最小 1,那么也就是说在任意一根柱子上,圆盘的编号必须从下往上依次减小) 目标:将所有的圆盘从一开始的柱子移动到第三根柱子上,在移动过程中和结束状态下圆盘的摆放都必须遵循 2 中的原则。 要求:列出完成目标所需要的所有步骤。 解析 汉诺塔问题是递归中的经典问题,这里也只介绍一下递归的解法。(以下的 n

TTreeView完整的枚举和递归算法

我只是一个虾纸丫 提交于 2019-12-28 09:11:53
TTreeView完整的枚举和递归算法 一、TTreeView (一)、重要属性 Memo_Test.Lines.Add( ‘TTreeView重要属性:’ +', 1、可见数: '+IntToStr((LAddObject as TTreeViewItem ). VisibleCount ) //:该节点所有展开的下级总数 +', 2、Item个数: '+IntToStr((LAddObject as TTreeViewItem). Count ) //:该节点所有下级总数>=0,末级Count=0 +', 3、几级: '+IntToStr((LAddObject as TTreeViewItem). Level ) //:该节点的级数:级数>=1 +', 4、全局索引: '+IntToStr((LAddObject as TTreeViewItem). GlobalIndex ) //:该节点所有展开的下级的重新的自动索引(作用不大) ); 5、该节点的父节点: (LAddObject as TTreeViewItem). ParentItem 6、该节点被勾选IsChecked: if (LAddObject as TTreeViewItem).IsChecked=True then ; 7、该节点是否展开其下级、展开或收拢其下级: if FTreeViewItemCurrt

快速排序算法原理及实现(单轴快速排序、三向切分快速排序、双轴快速排序)

情到浓时终转凉″ 提交于 2019-12-28 04:10:46
1. 工作原理(定义)   快速排序(Quicksort)是对冒泡排序的一种改进。(分治法策略)   快速排序的基本思想是在待排序的n个记录中任取一个记录(通常取第一个记录)作为基准,把该记录放入适当位置后,数据序列被此记录划分成两部分,分别是比基准小和比基准大的记录;然后再对基准两边的序列用同样的策略,分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。    2. 算法步骤   实现方法两种方法:挖坑法和指针交换法   基准的选择三种方法:1.选择最左边记录 2.随机选择 3.选择平均值 2.1 挖坑法 设置两个变量i、j,排序开始的时候:i=0,j=N-1; 以第一个数组元素作为关键数据,赋值给key,即key=A[0]; 从j开始向前搜索,即由后开始向前搜索(j--),找到第一个小于key的值A[j],将A[j]和A[i]的值交换; 从i开始向后搜索,即由前开始向后搜索(i++),找到第一个大于key的A[i],将A[i]和A[j]的值交换; 重复第3、4步,直到i=j;   【3,4步中,没找到符合条件的值,即3中A[j]不小于key,4中A[i]不大于key的时候改变j、i的值,使得j=j-1,i=i+1,直至找到为止。找到符合条件的值,进行交换的时候i, j指针位置不变。另外,i==j这一过程一定正好是i+或j-完成的时候,此时令循环结束】。

排序 之 堆排序 归并排序

陌路散爱 提交于 2019-12-28 04:05:01
堆的概念 堆是具有下列性质的完全二叉树:每个节点的值都大于或等于其左右孩子结点的值,称为大顶堆;或着每个结点的值都小于或等于其左右孩子结点的值,称为小顶堆。 堆排序 堆排序(Heap Sort)就是利用堆(假设利用大顶堆)进行排序的方法。它的基本思想是,将待排序的序列构造成一个大顶堆。此时,整个序列的最大值就是对顶的根结点。将它移走(其实就是将其与堆数组的末尾元素交换,此时末尾元素就是最大值),然后将剩余的n-1个序列重新构造成一个堆,这样就会得到n个元素中的次大值。如此反复执行,就可以得到一个有序序列了。 有上述思想可知,堆排序的两个要点: 1.如何由一个无序序列构建成一个堆? 2.如何在输出堆顶元素后,调整剩余元素称为一个新的堆? /* 堆排序********************************** */ /* 已知L->r[s..m]中记录的关键字除L->r[s]之外均满足堆的定义, */ /* 本函数调整L->r[s]的关键字,使L->r[s..m]成为一个大顶堆 */ void HeapAdjust(SqList *L,int s,int m) { int temp,j; temp=L->r[s]; for(j=2*s;j<=m;j*=2) /* 沿关键字较大的孩子结点向下筛选 */ { if(j<m && L->r[j]<L->r[j+1]) ++j; /*

数据结构与算法之PHP排序算法(快速排序)

|▌冷眼眸甩不掉的悲伤 提交于 2019-12-28 03:47:08
一、基本思想 快速排序又称划分交换排序,是对冒泡排序的一种改进,亦是分而治之思想在排序算法上的典型应用。 它的基本思想是:通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列的目的。 二、算法过程 1)从数列中挑出一个元素,称为“基准值”; 2)将待排序元素进行分区,比基准值小的元素放在基准值前面,比基准值大的元素放在基准值后面。分区结束后,该基准值就处于数组的中间位置; 3)对左右两个分区重复以上步骤直到所有元素都是有序的。 三、算法图解及PHP代码实现 1、替换版 上图只给出了第1趟快速排序的流程。在第1趟排序中,设置pivot=arr[i],即pivot=3。 1) 右 → 左 查找小于pivot的数:找到满足条件的数arr[j]=2,此时j=4;然后将a[j]赋值a[i],此时i=0;接着从左往右遍历。 2) 左 → 右 查找大于pivot的数:找到满足条件的数arr[i]=4,此时i=1;然后将a[i]赋值a[j],此时j=4;接着从右往左遍历。 3) 右 → 左 查找小于pivot的数:找到满足条件的数arr[j]=1,此时j=3;然后将a[j]赋值a[i],此时i=1;接着从左往右遍历。 4) 左 → 右

02.python实现排序算法

若如初见. 提交于 2019-12-28 03:46:10
一、列表排序   将无序列表变为有序列表   应用场景: 榜单,表格, 给二分查找用,给其他算法用 二、python实现三种简单排序算法 时间复杂度O(n^2), 空间O(1) 1、冒泡排序 思路:   列表每两个相邻的数,如果前面的比后面的大,那么交换这两个数 代码实现: # 冒泡排序 @cal_time # 测试执行时间 def bubble_sort(li): for i in range(len(li)-1): # i表示第i趟 # 第i趟无序区位置【0,n-i-1】 for j in range(len(li)-i-1): if li[j] > li[j+1]: li[j], li[j+1] = li[j+1], li[j] # 最好情况 O(n^2) # 平均情况 O(n^2) # 最坏情况 O(n^2) # 优化改进>>> # 思路:如果冒泡排序中执行一趟而没有交换,则列表已经是有序状态,可以直接结束算法。 @cal_time def bubble_sort2(li): for i in range(len(li)): # 表示第i趟 exchange = 0 # 第i趟无序区的位置【0,n-i-1】 n是列表长度 for j in range(len(li)-i-1): if li[j] > li[j+1]: li[j], li[j+1] = li[j+1], li

递归算法

泄露秘密 提交于 2019-12-27 21:52:33
一、递归的核心思想就是自己调用自己,一般来说能够用递归解决的问题应满足3个条件: 1.需要解决的问题可以转化为一个或多个子问题来求解,而这些子问题的求解方法与原问题完全相同,只是在数量和规模上不同。 2.递归调用的次数必须是有限的。 3.必须有结束递归的条件来终止递归。 二、何时使用递归? 1.定义是递归的 有许多数学公式、数列和概念的定义是递归的。比如求n!,Fibonacci数列等。这些问题的求解过程是可以将其递归定义直接转化为对应的递归算法的。 比如求 n! int fun(int n) { if(n==1) { //递归头 return(1); } else { //递归体 return (fun(n-1)*n); } } 2.有些数据结构是递归的 单链表就是一种递归数据结构,其结点类型定义如下: typedef struct LNode { ElemType data; struct LNode *next; }LinkList; 求一个不带头结点的单链表L所有的data域(假设为int类型)之和的递归算法如下: int Sum(LinkList *L) { if (L == NULL) { return 0; } else { return(L->data+sum(L->next)); } } 3.问题的求解方法是递归的 比如汉诺塔问题: 三、递归的不足