递归算法与递归程序#
- 格式:doc
- 大小:488.50 KB
- 文档页数:19
1 如果 n=0,n=1f(n)=nf(n) 如果 n>1图1:以递归的方式计算4的阶乘上图(1)展示了利用递归计算4!的过程。
它也说明了递归过程中的两个基本阶段:递推和回归。
在递推阶段,每一个递归调用通过进一步调用自己来记住这次递归过程。
当其中有调用满足终止条件时,递推结束。
比如,在计算n!时,终止条件是当n=1和n=0,此时函数只需简单的返回1即可。
每一个递归函数都必须拥有至少一个终止条件;否则递推阶段永远不会结束了。
一旦递推阶段结束,处理过程就进入回归阶段,在这之前的函数调用以逆序的方式回归,直到最初调用的函数为止,此时递归过程结束。
以递归的方式计算n的阶乘的函数实现:C函数fact的工作方式如下:它接受一个整数n作为参数,如果n小于0,该函数直接返回0,这代表一个错误。
如果n等于0或1,该函数返回1,这是因为0!和1!都等于1,以上是终止递归的条件。
否则,函数返回n-1的阶乘的n倍。
而n-1的阶乘又会以递归的方式再次调用fact来计算,如此继续。
代码实例(1):fact.c1/*fact.c*/2#include "fact.h"3int fact(int n){4if (n<0)5return0;6else if(n==0)7return1;8else if(n==1)9return1;10else11return n*f(n-1);12}为理解递归究竟是如何工作的,有必要先看看C语言中函数的执行方式。
我们先来看看C程序在内存中的组织方式(见图2-a)。
基本上,一个可执行程序由4个区域组成:代码段、静态数据区、堆与栈。
代码段包含程序运行时所执行的机器指令。
静态数据区包含在程序生命周期内一直持久的数据,比如全局变量和静态局部变量。
堆包含程序运行时动态分配的存储空间,比如malloc分配的内存。
栈包含函数调用的信息。
当C中调用了一个函数时,栈中会分配一块空间来保存与这个调用相关的信息。
算法总结之递推与递归递推算法递归算法⼤致包括两⽅⾯的内容:1)递归起点; 2)递归关系递推起点递归起点⼀般由题⽬或者实际情况确定,不由递归关系推出。
如果⽆法确定递归起点,那么递归算法就⽆法实现。
可见,递归起点是递归算法中的重要⼀笔。
递推关系递归关系是递归算法的核⼼。
常见的递归关系有以下⼏项:1)⼀阶递推;2)多阶递推;3)间接递推;4)逆向递推;5)多维递推。
下⾯通过栗⼦来详细介绍⼀下上述类别的递推关系。
1. ⼀阶递推在计算f(i)时,只⽤到前⾯项中的⼀项,如等差数列。
公差为3的等差数列,其递推关系为:f(i)=f(i-1)+3eg. 平⾯上10条直线最多能把平⾯分成⼏部分?分析:以直线数⽬为递推变量,假定i条直线把平⾯最多分成f(i)部分,则f(i-1)表⽰i-1条直线把平⾯分成的最多部分。
在i-1条直线的平⾯上增加直线i,易得i与平⾯上已经存在了的i-1条直线最多各有⼀个交点,即直线i最多被分成i段,⽽这i段将会依次将平⾯⼀分为⼆,即直线i将最多使平⾯多增加i部分。
所以,递推关系可表⽰为:f(i)=f(i-1)+i易得当0条直线时,平⾯为1部分。
所以f(0)=1为递推起点。
上述分析可⽤下⾯代码表⽰(c++):#define MAX 100int f[MAX] //存放f(i)int lines(int n){//输⼊n为直线数⽬//输出最多部分数int i;f(0)=1;for(i=1;i<=n;i++){f[i]=f[i-1]+3;}return f[i];}2. 多阶递推在计算f(i)时,要⽤到前⾯计算过的多项,如Fibonacci数列。
eg.求Fibonacci的第10项。
分析:总所周知,Fibonacci数列中的第n项等于第n-1项加上n-2项。
所以递推关系为f(i)=f(i-1)+f(i-2);且f[0]=f[1]=1。
C++代码如下:#define MAX 100int f[MAX];int fib(int n){//输⼊n为项数//输出第n个fib数int i;f[0]=0;f[1]=1;for(i=2;i<=n;i++){f[i]=f[i-1]+f[i-2];}return f[n]}3. 间接递推在计算f[i]时需要中间量,⽽计算中间量要⽤到之前计算过的项。
数据结构论文——递归算法的讨论所谓递归算法是把问题转化为规模缩小了的同类问题的子问题。
然后递归调用函数(或过程)来表示问题的解。
一个过程(或函数)直接或间接调用自己本身,这种过程(或函数)叫递归过程(或函数)。
递归过程一般通过函数或子过程来实现。
递归方法:在函数或子过程的内部,直接或者间接地调用自己的算法。
递归算法是一种直接或者间接地调用自身算法的过程。
在计算机编写程序中,递归算法对解决一大类问题是十分有效的,它往往使算法的描述简洁而且易于理解。
递归算法解决问题的特点:(1) 递归就是在过程或函数里调用自身。
(2) 在使用递归策略时,必须有一个明确的递归结束条件,称为递归出口。
(3) 递归算法解题通常显得很简洁,但递归算法解题的运行效率较低。
(4) 在递归调用的过程当中系统为每一层的返回点、局部量等开辟了栈来存储。
递归次数过多容易造成栈溢出等。
所以一般不提倡用递归算法设计程序。
下面就让我们结合例子详细讨论一下递归算法。
一、递归算法的原理递归算法简单的说就是在函数中调用函数自身,不断调用,直到满足函数得出计算结果(某个条件)。
因为其需要不断循环的调用自身,所以称为递归调用。
递归的原理,其实就是一个栈(stack), 比如求5的阶乘,要知道5的阶乘,就要知道4的阶乘,4又要是到3的,以此类推,所以递归式就先把5的阶乘表示入栈, 在把4的入栈,直到最后一个,之后呢在从1开始出栈, 看起来很麻烦,确实很麻烦,他的好处就是写起代码来,十分的快,而且代码简洁,其他就没什么好处了,运行效率出奇的慢。
还有一个十分形象的例子:从前有座山,山里有个庙,庙里有个老和尚正在讲故事:从前有座山,山里有个庙,庙里有个老和尚正在讲故事:从前有座山,山里有个庙,庙里有个老和尚正在讲故事……如此循环往复到最终的要求。
递归分为2种,直接递归和间接递归。
直接递归,比如方法A内部调用方法A自身。
间接递归,比如方法A内部调用方法B,方法B内部调用方法C,方法C 内部调用方法A。
C语言常用算法程序汇总C语言是一门广泛应用于计算机编程的语言,具有较高的效率和灵活性。
在C语言中,常见的算法程序包括排序算法、查找算法、递归算法等等。
以下是一些常用的C语言算法程序的汇总:1.排序算法:-冒泡排序:通过多次迭代比较相邻元素并交换位置,将最大的元素逐渐移动到正确的位置。
-插入排序:将待排序的元素与已排序的部分依次比较并插入到正确的位置。
-选择排序:每次从待排序的元素中选择最小的元素并与已排序的部分交换位置。
-快速排序:通过选择一个基准元素,将数组划分为两个子数组进行递归排序。
2.查找算法:-顺序查找:逐个比较数组中的元素,直到找到目标元素或到数组末尾。
-二分查找:通过比较目标元素与数组中间元素的大小,逐步缩小范围,直到找到目标元素。
-哈希查找:通过散列函数将目标元素映射到哈希表的索引位置进行查找。
3.递归算法:-阶乘:通过递归调用自身计算一个正整数的阶乘。
-斐波那契数列:通过递归调用自身计算斐波那契数列的第n个数。
-二叉树遍历:通过递归调用自身遍历二叉树的各个节点。
4.图算法:- 最短路径算法:如Dijkstra算法和Floyd算法,用于计算图中两个节点之间的最短路径。
-拓扑排序:通过对有向无环图进行排序,使得所有的边从排在前面的节点指向排在后面的节点。
- 最小生成树:如Prim算法和Kruskal算法,用于找到图中连接所有节点的最小子树。
5.动态规划:-最长公共子序列:通过寻找两个字符串中的最长公共子序列,解决字符串匹配问题。
-背包问题:通过动态规划解决在给定容量下选取物品使得总价值最大的问题。
-最大子序列和:通过动态规划解决一个数组中选取连续子序列使得和最大的问题。
以上只是一些C语言中常用的算法程序的汇总,实际上,还有很多其他的算法,如逆波兰表达式、霍夫曼编码、最小割等等。
通过学习这些算法,可以更好地理解C语言的应用和开发。
递归树
递归树的结点有两个域,如下图:
T(size)指问题大小为size时,函数的复杂度。
nonrec.cost指问题大小为size时的非递归代价。
根结点的每个子结点都代表了这个问题分拆的一个子问题的复杂度。
就这样递归地分解问题。
一直到达叶子结点,也就是base-case.在前面的讨论中,我们没有涉及base-case,在使用递归树分析复杂度时,我们假设base-case的复杂度为1。
举一个例子就可以很明白的说明如何构造递归树。
Example1: 由递归方程T(n)=2T(n/2)+n构造递归树
首先,构造根接点
它的子结点是
……,以此类推。
所以,最后的递归树为:
递归树规则:
根结点的复杂度=所有非叶结点的非递归复杂度+叶子结点的复杂度。
所以,在上面的例子中,每层的非递归复杂度为n,而base-case出现在大约lgn 层(n/2^d =1;d = lgn)。
由于base-case的复杂度为1,所以T(n)≈nlgn,即递归树是分析和计算递归方程的一个重要工具。
它可以直观地表示出递归函数的复杂度,并使人易于理解。
五大基础算法算法是计算机科学中的一个重要概念,它是指为解决某一问题而设计的一系列计算步骤的有序集合。
在计算机科学中,算法是非常重要的,它们是计算机程序的核心部分,可以解决各种计算机科学问题,从简单到复杂都有。
基础算法是算法学习中最基本、最常用的一类算法,在日常生活当中也得到广泛应用。
接下来我们就来介绍五大基础算法。
一、排序算法排序算法是将一组数据按照某种规则进行排序的算法。
在日常生活中,我们经常使用排序算法来对一些数据进行排序,例如比赛名次,商品价格等等。
常见的排序算法有冒泡排序、快速排序、选择排序和插入排序等。
冒泡排序是一种较为简单的排序算法,它的基本思想是对相邻的数据进行比较和交换,从而达到排序的目的。
具体实现过程中需要通过两个嵌套的循环来进行比较和交换。
快速排序则是一种比较高效的排序算法,它的基本思想是采用“分治”策略,将数据分为两个子序列,一个比关键字小,一个比关键字大。
通过递归的方式不断进行分治,最终完成排序。
选择排序是通过选择最小的元素放到前面的位置,从而达到排序的目的。
插入排序则是通过将元素插入到已经排好序的序列中,使得整个序列有序。
二、递归算法递归算法是指函数调用自身的一种算法。
在计算机科学中,递归算法是一种基本的算法思想,它可以解决一些复杂的问题。
例如,二叉树的遍历、图的遍历、背包问题等等都可以使用递归算法来解决。
三、查找算法查找算法是在一个数据集中查找某一个元素的算法。
常见的查找算法有线性查找、二分查找和哈希查找等。
线性查找是将数据集中的元素与目标元素逐一比较,直到找到目标元素为止。
二分查找也叫折半查找,它的基本思想是先找到中间元素,再与目标元素进行比较。
通过每次缩小查找范围,最终找到目标元素。
哈希查找则是通过哈希函数将数据集映射到不同的散列表中,从而进行查找的算法。
四、贪心算法贪心算法是一种基于贪心策略的算法思想。
贪心策略是指每一步都选择当前局部最优解,从而最终达到全局最优解的策略。
计算机算法设计五⼤常⽤算法的分析及实例摘要算法(Algorithm)是指解题⽅案的准确⽽完整的描述,是⼀系列解决问题的清晰指令,算法代表着⽤系统的⽅法描述解决问题的策略机制。
也就是说,能够对⼀定规范的输⼊,在有限时间内获得所要求的输出。
如果⼀个算法有缺陷,或不适合于某个问题,执⾏这个算法将不会解决这个问题。
不同的算法可能⽤不同的时间、空间或效率来完成同样的任务。
其中最常见的五中基本算法是递归与分治法、动态规划、贪⼼算法、回溯法、分⽀限界法。
本⽂通过这种算法的分析以及实例的讲解,让读者对算法有更深刻的认识,同时对这五种算法有更清楚认识关键词:算法,递归与分治法、动态规划、贪⼼算法、回溯法、分⽀限界法AbstractAlgorithm is the description to the problem solving scheme ,a set of clear instructions to solve the problem and represents the describe the strategy to solve the problem using the method of system mechanism . That is to say, given some confirm import,the Algorithm will find result In a limited time。
If an algorithm is defective or is not suitable for a certain job, it is invalid to execute it. Different algorithms have different need of time or space, and it's efficiency are different.There are most common algorithms: the recursive and divide and conquer、dynamic programming method、greedy algorithm、backtracking、branch and bound method.According to analyze the five algorithms and explain examples, make readers know more about algorithm , and understand the five algorithms more deeply.Keywords: Algorithm, the recursive and divide and conquer, dynamic programming method, greedy algorithm、backtracking, branch and bound method⽬录1. 前⾔ (4)1.1 论⽂背景 (4)2. 算法详解 (5)2.1 算法与程序 (5)2.2 表达算法的抽象机制 (5)2.3 算法复杂性分析 (5)3.五中常⽤算法的详解及实例 (6)3.1 递归与分治策略 (6)3.1.1 递归与分治策略基本思想 (6)3.1.2 实例——棋盘覆盖 (7)3.2 动态规划 (8)3.2.1 动态规划基本思想 (8)3.2.2 动态规划算法的基本步骤 (9)3.2.3 实例——矩阵连乘 (9)3.3 贪⼼算法 (11)3.3.1 贪⼼算法基本思想 (11)3.3.2 贪⼼算法和动态规划的区别 (12)3.3.3 ⽤贪⼼算法解背包问题的基本步骤: (12)3.4 回溯发 (13)3.4.1 回溯法基本思想 (13)3.3.2 回溯发解题基本步骤 (13)3.3.3 实例——0-1背包问题 (14)3.5 分⽀限界法 (15)3.5.1 分⽀限界法思想 (15)3.5.2 实例——装载问题 (16)总结 (18)参考⽂献 (18)1. 前⾔1.1 论⽂背景算法(Algorithm)是指解题⽅案的准确⽽完整的描述,是⼀系列解决问题的清晰指令,算法代表着⽤系统的⽅法描述解决问题的策略机制。
简单算法c语言
C语言中的算法是程序设计的基础,也是我们在编写程序时必须掌握
的技能之一。
简单算法是指那些基本的、常用的、易于理解和实现的
算法,如排序、查找、递归等。
一、排序算法
1.冒泡排序
冒泡排序是一种简单的排序算法,其思想是将相邻两个元素比较大小,如果前面比后面大,则交换位置,直到整个序列有序为止。
2.选择排序
选择排序是一种简单直观的排序算法,其思想是从未排序序列中找到
最小元素,放到已排好序列的末尾。
3.插入排序
插入排序是一种简单直观的排序算法,其思想是将未排好序列中每一
个元素插入到已排好序列中正确位置上。
二、查找算法
1.线性查找
线性查找又称顺序查找,其思想是从头到尾遍历整个数组或列表,逐个比较每一个元素是否与目标相同。
2.二分查找
二分查找又称折半查找,其思想是先将数组或列表按照大小顺序排好序,然后通过不断地折半缩小范围来寻找目标元素。
三、递归算法
递归算法是指在程序中调用自身的一种算法,其思想是将问题分解成更小的子问题,并不断地递归调用自身来解决这些子问题。
例如,计算阶乘可以使用递归算法来实现:
int factorial(int n)
{
if(n == 0 || n == 1)
return 1;
else
return n * factorial(n-1);
}
以上就是C语言中的简单算法,虽然它们看起来很简单,但是它们在实际编程中却有很大的作用。
掌握这些基本的、常用的、易于理解和实现的算法,可以提高我们编写程序的效率和质量。
递推算法在程序编辑过程中,我们可能会遇到这样一类问题,出题者告诉你数列的前几个数,或通过计算机获取了数列的前几个数,要求编程者求出第N项数或所有的数列元素(如果可以枚举的话),或求前N项元素之和。
这种从已知数据入手,寻找规则,推导出后面的数的算法,称这递推算法。
典型的递推算法的例子有整数的阶乘,1,2,6,24,120…,a[n]=a[n-1]*n(a[1]=1);前面学过的2n,a[n]=a[n-1]*2(a[1]=1),菲波拉契数列:1,2,3,5,8,13…,a[n]=a[n-1]+a[n-2](a[1]=1,a[2]=2)等等。
在处理递推问题时,我们有时遇到的递推关系是十分明显的,简单地写出递推关系式,就可以逐项递推,即由第i项推出第i+1项,我们称其为显示递推关系。
但有的递推关系,要经过仔细观察,甚至要借助一些技巧,才能看出它们之间的关系,我们称其为隐式的递推关系。
下面我们来分析一些例题,掌握一些简单的递推关系。
例如阶梯问题:题目的意思是:有N级阶梯,人可以一步走上一级,也可以一步走两级,求人从阶梯底走到顶端可以有多少种不同的走法。
这是一个隐式的递推关系,如果编程者不能找出这个递推关系,可能就无法做出这题来。
我们来分析一下:走上第一级的方法只有一种,走上第二级的方法却有两种(两次走一级或一次走两级),走上第三级的走法,应该是走上第一级的方法和走上第二级的走法之和(因从第一级和第二级,都可以经一步走至第三级),推广到走上第i级,是走上第i-1级的走法与走上第i-2级的走法之和。
很明显,这是一个菲波拉契数列。
到这里,读者应能很熟练地写出这个程序。
在以后的程序习题中,我们可能还会遇到菲波拉契数列变形以后的结果:如f(i)=f(i-1)+2f(i-2),或f(i)=f(i-1)+f(i-2)+f(i-3)等。
我们再来分析一下尼科梅彻斯定理。
定理内容是:任何一个整数的立方都可以写成一串连续的奇数和,如:43=13+15+17+19=64。
【关键字】分析《算法分析与设计》作业参考答案作业一一、名词解释:1.递归算法:直接或间接地调用自身的算法称为递归算法。
2.程序:程序是算法用某种程序设计语言的具体实现。
2、简答题:1.算法需要满足哪些性质?简述之。
算法是若干指令的有穷序列,满足性质:1)输入:有零个或多个外部量作为算法的输入。
2)输出:算法产生至少一个量作为输出。
3)确定性:组成算法的每条指令清晰、无歧义。
4)有限性:算法中每条指令的执行次数有限,执行每条指令的时间也有限。
2.简要分析分治法能解决的问题具有的特征。
分析分治法能解决的问题主要具有如下特征:1)该问题的规模缩小到一定的程度就可以容易地解决;2)该问题可以分解为若干个规模较小的相同问题,即该问题具有最优子结构性质;3)利用该问题分解出的子问题的解可以合并为该问题的解;4)该问题所分解出的各个子问题是相互独立的,即子问题之间不包含公共的子问题。
3.简要分析在递归算法中消除递归调用,将递归算法转化为非递归算法的方法。
将递归算法转化为非递归算法的方法主要有:1)采用一个用户定义的栈来模拟系统的递归调用工作栈。
该方法通用性强,但本质上还是递归,只不过人工做了本来由编译器做的事情,优化效果不明显。
2)用递推来实现递归函数。
3)通过Cooper变换、反演变换能将一些递归转化为尾递归,从而迭代求出结果。
后两种方法在时空复杂度上均有较大改善,但其适用范围有限。
三、算法编写及算法应用分析题:1.冒泡排序算法的基本运算如下:for i ←1 to n-1 dofor j ←1 to n-i doif a[j]<a[j+1] then交换a[j]、a[j+1];分析该算法的时间复杂性。
解答:排序算法的基本运算步为元素比较,冒泡排序算法的时间复杂性就是求比较次数与n的关系。
1)设比较一次花时间1;2)内循环次数为:n-i次,(i=1,…n),花时间为:3)外循环次数为:n-1,花时间为:2.设计一个分治算法计算一棵二叉树的高度。
算法设计与分析的基本方法1.递推法递推算法是一种用若干步可重复的简运算(规律)来描述复杂问题的方法.递推是序列计算机中的一种常用算法。
它是按照一定的规律来计算序列中的每个项,通常是通过计算机前面的一些项来得出序列中的指定象的值。
其思想是把一个复杂的庞大的计算过程转化为简单过程的多次重复,该算法利用了计算机速度快和不知疲倦的机器特点。
2.递归法程序调用自身的编程技巧称为递归(recursion)。
一个过程或函数在其定义或说明中有直接或间接调用自身的一种方法,它通常把一个大型复杂的问题层层转化为一个与原问题相似的规模较小的问题来求解,递归策略只需少量的程序就可描述出解题过程所需要的多次重复计算,大大地减少了程序的代码量。
递归的能力在于用有限的语句来定义对象的无限集合。
一般来说,递归需要有边界条件、递归前进段和递归返回段。
当边界条件不满足时,递归前进;当边界条件满足时,递归返回。
注意:(1) 递归就是在过程或函数里调用自身;(2) 在使用递归策略时,必须有一个明确的递归结束条件,称为递归出口。
3.穷举法穷举法,或称为暴力破解法,是一种针对于密码的破译方法,即将密码进行逐个推算直到找出真正的密码为止。
例如一个已知是四位并且全部由数字组成的密码,其可能共有10000种组合,因此最多尝试10000次就能找到正确的密码。
理论上利用这种方法可以破解任何一种密码,问题只在于如何缩短试误时间。
因此有些人运用计算机来增加效率,有些人辅以字典来缩小密码组合的范围。
4.贪心算法贪婪算法是一种对某些求最优解问题的更简单、更迅速的设计技术。
用贪婪法设计算法的特点是一步一步地进行,常以当前情况为基础根据某个优化测度作最优选择,而不考虑各种可能的整体情况,它省去了为找最优解要穷尽所有可能而必须耗费的大量时间,它采用自顶向下,以迭代的方法做出相继的贪心选择,每做一次贪心选择就将所求问题简化为一个规模更小的子问题, 通过每一步贪心选择,可得到问题的一个最优解,虽然每一步上都要保证能获得局部最优解,但由此产生的全局解有时不一定是最优的,所以贪婪法不要回溯。
算法分析与设计论⽂1:递归算法程序直接或间接调⽤⾃⾝的编程技巧称为递归算法(Recursion)。
递归算法是⼀个过程或函数在其定义或说明中有直接或间接调⽤⾃⾝的⼀种⽅法。
它通常把⼀个⼤型复杂的问题转化为⼀个与原问题类似的规模较⼩的问题来求解。
递归策略只需少量的代码就可描述出解题过程所需要的多次重复计算,⼤⼤减少了程序的代码量。
递归的优势在于⽤有限的语句来定义对象的⽆限集合,⽤递归思想写出的程序往往⼗分简洁易懂。
递归需要有边界条件,递进前进段和递归返回段,当边界条件不满⾜时,递归前进;当边界条件满⾜时,递归返回(使⽤递归时,不必须有⼀个明确的递归出⼝,否则递归将⽆限进⾏下去)。
递归算法解题的运⾏效率较低,在递归调⽤过程中,系统为每⼀层的返回点,局部变量等开辟了堆栈来储存。
递归次数过多容易造成堆栈溢出等。
例:Fibonacci数列“菲波那切数列”是意⼤利数学家列昂纳多-斐波那契最先研究的⼀种递归数列,他的每⼀项都等于前两项制盒次数列的前⼏项为1,1,2,3,5等。
在⽣物数学中许多⽣物现象都会出现菲波那切数列的规律,斐波那契数列相邻两项的⽐例近于黄⾦分割数,其递归定义为:Fibonacci数列的递归算法:int fib(int n){if (n<=1) return 1;return fib(n-1)+fib(n-2);}算法效率⾮常低,重复递归的次数太多,通常采⽤递推算法:int fib[50]; //采⽤数组保存中间结果void Fibonacci(int n){fib[0] = 1;fib[1] = 1;for (int i=2; i<=n; i++)fib[i] = fib[i-1]+fib[i-2];}采⽤数组保存之前已求出的数据,减少了递归次数,提⾼了算法效率。
2:分治算法在计算机科学中,分治法是⼀种很重要的算法。
字⾯上的解释是“分⽽治之”,就是把⼀个复杂的问题分成两个或更多的相同或相似的⼦问题,再把⼦问题分成更⼩的⼦问题……直到最后⼦问题可以简单的直接求解,原问题的解即⼦问题的解的合并。
c语言常见算法C语言是一种非常流行的编程语言,广泛应用于软件开发和计算机科学领域。
在C语言中,算法是解决问题的关键步骤。
本文将介绍一些常见的C语言算法,包括排序算法、搜索算法和递归算法。
一、排序算法1. 冒泡排序算法冒泡排序是一种简单的排序算法,它重复地遍历要排序的列表,比较相邻的两个元素,并交换它们的位置,直到整个列表排序完成。
2. 插入排序算法插入排序算法通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。
3. 快速排序算法快速排序是一种高效的排序算法,它通过选择一个元素作为基准,将列表分为两部分,一部分小于基准,一部分大于基准,然后递归地对两部分进行排序。
二、搜索算法1. 线性搜索算法线性搜索算法逐个地检查列表中的元素,直到找到目标元素或者遍历完整个列表。
2. 二分搜索算法二分搜索算法适用于已排序的列表。
它通过比较目标元素和列表的中间元素,将列表分为两部分,然后在适当的部分继续搜索,直到找到目标元素或者确定目标元素不存在。
三、递归算法递归算法是一种自我调用的算法,它将问题分解成更小的子问题,然后在子问题上递归地调用自身,直到达到基本情况。
对于C语言中的算法来说,递归函数的编写非常重要。
需要确保递归的终止条件,并正确处理递归调用中传递的参数。
四、其他常见算法1. 图算法图算法是解决与图相关的问题的算法。
它可以解决最短路径问题、最小生成树问题等。
2. 动态规划算法动态规划算法是一种通过将问题分解成更小的子问题来解决复杂问题的算法。
它通常用于解决最优化问题。
3. 贪心算法贪心算法通过每一步选择当前最优解来构建问题的解决方案。
它通常不能保证找到全局最优解,但在某些情况下可以得到较好的近似解。
总结C语言常见算法涵盖了排序算法、搜索算法、递归算法以及其他常用的算法。
对于每个算法,我们都介绍了其基本原理和应用场景。
在实际编程中,根据具体的问题,选择合适的算法是非常重要的。
熟悉C语言中的常见算法,可以帮助程序员更好地解决问题,提高代码的效率与质量。
一、教学目标1、知识与技能(1).认识递归现象。
(2).使用递归算法解决问题往往能使算法的描述乘法而易于表达(3).理解递归三要素:每次递归调用都要缩小规模;前次递归调用为后次作准备:递归调用必须有条件进行。
(4).认识递归算法往往不是高效的算法。
(5).了解递归现象的规律。
(6).能够设计递归程序解决适用于递归解决的问题。
(7).能够根据算法写出递归程序。
(8).了解生活中的递归现象,领悟递归现象的既有重复,又有变化的特点,并且从中学习解决问题的一种方法。
2、方法与过程本节让同学们玩汉诺塔的游戏,导入递归问题,从用普通程序解决斐波那契的兔子问题入手,引导学生用自定义了一个以递归方式解决的函数过程解决问题,同时让同学们做三个递归练习,巩固提高。
然后让学生做练习(2)和练习(3)这两道题目的形式相差很远,但方法和答案却是完全相同的练习,体会其中的奥妙,加深对递归算法的了解。
最后用子过程解决汉诺塔的经典问题。
3、情感态度和价值观结合高中生想象具有较强的随意性、更富于现实性的身心发展特点,综合反映出递归算法的特点,以及递归算法解答某些实践问题通常得很简洁,从而激发学生对程序设计的追求和向往。
二、重点难点1、教学重点(1)了解递归现象和递归算法的特点。
(2)能够根据问题设计出恰当的递归程序。
2、教学难点(1)递归过程思路的建立。
(2)判断问题是否适于递归解法。
(3)正确写出递归程序。
三、教学环境1、教材处理教材选自《广东省普通高中信息技术选修一:算法与程序设计》第四章第五节,原教材的编排是以本节以斐波那契的兔子问题引人,导出递归算法,从而自定义了一个以递归方式解决的函数过程。
然后利用子过程解决汉诺塔的经典问题。
教材经处理后,让同学们玩汉诺塔的游戏,导入递归问题,从用普通程序解决斐波那契的兔子问题入手,引导学生用自定义了一个以递归方式解决的函数过程解决问题,同时让同学们做三个递归练习,巩固提高。
然后让学生做练习(2)和练习(3)这两道题目的形式相差很远,但方法和答案却都是完全相同的练习,体会其中的奥妙,加深对递归算法的了解。
最后用子过程解决汉诺塔的经典问题。
教学方法采用讲解、探究、任务驱动和学生自主学习相结合2、预备知识学生已掌握了用计算机解决问题的过程,掌握了程序设计基础,掌握了解析法、穷举法、查找法、排序法设计程序的技巧。
3、硬件要求建议本节课在多媒体电脑教室中完成,最好有广播教学系统或投影仪,为拓展学习,学生机应允许上互联网。
4、所需软件学生机要安装VB6.0或以上版本。
5、所需课时2课时(90分钟)四、教学过程导入:大家玩汉诺塔游戏:图4-5(1)汉诺塔游戏的部分界面这个游戏盘子在A、B、C三根柱子上不停运动,有没有规律,和你在照过镜子时遇到的情况相同吗?当你往镜子前面一站,镜子里面就有一个你的像。
但你试过两面镜子一起照吗?如果甲、乙两面镜子相互面对面放着,你往中间一站,嘿,两面镜子里都有你的千百个“化身”!为什么会有这么奇妙的现象呢?原来,甲镜子里有乙镜子的像,乙镜子里也有甲镜子的像,而且这样反反复复,就会产生一连串的“像中像”。
这是一种递归现象。
由同学们总结出递归算法的概念递归算法:是一种直接或者间接地调用自身的算法。
在计算机编写程序中,递归算法对解决一大类问题是十分有效的,它往往使算法的描述简洁而且易于理解。
4-16:著名的意大利数学家斐波那契(Fibonacci)在他的著作《算盘书》中提出了一个“兔子问题”:假定小兔子一个月就可以长成大兔子,而大兔子每个月都会生出一对小兔子。
如果年初养了一对小兔子,问到年底时将有多少对兔子? (当然得假设兔子没有死亡而且严格按照上述规律长大与繁殖)我们不难用以前学过的知识设计出如下算法:①输入计算兔子的月份数:n②If n < 3 Then c = 1 Else a = 1: b = 1③i = 3④ c = a + b:a = b:b = c⑤i=i+1,如果i≤n则返回④⑥结束参考程序如下:Private Sub Command1_Click()n = Val(Text1.Text)If n < 3 Then c = 1 Else a = 1: b = 1For i = 3 To nc = a + ba = bb = cNext iText2.Text = "第" & n & "月的兔子数目是:" & cEnd Sub图4-5(2)斐波那契兔子程序运行结果图开动脑筋:我们有没有更简单的方法解决该问题呢?4.5.1 从斐波那契的兔子问题看递归算法1.斐波那契的兔子问题子(1)分析问题。
我们可以根据题意列出表4-3来解决这个问题:表4—3兔子问题分析表这个表格虽然解决了斐波那契的兔子问题(年底时兔子的总数是144只),但仔细观察一下这个表格,你会发现兔子的数目增长得越来越快,如果时间再长,只用列表的方法就会有困难。
(例如,你愿意用列表的方法求出5年后兔子的数目吗?)我们需要研究表中的规律,找出一般的方法,去解决这个问题。
交流仔细研究表4-8,你有些什么发现?每一个月份的大兔数、小兔数与上一个月的数字有什么联系,能肯定这个规律吗?恭喜你,你快成功了?(2)设计算法。
“兔子问题”很容易列出一条递推式而得到解决。
假设第N个月的兔子数目是F(N),我们有:这是因为每月的大兔子数目一定等于上月的兔子总数,而每个月的小兔子数目一定等于上月的大兔子数目(即前一个月的兔子的数目)。
由上述的递推式我们可以设计出递归程序。
递归程序的特点是独立写出一个函数(或子过程),而这个函数只对极简单的几种情况直接给出解答,而在其余情况下通过反复的调用自身而把问题归结到最简单的情况而得到解答。
空中加油站:自定义函数的定义格式:Function procedurename(arguments) [As type]StatementsEnd Function其中的procedurename是函数名,arguments是函数中的参数表,type是函数返回值的数据类型,[]表示可有可无的部分,statements是过程中的代码调用函数的格式:procedurename(arguments)(3)编写程序。
窗体中开设一个文本框Textl用于填人月数N,设置命令框Commandl,点击它即执行程序求出第N月的兔子数。
然后用文本框Text2输出答案。
根据递推式可以写出递归程序如下:Function Fib(ByVal N As Integer) As Long文本框2 If N < 3 Then Fib = 1 Else Fib = Fib(N - 1) + Fib(N - 2)End FunctionPrivate Sub Command1_Click()N = Val(Text1.Text)Text2.Text = "第" & N & "月的兔子数目是:" & Fib(N)End Sub(4)调试程序因为这个算法的效率不高,建议在调试程序时月份数不要大于40。
图4-5(4)斐波那契兔子程序运行结果图(5)检测结果挑战自我:(以下部分由学生自己完成)(1)利用递归方法编写一求N的阶乘。
分析:根据N!=N*(N-1)*(N-2)*(N-3)*……*3*2*1可以推出下列式子:这是一个典型的递归算法,参考程序如下:Function F(ByVal n As Integer) As LongIf n = 1 Then F = 1 Else F = n * F(n - 1)End FunctionPrivate Sub Form_Click()Dim n As Integern = Val(InputBox("请输入正整数N:", "求N的阶乘")) Print "输入的正整数是"; n;Print ",阶乘是"; F(n)End Sub图4-5(5)求阶乘程序的运行结果图(2)对一正整数N,用数字l和2组成一条加法算式,使其和为N,共可以列出多少条不同的式子?(“l+2”和“2+1”看作是不同的式子)。
算法设计:假设和为N时可列式子的方法数是F(N),那么第一个加数可选择1或2。
当第一个加数为1时剩下加数的和为N一1,故方法数为F(N一1);当第一个加数为2时,剩下加数的和为N-2,故方法数为F(N-2)。
于是可以得到如下式子:这是一个典型的递归算法,参考程序如下:参考程序如下:Function F(ByVal n As Integer) As LongIf n <= 2 Then F = n Else F = F(n - 1) + F(n - 2)End FunctionPrivate Sub Form_Click()Dim n As Integern = Val(InputBox("请输入正整数N:", "输入式子的总和"))Print "当总和是"; n; "时"Print "可以列出不同的由1和2组成的加法式子"; F(n); "条"End Sub图4-5(6)书上P137练习2程序运行结果图(3)罗光明在上楼梯时,有时一步一级楼梯,有时一步两级。
如果楼梯有N级,他上完这N级楼梯有多少种不同的方法?设计算法假设楼梯级数为N时的方法数是F(N),那么第一步可选择1或2级楼梯。
当第一步为1级时剩下楼梯的级数为N-1,故方法数为F(N-1);当第一步为2级时,剩下楼梯的级数为N-2,故方法数为F(N-2)。
于是可以得到如下式子:这是一个典型的递归算法,参考程序如下:程序如下:Function F(ByVal n As Integer)As LongIf n<=2 Then F=n Else F=F(n-1)+F(n-2)End Functi 0nPrivate Sub Form_Click()Dim n As Integern=Val(InputBox("请输入楼梯级数N:","输人楼梯级数"))Print "当楼梯级数";n;"时,"Print "可以有";F(n);"种不同的上楼梯方法。
"End Sub同学们比较一下你们所做的练习(2)和(3)的程序代码,不知同学们有没有发现一个有趣的现象?为什么会这样?本节小结:递归算法的特点递归过程一般通过函数或子过程来实现。