要理解递归算法首先你要理解递归算法。英文原句

要理解递归,你先要理解递归
傅里叶变换在物理学、数论、组合数学、信号处理、概率论、统计学、密码学、声学、光学、海洋学、结构动力学等领域都有着广泛的应用(例如在信号处理中,傅里叶变换的典型用途是将信号分解成幅值分量和频率分量)。
傅里叶变换能将满足一定条件的某个函数表示成三角函数(正弦和/或余弦函数)或者它们的积分的线性组合。在不同的研究领域,傅里叶变换具有多种不同的变体形式,如连续傅里叶变换和离散傅里叶变换。
傅里叶变换是一种解决问题的方法,一种工具,一种看待问题的角度。理解的关键是:一个连续的信号可以看作是一个个小信号的叠加,从时域叠加与从频域叠加都可以组成原来的信号,将信号这么分解后有助于处理。
我们原来对一个信号其实是从时间的角度去理解的,不知不觉中,其实是按照时间把信号进行分割,每一部分只是一个时间点对应一个信号值,一个信号是一组这样的分量的叠加。傅里叶变换后,其实还是个叠加问题,只不过是从频率的角度去叠加,只不过每个小信号是一个时间域上覆盖整个区间的信号,但他确有固定的周期,或者说,给了一个周期,我们就能画出一个整个区间上的分信号,那么给定一组周期值(或频率值),我们就可以画出其对应的曲线,就像给出时域上每一点的信号值一样,不过如果信号是周期的话 ,频域的更简单,只需要几个甚至一个就可以了,时域则需要整个时间轴上每一点都映射出一个函数值。
傅里叶变换就是将一个信号的时域表示形式映射到一个频域表示形式;逆傅里叶变换恰好相反。这都是一个信号的不同表示形式。它的公式会用就可以,当然把证明看懂了更好。
对一个信号做傅里叶变换,可以得到其频域特性,包括幅度和相位两个方面。幅度是表示这个频率分量的大小,那么相位呢,它有什么物理意义?频域的相位与时域的相位有关系吗?信号前一段的相位(频域)与后一段的相位的变化是否与信号的频率成正比关系。
傅里叶变换就是把一个信号,分解成无数的正弦波(或者余弦波)信号。也就是说,用无数的正弦波,可以合成任何你所需要的信号。
想一想这个问题:给你很多正弦信号,你怎样才能合成你需要的信号呢?答案是要两个条件,一个是每个正弦波的幅度,另一个就是每个正弦波之间的相位差。所以现在应该明白了吧,频域上的相位,就是每个正弦波之间的相位。  
傅里叶变换用于信号的频率域分析,一般我们把电信号描述成时间域的数学模型,而数字信号处理对信号的频率特性更感兴趣,而通过傅立叶变换很容易得到信号的频率域特性。
傅里叶变换简单通俗理解就是把看似杂乱无章的信号考虑成由一定振幅、相位、频率的基本正弦(余弦)信号组合而成,傅里叶变换的目的就是找出这些基本正弦(余弦)信号中振幅较大(能量较高)信号对应的频率,从而找出杂乱无章的信号中的主要振动频率特点。如减速机故障时,通过傅里叶变换做频谱分析,根据各级齿轮转速、齿数与杂音频谱中振幅大的对比,可以快速判断哪级齿轮损伤。
拉普拉斯变换,是工程数学中常用的一种积分变换。
它是为简化计算而建立的实变量函数和复变量函数间的一种函数变换。对一个实变量函数作拉普拉斯变换,并在复数域中作各种运算,再将运算结果作拉普拉斯反变换来求得实数域中的相应结果,往往比直接在实数域中求出同样的结果在计算上容易得多。拉普拉斯变换的这种运算步骤对于求解线性微分方程尤为有效,它可把微分方程化为容易求解的代数方程来处理,从而使计算简化。在经典控制理论中,对控制系统的分析和综合,都是建立在拉普拉斯变换的基础上的。
引入拉普拉斯变换的一个主要优点,是可采用传递函数代替微分方程来描述系统的特性。这就为采用直观和简便的图解方法来确定控制系统的整个特性(见信号流程图、动态结构图)、分析控制系统的运动过程(见奈奎斯特稳定判据、根轨迹法),以及综合控制系统的校正装置(见控制系统校正方法)提供了可能性。
拉普拉斯变换在工程学上的应用:应用拉普拉斯变换解常变量齐次微分方程,可以将微分方程化为代数方程,使问题得以解决。在工程学上,拉普拉斯变换的重大意义在于:将一个信号从时域上,转换为复频域(s域)上来表示;在线性系统,控制自动化上都有广泛的应用。
在数字信号处理中,Z变换是一种非常重要的分析工具。但在通常的应用中,我们往往只需要分析信号或系统的频率响应,也即是说通常只需要进行傅里叶变换即可。那么,为什么还要引进Z变换呢?
Z变换和傅里叶变换之间有存在什么样的关系呢?傅里叶变换的物理意义非常清晰:将通常在时域表示的信号,分解为多个正弦信号的叠加。每个正弦信号用幅度、频率、相位就可以完全表征。傅里叶变换之后的信号通常称为频谱,频谱包括幅度谱和相位谱,分别表示幅度随频率的分布及相位随频率的分布。在自然界,频率是有明确的物理意义的,比如说声音信号,男同胞声音低沉雄浑,这主要是因为男声中低频分量更多;女同胞多高亢清脆,这主要是因为女声中高频分量更多。对一个信号来说,就包含的信息量来讲,时域信号及其相应的傅里叶变换之后的信号是完全一样的。那傅里叶变换有什么作用呢?因为有的信号主要在时域表现其特性,如电容充放电的过程;而有的信号则主要在频域表现其特性,如机械的振动,人类的语音等。若信号的特征主要在频域表示的话,则相应的时域信号看起来可能杂乱无章,但在频域则解读非常方便。在实际中,当我们采集到一段信号之后,在没有任何先验信息的情况下,直觉是试图在时域能发现一些特征,如果在时域无所发现的话,很自然地将信号转换到频域再看看能有什么特征。信号的时域描述与频域描述,就像一枚硬币的两面,看起来虽然有所不同,但实际上都是同一个东西。正因为如此,在通常的信号与系统的分析过程中,我们非常关心傅里叶变换。
既然人们只关心信号的频域表示,那么Z变换又是怎么回事呢?要说到Z变换,可能还要先追溯到拉普拉斯变换。拉普拉斯变换是以法国数学家拉普拉斯命名的一种变换方法,主要是针对连续信号的分析。拉普拉斯和傅里叶都是同时代的人,他们所处的时代在法国是处于拿破仑时代,国力鼎盛。在科学上也取代英国成为当时世界的中心,在当时众多的科学大师中,拉普拉斯、拉格朗日、傅里叶就是他们中间最为璀璨的三颗星。傅里叶关于信号可以分解为正弦信号叠加的论文,其评审人即包括拉普拉斯和拉格朗日。
回到正题,傅里叶变换虽然好用,而且物理意义明确,但有一个最大的问题是其存在的条件比较苛刻,比如时域内绝对可积的信号才可能存在傅里叶变换。拉普拉斯变换可以说是推广了这以概念。在自然界,指数信号exp(-x)是衰减最快的信号之一,对信号乘上指数信号之后,很容易满足绝对可积的条件。因此将原始信号乘上指数信号之后一般都能满足傅里叶变换的条件,这种变换就是拉普拉斯变换。这种变换能将微分方程转化为代数方程,在18世纪计算机还远未发明的时候,意义非常重大。从上面的分析可以看出,傅里叶变换可以看做是拉普拉斯的一种特殊形式,即所乘的指数信号为exp(0)。也即是说拉普拉斯变换是傅里叶变换的推广,是一种更普遍的表达形式。在进行信号与系统的分析过程中,可以先得到拉普拉斯变换这种更普遍的结果,然后再得到傅里叶变换这种特殊的结果。这种由普遍到特殊的解决办法,已经证明在连续信号与系统的分析中能够带来很大的方便。
Z变换可以说是针对离散信号和系统的拉普拉斯变换,由此我们就很容易理解Z变换的重要性,也很容易理解Z变换和傅里叶变换之间的关系。Z变换中的Z平面与拉普拉斯中的S平面存在映射的关系,z=exp(Ts)。在Z变换中,单位圆上的结果即对应离散时间傅里叶变换的结果。
已投稿到:
以上网友发言只代表其个人观点,不代表新浪网的观点或立场。深入理解递归函数
&&& 刚开始接触编程对递归调用都是比较头痛,很多年前我也会一样。昨天晚上睡觉突然想起了谭浩强C语言的汉诺塔递归调用,记得当时是在高中的时候,我表姐在上大学,她把谭浩强的C语言给了我,只看书不实践,现在想起来效果还真差。其中递归调用汉诺塔看了好久都没有整明白,直到上大学学习C语言也还没有搞明白,当学到递归调用了,我就去问老师,老是说回去看看,下周告诉我。谁知到老师真的很忙,下周也没有结果。后来自己什么时候明白的也忘记了。&&&&
&&& 刚开始接触递归都会告诉你,递归占用资源,使程序复杂,最好不要使用;还有人说,如果这个人一来就是用递归,我肯定不会聘用他。但是我认为这些观点太片面。递归算法的目的降低程序的复杂度,解放大脑负担,让大脑更加专注于问题本身。程序的性能跟递归没有什么关系,更重要的时算法本身,我们会在稍后讲解一下同一种算法同样是递归,性能的差异巨大。设计模式中,很多模式都存在递归。
&&& 刚开始接触递归的,往往都会在里面打圈圈,自己越绕越晕,觉得递归太复杂。其实看待递归的时候,也是要分层面看待,不要把自己的大脑当做是电脑,可以绕很多的圈圈,有人说人的大脑同时能处理7个左右的变量,绕一圈就多几个变量,能绕几圈啊。呵呵。找到一个算法,在编写算法的时候,只考虑一次递归所做的事情,如果遇到到递归调用函数的时候,把他当做一个函数整体考虑,他能完成他要完成的事情,要相信他,也要相信自己。我们所在的层面就是算法的层面,或者一次执行的层面。如果在算法层面和递归调用层面来回穿插的思考,读懂递归算法将非常困难,递归的复杂度就在于压栈会导致大量的变量需要存储,对我们的大脑来说负担太重,但是对计算机来说是小意思,相对来说算法层面往往很简单,所以我们一定要站在算法层面考虑问题,而不是递归层面。
&&& 下面来看我如何一步一步实现汉诺塔:(VS 2010 C# 控制台程序)&
class Program
static void Main(string[] args)
static void Move(int n, char a, char b, char c)
if (n & 1)
if (n == 1)
MoveTo(a, c);
//以下三句可能存在问题,只是为了快速思考,先写上,看着代码找感觉。
Move(n - 1, a, b, c);
MoveTo(a, c);
Move(n - 1, a, b, c);
private static void MoveTo(char a, char c)
throw new NotImplementedException();
&&& 凭着感觉直接写了个Move方法,第一个参数为盘子的个数,将所有盘子从 a 移动到 c。
&&& 第一个判断,防止错误的参数。
&&&&第二个判断,当n 等于1 时,也就是一个盘子,直接盘子从a移动到c上。
&&& 如果多余一个,将n-1个盘子从a移到b,再将最下面一个从a移动到c,最后从b上将n-1个盘子移动到c上。
//这三句肯定有问题的,只是为了快速把大脑里的想法写出看,看着来找感觉。
Move(n - 1, a, b, c);
//这句要实现将A座n-1的盘子移动到B上。
MoveTo(a, c);
//这句实现将A座最下面的一个盘子移动到C上
Move(n - 1, a, b, c);
//这句要实现将移动到B座的盘子在移动到C座上,这就OK了。
&&& 因为Move这个方法就是要把盘子从 a& 移动到&c,所以我们在递归调用时仅仅记住这个函数的这个功能就行了,这是一个函数的整体功能。
&&& 我们分别来讲解当N&1的3个步骤:
&&&& 第一步,讲 n-1 个盘子从 a 移动到 b 。把n-1盘子全部移动到 b 位置和 c 的方法是一样的,也就是算法是一样的。只是规模比原来少1。所以我们可以递归调用Move方法来解决将 n-1 个盘子从 a 移动到 b。 这时&b 就像相当于原来的c位置了,那么就这样调用&& Move(n-1, a, c, b).
&&&& 第二步,当 n-1 个盘子从 a 移动到 b 之后,a& 上就一个盘子,我们就可以直接将盘子移动到 c 上面。调用MoveTo(a, c)实现盘子的移动。在这一步,其实就是相当于移动只有一个盘子的情况,我们还可以递归调算法本身 Move(1, a, b, c);& 这样调用也是可以的。在执行完成后,a 位置上是空的, b 位置上有 n-1 个盘子, c 位置上有一个最大的盘子。
&&& 第三步,在第二步之后,我们只需要将 b 位置上的盘子都移动到 c 位置就可以了。这个和第一步类似,只是位置变了。 b 相当于原来的 a 位置(因为盘子在b上), a 位置相当于原来的 b 位置,因为移动到 c ,所以 c 还是相当于与原来的 c 位置。 语句调用这样写 Move(n - 1, b, a, c);
&&& 完善MoveTo方法,输出结果就好了。如果是图形移动,在这里写移动图形的方法即可。
private static void MoveTo(char from, char to)
Console.WriteLine(from + & -& & + to);
在Main函数中写代码测试一下:
Move(3, 'A', 'B', 'C');
Console.ReadKey();
运行一下没有问题。
将代码进行重构和调整:
class Program
static void Main(string[] args)
Hanor(4, &A&, &B&, &C&);
Console.ReadKey();
static void Hanor(int n, string platOne, string platTwo, string platThree)
if (n & 1)
if (n == 1)
MoveTo(platOne, platThree);
Hanor(n - 1, platOne, platThree, platTwo);
MoveTo(platOne, platThree);
Hanor(n - 1, platTwo, platOne, platThree);
private static void MoveTo(string a, string c)
Console.WriteLine(a + & -& & + c);
&&& 函数执行对不对,最好不要用大脑去测试,用电那运行测试,看看运行结果正常就OK了。如果好奇,感兴趣,或者测试一下大脑,可以自己绕一绕。
&&& 下面在举一个递归算法的例子,用于说明他递归算法的性能,代码如下:
static int Fun(int n)
if (n &= 1)
return Fun(n - 1) + Fun(n - 1);
&&&&这个函数的表示:当n&=1时, f(n) =1;当n&1时,f(n) = f(n-1) + f(n-1)
&&& 这个函数这样写性能会随n的增大成指数下降,汉诺塔的性能和这个是一样的。这都是算法导致的,对于这个问题,他会调用2的(n-1)次方次,但是改变一下解决问题的算法,那么情况会是怎样? f(n-1) +f(n-1) 其实相当于f(n-1)*2。如果算法改成这样,结果不会有任何问题,性能却非常高,函数被调用次数变为n次。所以算法才是对新能影响的关键。修改该后的代码如下:
static int Fun(int n)
if (n &= 1)
return Fun(n - 1) * 2;
&&& 在这里有一点要注意,可能有些人担心前后两个f(n-1)的结果可能不一样,其实这种担心是因为递归的原因。之前说了,在递归调用时要把函数作为整体来看待,当做一般的函数来看待。所以这里的结果肯定会是一样的。对于汉诺塔能不能也能不性能提升到这么高呢?这也在于算法,能不能提高性能在于能不能找到算法。
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:6668次
排名:千里之外
评论:19条
(1)(1)(2)(2)(1)人人网-抱歉,没有找到该网页
你输入的网址可能不正确,或者该网页不存在。&或者
北京千橡网景科技发展有限公司:
文网文[号··京公网安备号·甲测资字
文化部监督电子邮箱:wlwh@··
文明办网文明上网举报电话: 举报邮箱:&&&&&&&&&&&&谁明白递归算法_c++吧_百度贴吧
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&签到排名:今日本吧第个签到,本吧因你更精彩,明天继续来努力!
本吧签到人数:0成为超级会员,使用一键签到本月漏签0次!成为超级会员,赠送8张补签卡连续签到:天&&累计签到:天超级会员单次开通12个月以上,赠送连续签到卡3张
关注:144,806贴子:
谁明白递归算法收藏
求解析,求思路!
要理解递归,首先要理解递归
谁说的来着
Xinu Is Not Unix
int Same(int n){if(n)return Same(n-1)+1;return 0;}
GNU IS NOT UNIX
GNU's Not Unix.
求递归终点
throw new StackOverflowException();
我记得Hurd更好
throw new BrainOverflowException();
4L的例子摆着呢
while(new int){}
这个问题要问15L
递归就是自己执行自己,自己执行自己,自我反复嵌套,如果没有判断终止的话,其实就是个死循环...
多看点例程就好。
这点我明白,关键是喔不懂使用。
不用专门为了递归而去递归,到需要的时候自然会用到,像枚举ListCtrl控件的节点,到时候现百度就是。
写错了,应该是TreeCtrl........
登录百度帐号我的游戏推荐游戏
后查看最近玩过的游戏
为兴趣而生,贴吧更懂你。或}

我要回帖

更多关于 递归算法 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信