递归加缓存
A. Hibernate加载树形结构的数据怎么用上二级缓存
public Menu getParent() {
return parent;
}
@OneToMany(cascade = CascadeType.REFRESH, fetch = FetchType.LAZY, mappedBy = "pid")
public Set<Menu> getChildren() {
return children;
}
这些数据由于很修改少,访问频繁,因此很适合放在缓存中。
下面是EhCache配置:
?
1
2
3
4
5
6
7
8
9
10
<cache name="Menu"
maxElementsInMemory="100"
eternal="false"
timeToIdleSeconds="120"
timeToLiveSeconds="120"
overflowToDisk="false"
diskPersistent="false"
="120"
memoryStoreEvictionPolicy="LRU"
/>
我在程序中用递归方式获得整个树形结构的数据,观察后台Hibernate输出的语句,一直都没使用上缓存。根据Hibernate使用缓存的机制:
1) Hibernate首先根据这些查询信息组成一个Query Key,Query Key包括条件查询的请求一般信息:SQL, SQL需要的参数,记录范围(起始位置rowStart,最大记录个数maxRows),等。 2) Hibernate根据这个Query Key到Query缓存中查找对应的结果列表。如果存在,那么返回这个结果列表;如果不存在,查询数据库,获取结果列表,把整个结果列表根据Query Key放入到Query缓存中。 3) Query Key中的SQL涉及到一些表名,如果这些表的任何数据发生修改、删除、增加等操作,这些相关的Query Key都要从缓存中清空。
B. java 用递归在字符串中重复出现的字符中添加一个*
Java中方法的概念以及递归(汉诺塔问题)
文章目录
Java中方法的概念以及递归(汉诺塔问题)
1、递归的概念
2、递归的练习
1)、汉诺塔问题
2)、青蛙跳台阶
3)、青蛙跳台阶(进阶)(递归->动态规划)
1、重载所能解决的问题
1、方法的概念
2、实参形参的关系
一、方法的基本使用
二、方法的重载
三、递归的概念
能够使代码模块化,使代码的结构更加清晰。
当重复使用一个功能(代码)时,只需要写出方法名进行调用,避免相同代码重复累赘。
让代码更好理解更简单。
- public class Main { public static void main(String[] args) { int a = 10; int b = 20; int c = add(a, b); //在main方法中,直接调用其他方法,必须为static的方法 } public static int add(int num1, int num2) { return num1 + num2; }}
方法名相同
方法的参数不同。(形参类型不同,个数不同)
方法的返回值类型不影响重载
- public class Main { public static void main(String[] args) { int n = 5; //求5的阶乘 System.out.println(fact(n)); } public static int fact (int n) { if (n == 1) { //递归结束的条件 return 1; } return n * fact(n - 1); //例如5! = 5 * 4! -》 5 * 4 * 3! ,一直递归到1的阶乘,就结束 }}
先将N - 1层移动到mid柱子,给最下面那一层让路。
N - 1层移开之后,路就让出来了。此时移动第N层圆盘即可。
此时第一步移动的 N- 1层圆盘 还在mid柱子上,现在就是从 mid柱子 移动到 right柱子上。
- public class Main { public static void main(String[] args) { //汉诺塔 int n = 3; hanoiTower(n, "left", "right", "mid"); } public static void hanoiTower(int n, String from, String to, String mid) { if (n == 1) { System.out.println("move 1 from " + from + " to " + to); return; //记得返回,终止递归 } hanoiTower(n - 1, from, mid, to); //图1 -> 图2 System.out.println("move " + n + " from " + from + " to " + to); //图2 -> 图3 hanoiTower(n - 1, mid, to, from); //图3 -> 图4 }}
- public class Main { public static void main(String[] args) { int n = 3; //台阶数 System.out.println(jumpFloor(n)); } public int jumpFloor(int target) { if (target == 1) { //情况一 return 1; } if (target == 2) { //情况二 return 2; } return jumpFloor(target - 1) + jumpFloor(target - 2); //情况三 }}
- public class Main { public static void main(String[] args) { int n = 3; //假设就是3层台阶 System.out.println(frogJumpPlus(n)); } public static int frogJumpPlus(int n) { if (n == 1) { return 1; } if (n == 2) { return 2; } int res = 1; //当前,需要选择一种的跳法 //此处的for循环,就是去尝试,跳1步、2步、3步……一直跳到n层台阶,将这些情况全部加起来,就是当前的结果 for (int i = 1; i < n; i++) { res += frogJumpPlus(n - i); //i控制台阶数,每次循环,都减一步台阶。去递归所有的台阶 } return res; }}
- public class Main { public static void main(String[] args) { int n = 3; //假设就是3层台阶 System.out.println(frogJumpPlus(n)); } public static int frogJumpPlus(int n) { if (n == 1) { return 1; } int[] dp = new int[n + 1]; dp[1] = 1; dp[2] = 2; for (int i = 3; i <= n; i++) { dp[i] = 1; //加上自己需要跳的这一步 for (int j = 1; j < i; j++) { dp[i] += dp[j]; //把前面所有数据,累加一遍,就是当前台阶的跳法 } } return dp[n]; }}
一、方法的基本使用
1、方法的概念
Java语言中的“方法”(Method)在其他语言当中也可能被称为“函数”(Function)。
对于一些复杂的代码逻辑,如果希望重复使用这些代码,并且做到“随时任意使用”,那么就可以将这些代码放在一个大括号“{}”当中,并且起一个名字。使用代码的时候,直接找到名字调用即可。
方法存在的意义:
接下来看方法的结构:
访问修饰限定符:自由选择,告诉编译器如何调用该方法。定义了该方法的访问类型。
**静态static:**当调用的主函数是static时,被调用的函数需要为static的。例如:java中,main方法直接调用add方法。此时的add方法需要static修饰。
返回值类型:方法可能会返回值。return Value Type 是方法返回值的数据类型。有些方法执行所需的操作,但没有返回值。在这种情况下,return Value Type 是关键字void。
参数类型:参数像是一个占位符。当方法被调用时,传递值给参数。这个值被称为实参或变量。参数列表是指方法的参数类型、顺序和参数的个数。参数是可选的,方法可以不包含任何参数。
方法名(函数名):是方法的实际名称。方法名和参数表共同构成方法签名。
方法体:方法体包含具体的语句,定义该方法的功能。
2、实参形参的关系
实参:在方法中,实际传递的数值就是实际参数。比如上面的main函数中, int c = add(a, b); 这里的a和b就是实际参数,称为实参。
形参:在被调用的方法里,由实参传递过来的数值,就称为形式参数。形参是实参的一份临时拷贝。也就是说,main函数传递的a和b,与add方法中的a和b,虽然都是10和20(上面代码中),但是二者并不是来自同一块内存空间:如下图所示:
二、方法的重载
1、重载所能解决的问题
在我们平常写代码中,少不了数据的加减乘除。也少不了对不同类型的数据进行四则运算。假设:我们就写了上面的代码(add方法),我们用浮点数(小数)调用add方法,会有什么情况发生?
此时大家就会想,我重新写一个double类型的方法不就行了吗。
没错,就是再次写一个double类型的add就行啦。在C语言中,我们写的函数(方法),不能够写重命的。比如,我写两个add的函数。函数名就是叫add。一模一样,在C语言中是不允许的。
但是在java中,这是可以。也就是这节所讲的 方法重载。
根据形参的类型和形参的个数,去寻找被调用的方法。
上面的代码,分别调用了add方法,虽然都叫add。但是形参类型不一样。所以是两个不同的方法。这就叫重载。
重载的规则
注:当方法的方法名相同,参数相同,但返回值类型不同的时候,这不构成重载。
三、递归的概念
1、递归的概念
一个方法在自己调用自己时,就称为“递归”。
当一个大问题,是由若干个小问题,并且这些小问题的解决方法,都是一样的。这样的问题,很大可能就能用递归去解决。
递归相当于数学上的**“数学归纳法**”,有一个起始条件, 然后有一个递推公式
例如,我们求N!
起始条件: N= 1的时候, N!为1. 这个起始条件相当于递归的结束条件.
递归公式:求N!,直接不好求,可以把问题转换成N!=> N * (N-1)!
例如代码:
2、递归的练习
1)、汉诺塔问题
汉诺塔游戏(7K7K小游戏链接)。在开始讲解之前,大家还是先去玩一玩汉诺塔游戏,看看是什么规则。更容易的理解下面的代码。
牛客网OJ题链接
汉诺塔游戏规则:
现有三根柱子,我们分别叫left, mid,right。现在有3个圆盘left柱子上,3个圆盘的大小关系为:从上往下,圆盘越来越大。
每次只能取出一个圆盘,并且圆盘在取和放的时候,必须在这三根柱子上完成。不能取出来放到其他地方。
且,大的圆盘不能放到小的圆盘上。
问,怎么移动圆盘,让圆盘从left柱子,移动到right柱子上。
情况一:我们先从1个圆盘举例说明, 我们直接从left柱,移动到right柱即可
情况二:2个圆盘的情况
情况三:3个圆盘的情况
这就是大致的思路:
不要去深究每一步的细节,抓好大致的思路,确定好递归终止的条件。宏观的去想这个问题,就能够很好地抓到问题的本质。
2)、青蛙跳台阶
青蛙跳台阶 OJ题链接
情况一:一步台阶只能跳一次,就跳完了;1种
情况二:两步台阶题意是,青蛙一次可以跳一步台阶,也可以跳两步台阶。所以情况二的跳法是2 种
情况三:三步台阶
现在摆在我面前的问题就是。我要么跳一步台阶。我要么跳两步台阶。
不对,是摆在青蛙面前的问题!!!口误口误!
假设1:青蛙跳一步台阶后,还剩两个台阶没跳。此时是不是又回到了两层台阶的决策问题(上文情况二);
假设2:青蛙跳两步台阶后,还剩一个台阶没跳。此时是不是又回到了一层台阶的决策问题(上文情况一);
我们把这两种情况的假设,结果加起来,就是三层台阶的所有跳法了!!!
再往下,四层、五层……,推导的思路,不就展开了嘛
3)、青蛙跳台阶(进阶)(递归->动态规划)
青蛙跳台阶(进阶)OJ链接
看完题目,各位有什么感想???
是不是跟初级的,区别不是很大?递归终止的条件还是一步台阶和两步台阶的情况。
情况一和情况二的情况,我们就不说了,跟上文初阶的一模一样。还是1种跳法和2种跳法;我们重点来看一下三层台阶的情况。
情况三:三层台阶
三层台阶:也就是说青蛙一次可以跳到3层台阶。弹跳力见涨啊!(注意:并不是说,青蛙就一次只能跳3层台阶,题意是(1 ……n层中 ,每一层 它都可以一次跳过)。
假设青蛙一次最大跳三层:
假设一:青蛙第一次跳一层台阶,还剩两个台阶没跳 ->两层台阶的决策问题。
假设二:青蛙第一次跳两层台阶,还剩一个台阶没跳 ->一层台阶的决策问题。
假设三:青蛙第一次跳三层台阶,没有台阶跳了 ->0层台阶的决策问题。
那如果是四层台阶 五层台阶 N层台阶呢? 那是不是有几层,就有几种假设情况?那就需要相加!!!来看这个题的代码:
上面的代码,就是经典的递归方式,去解这个题。
其实,在台阶数足够大时,这样的递归,会有很多的重复计算:比如:
计算5层台阶时:
假设一:第一次跳一层台阶,第二次跳一层台阶。此时还剩三层台阶。 ->三层台阶决策问题。
假设二:第一次跳两层台阶,此时还剩下三层台阶。 ->三层台阶决策问题。
此时我们就发现了,上面两种假设就会产生重复计算。我们此时就想,有没有一种方法,让我们只计算一次,就能解决重复计算的问题。
那就是加缓存,我们用一块空间,来保存每次计算的结果,当我们需要的时候,直接从内存空间里面拿就行。
暴力递归 -> 动态规划:
对比两种方法:
我们画出前面几组数据,就能找出规律:
可能你就会疑惑,我写不出来这动态规划。那可以先写递归的版本。在递归的版本上去修改,加缓存。
具体是以什么形式来缓存,还得看你的可变参数,例如这个题的可变参数就只有一个n,也就是台阶数。那我们就开辟一维数组,就能解决。
那如果是两个可变参数,那么此时就可能需要二维数组来做缓存了!!!
总之,像这种考察递归的题目。我们都可以加缓存的形式。到底需不需要加缓存,我们就得看看,递归的时候,是否涉及了大量的重复计算。
最后考考大家,上面写的动态规划的版本,是否还可以优化呢???(提示一下: 两层for循环,时间复杂度O(N2))
好啦,本期更新就到此结束了,我们下期见!!!
,https://blog.csdn.net/x0919/article/details/119279165
C. 怎么列动态规划递推方程
动态规划中递推式的求解方法不是动态规划的本质。我曾经作为省队成员参加过NOI,保送之后也给学校参加NOIP的同学多次讲过动态规划,我试着讲一下我理解的动态规划,争取深入浅出。希望你看了我的答案,能够喜欢上动态规划。0.动态规划的本质,是对问题状态的定义和状态转移方程的定义。引自维基网络.动态规划是通过拆分问题,定义问题状态和状态之间的关系,使得问题能够以递推(或者说分治)的方式去解决。本题下的其他答案,大多都是在说递推的求解方法,但如何拆分问题,才是动态规划的核心。而拆分问题,靠的就是状态的定义和状态转移方程的定义。1.什么是状态的定义?首先想说大家千万不要被下面的数学式吓到,这里只涉及到了函数相关的知识。我们先来看一个动态规划的教学必备题:给定一个数列,长度为N,求这个数列的最长上升(递增)子数列(LIS)的长度.以172834为例。这个数列的最长递增子数列是1234,长度为4;次长的长度为3,包括178;123等.要解决这个问题,我们首先要定义这个问题和这个问题的子问题。有人可能会问了,题目都已经在这了,我们还需定义这个问题吗?需要,原因就是这个问题在字面上看,找不出子问题,而没有子问题,这个题目就没法解决。所以我们来重新定义这个问题:给定一个数列,长度为N,设为:以数列中第k项结尾的最长递增子序列的长度.求中的最大值.显然,这个新问题与原问题等价。而对于来讲,都是的子问题:因为以第k项结尾的最长递增子序列(下称LIS),包含着以第中某项结尾的LIS。上述的新问题也可以叫做状态,定义中的“为数列中第k项结尾的LIS的长度”,就叫做对状态的定义。之所以把做“状态”而不是“问题”,一是因为避免跟原问题中“问题”混淆,二是因为这个新问题是数学化定义的。对状态的定义只有一种吗?当然不是。我们甚至可以二维的,以完全不同的视角定义这个问题:给定一个数列,长度为N,设为:在前i项中的,长度为k的最长递增子序列中,最后一位的最小值..若在前i项中,不存在长度为k的最长递增子序列,则为正无穷.求最大的x,使得不为正无穷。这个新定义与原问题的等价性也不难证明,请读者体会一下。上述的就是状态,定义中的“为:在前i项中,长度为k的最长递增子序列中,最后一位的最小值”就是对状态的定义。2.什么是状态转移方程?上述状态定义好之后,状态和状态之间的关系式,就叫做状态转移方程。比如,对于LIS问题,我们的第一种定义:设为:以数列中第k项结尾的最长递增子序列的长度.设A为题中数列,状态转移方程为:(根据状态定义导出边界情况)用文字解释一下是:以第k项结尾的LIS的长度是:保证第i项比第k项小的情况下,以第i项结尾的LIS长度加一的最大值,取遍i的所有值(i小于k)。第二种定义:设为:在数列前i项中,长度为k的递增子序列中,最后一位的最小值设A为题中数列,状态转移方程为:若则否则:(边界情况需要分类讨论较多,在此不列出,需要根据状态定义导出边界情况。)大家套着定义读一下公式就可以了,应该不难理解,就是有点绕。这里可以看出,这里的状态转移方程,就是定义了问题和子问题之间的关系。可以看出,状态转移方程就是带有条件的递推式。3.动态规划迷思本题下其他用户的回答跟动态规划都有或多或少的联系,我也讲一下与本答案的联系。a.“缓存”,“重叠子问题”,“记忆化”:这三个名词,都是在阐述递推式求解的技巧。以Fibonacci数列为例,计算第100项的时候,需要计算第99项和98项;在计算第101项的时候,需要第100项和第99项,这时候你还需要重新计算第99项吗?不需要,你只需要在第一次计算的时候把它记下来就可以了。上述的需要再次计算的“第99项”,就叫“重叠子问题”。如果没有计算过,就按照递推式计算,如果计算过,直接使用,就像“缓存”一样,这种方法,叫做“记忆化”,这是递推式求解的技巧。这种技巧,通俗的说叫“花费空间来节省时间”。都不是动态规划的本质,不是动态规划的核心。b.“递归”:递归是递推式求解的方法,连技巧都算不上。c."无后效性",“最优子结构”:上述的状态转移方程中,等式右边不会用到下标大于左边i或者k的值,这是"无后效性"的通俗上的数学定义,符合这种定义的状态定义,我们可以说它具有“最优子结构”的性质,在动态规划中我们要做的,就是找到这种“最优子结构”。在对状态和状态转移方程的定义过程中,满足“最优子结构”是一个隐含的条件(否则根本定义不出来)。对状态和“最优子结构”的关系的进一步解释,什么是动态规划?动态规划的意义是什么?-王勐的回答写的很好,大家可以去读一下。需要注意的是,一个问题可能有多种不同的状态定义和状态转移方程定义,存在一个有后效性的定义,不代表该问题不适用动态规划。这也是其他几个答案中出现的逻辑误区:动态规划方法要寻找符合“最优子结构“的状态和状态转移方程的定义,在找到之后,这个问题就可以以“记忆化地求解递推式”的方法来解决。而寻找到的定义,才是动态规划的本质。有位答主说:分治在求解每个子问题的时候,都要进行一遍计算动态规划则存储了子问题的结果,查表时间为常数这就像说多加辣椒的菜就叫川菜,多加酱油的菜就叫鲁菜一样,是存在误解的。文艺的说,动态规划是寻找一种对问题的观察角度,让问题能够以递推(或者说分治)的方式去解决。寻找看问题的角度,才是动态规划中最耀眼的宝石!(大雾)
D. 缓存,递归,授权dns的统一和分离部署的区别
系统linux简单使用dnsmasq用yum或者apt-get装使用 vi打/etc/dnsmasq.conf配置文件拉使用 server=ip 式添加级服务器用途用避免dns污染其实能流量经际口遇dns抢答
windowsserver其实自带dns服务器工具通服务器管理器启用
E. 一个关于递归的问题C#,代码如下
class Program //这句不用说吧
{
static void Main(string[] args) //这句也是,命令行入口,不多说
{
Program pr = new Program(); //新建Porgram类pr,实例化。
pr.Count(3); //总次数三次
Console.ReadKey(); //等待按键结束
}
public void Count(int inVal) //函数Count ,依据参数倒序显示,比如输入5,那
{ 么显示5,4,3,2,1
if (inVal == 0) //如果参数为0,则返回,程序不再执行
{
return;
}
Count(inVal - 1); //每次减1
Console.WriteLine("{0}",inVal); //输出显示
}
}
F. 路由器的递归查询怎样解释
什么是路由? 所谓路由的过程就是从入站接口接收到数据包,经过CPU的处理(查找路由表,重构二层帧),把“新”包放入到相应的接口的过程。这个过程实际上可以 转化成下面的一个模型:一辆汽车(数据包)走到了一个十字路口,注意,此时它是有目的地的(目的IP地址),比如这辆汽车想去往北京,到了这个十字路口, 看到了有几个牌子上面写着“北京,石家庄,唐山”,那么这个时候驾驶员(CPU)就应该来选择那个去往北京的路口(出站接口),这样也就完成了路由功能。更进一步,微观上的路由查询是怎么进行的。这里所说的微观,并不去讨论路由转发的各种算法,而是去讨论路由器如何去查找路由表。我们先来看一个简单的拓扑
有四个路由器,分别是POOH,TIGGER,PIDET,RABBIT,在这个拓扑下面显示的是POOH的路由表,可以看到,现在已经可以从POOH上查询到了五个网段,也就是说现在达到了全网互通。
举 例来说,如果想达到网段10.1.10.0,CPU开始查找路由表,发现了一个路由条目是到达10.1.10.0的,通过192.168.1.194,而 这个地址就是piglet路由器最左边的那个端口,那么这个192.168.1.194又是怎么到达呢?再一次查找路由表,找到了一个网段 192.168.1.192,这里面就包含了192.168.1.194这个地址,而到达它是通过192.168.1.66来实现的。那么 192.168.1.66又是应该怎么到达?还得继续查找路由表。192.168.1.194
这个过程在周而复始的进行,形成一个递归的过程,知道路由器找到直连网段位置,按照上面的那个实例来说就是当找到192.168.1.64这个条目。
好了,这就是路由器递归查询的过程。
但是,这样的查询方法有什么用途呢?你是否考虑过呢?
先让我们回到一个比较本质的问题上去,路由器和交换机的作用是什么?其实无非是两个作用,一是考虑如何把数据包正确的送到目的地址,二是如何更快的送到。 至于其他的各种安全技术,QoS等等都是为这两个终极目标服务的。由于本篇不涉及到交换机的内容所以在此略过不提,单说路由器,工程师们为了让路由器更好的完成这两个任务做出了不懈的努力,其中一个就是不断改进的包交换方法以达到快速的转发包的目的。
先让我们从历史的角度看一下
最早诞生的是“进程交换”
这种交换很传统,路由器每收到一个包就会通过CPU查找路由表然后送到出站端口,每过来一个包就会这样做一次。这种方法是没有问题的,但是却很慢,明显的效率不高。
为了解决这个问题,“快速交换”诞生了
这 里面有一个前提,也是能开发出“快速交换”的一个先提条件,那就是我们的数据一般都是以流的形式传播的,流,这个词十分形象,就是一串数据包都去往同一个 地方。当工程师发现了这个规律之后,“快速交换”的想法诞生了,所谓快速交换就是,先分析每个流的第一个包,按照进程交换的方式进行查询,然后出站同时把 这个查询的结果保存在一个独立的缓存中。当这个流中剩下的包进站时,路由器不是去查路由表而是去查缓存,这样就能节省CPU的资源,直接把包转发出去。这 样不但提高了包转发的速度,实际上也提高了CPU的使用效率。
最后就是CEF
思科的快速交换,CEF有太多的内容需要讲,相对于前两种交换方式有很大的不同,我在这里只取其在交换形式上的差别。进程交换是当一个新数据流来了后路由第一个包,然后把信息记入缓存来对转发进行加速。而CEF的做法更绝!
连第一个包都不用查了,直接进行缓存操作!而且是在包之前就进行了缓存。
也就是大名鼎鼎的FIB表。
当一个数据包入站的时候,直接查询FIB表而不是路由表,这样就能大大增加转发的速度。
也 许你有疑问,我当初就是有疑问的,本来有好好的路由表,现在又建立了一个FIB表,一个数据包到了不还是需要查找吗?这样有什么作用?很显然现在一般的图 书上并没有写明原因,没有给我一个合理的解释。不过对于这个问题,以及对于CEF的专题讨论我会在下周的时候单独写一篇文章来叙述,让你明白CEF!
现在让我们尊重一个事实,CEF更快!
我用了大量的篇幅来写看似与本篇主题无关的“路由器交换”,我想告诉大家的是“加快交换,远离路由表”,CPU路由查询的次数越少转发的效率越高!
那么现在让我们回到本篇文章的主题“递归路由的查询”,强烈的困惑!人家查一次路由表都嫌多,你却使用递归查询查了那么多遍路由表!
确实,这就是递归查询的最大缺点!也是我们在设计网络的时候必须要考虑的一个问题。不过仔细想一下,既然这是一个极为“不成功”的方法,那么为什么还会允许它的存在呢?这又是为了什么?
递归查询的优势!无与伦比的优势!
我们来看一下这个拓扑,注意一下SANDERZ的静态路由的设计。
这就是一个典型的递归路由的使用案例,可以仔细的看一下。
这里我们先设计一个情景,从显示的路由路由信息来看,现在到达右侧网段的所有数据都要从HEFFALUMP路由器通过,这个时候如果HEFFALUMP坏了,那么必须要从WOOZLE进行路由。
这个时候网络管理员只需要调整一条路由就可以了。
Sanderz(config)# ip route 10.87.14.0 255.255.255.0 10.23.5.95
Sanderz(config)# no ip route 10.87.14.0 255.255.255.0 10.23.5.20
这样就完成了任务。
那么如果不使用递归路由呢?那么图中的每一个路由都要重新设置,如果按照上图的案例来说,我们需要重新写26条路由条目。如果你觉得这样的数量还能忍受, 那么如果有100个,400个网段呢?你要重写200条,800条路由!这个工作量就大了吧,你还能忍受吗?同样是400个网段,使用递归路由还是上面的 两条命令。
借用并改造算法中时间复杂度的概念:不使用递归路由的时间复杂度为O(n),而使用了递归路由的时间复杂度为O(1)!
这也就是递归路由最大的优点!
面对递归路由的优点与缺点,确实是很难办,是需要斟酌的。(这是《ROUTING TCP/IP VOL.1 》的说法)
不过我想其实并不是那么“难办”
从实际的网络应用来讲,现在能够使用静态路由的网络拓扑不会很大,相对于路由器CPU的处理能力来讲不是很大的负担,也就不会很影响速度,所以为了管理的方便我们是可以放心的使用递归路由的。
但是,我这种说法并不包含 两个大的园区网之间用静态路由的情况(教育网),这样的情况还是使用最普通的路有方式吧。
具体情况具体分析,相必大家对与递归路由的优势和缺点也是很熟悉了,能够在其间取舍。
G. dns中递归查询与迭代查询的区别
两者区别如下:
递归是用户只向本地DNS服务器发出请求,然后等待肯定或否定答案。而迭代是本地服务器向根DNS服务器发出请求,而根DNS服务器只是给出下一级DNS服务器的地址,然后本地DNS服务器再向下一级DNS发送查询请求直至得到最终答案。
H. 递归的时候内存溢出一般用什么方法解决
递归终止条件,一般有多种方式:
1. 添加递归深度参数到递归函数的参数中
每次调用深度加一,在函数体中添加条件语句,当深度超过某个值时强行return;
2. 引入元素栈结构,每次递归的一些需要记录的内容,通常会压入栈中,适当的时候再弹出
在函数体中,添加条件语句,判断栈大小或者栈元素,达到条件时进行return;
I. 什么是递归程序递归程序的优缺点是什么
递归程序是指在计算机科学中是指一种通过重复将问题分解为同类的子问题而解决问题的程序。递归式方法可以被用于解决很多的计算机科学问题,因此它是计算机科学中十分重要的一个概念。满足使用递归的条件:
子问题为同类事物,且更简单
必须有个出口
代码简洁
符合思维习惯,容易理解
效率较低
递归层次太深,耗内存且容易栈溢出一定要使用的话,最好使用缓存避免相同的计算,限制递归调用的次数
优点:
缺点:
J. “递归”和“迭代”有什么区别
“递归”和“迭代”的区别如下:
1、递归的基本概念:程序调用自身的编程技巧称为递归,是函数自己调用自己.一个函数在其定义中直接或间接调用自身的一种方法,它通常把一个大型的复杂的问题转化为一个与原问题相似的规模较小的问题来解决,可以极大的减少代码量.递归的能力在于用有限的语句来定义对象的无限集合。