递归算法

2-路归并排序的非递归写法

亡梦爱人 提交于 2019-11-29 05:36:15
《算法笔记》中摘取 2-路归并排序的非递归写法主要考虑到这一点:每次分组时组内元素个数上线都是2的幂次。于是就可以想到这样的思路:令步长step的初值为2,然后减数组中每个step个元素作为一组,将其内部进行排序(即把左step / 2个元素与右step / 2个元素合并,而若元素个数不超过step / 2,则不操作);再令step 乘以 2,重复上面的操作,直到step / 2超过元素个数n。 const int maxn = 100; //将数组A的[L1, R1]与[L2, R2]区间合并为有序区间(此处L2记为R1 + 1) void merge(int A[], int L1, int R1, int L2, int R2) { int i = L1, j = L2; //i指向A[L1], j指向A[L2] int temp[maxn], index = 0; //temp临时存放合并后的数组,index为其下标 while(i <= R1 && j <= R2) { if(A[i] <= A[j]) { //如果A[i] <= A[j] temp[index++] = A[i++]; //将A[i]加入序列temp } else { //如果A[i] > A[j] temp[index++] = A[j++];//将A[j]加入序列temp } } while(i <

2-路归并排序的递归写法

ⅰ亾dé卋堺 提交于 2019-11-29 05:35:59
《算法笔记》中摘取 2-路归并排序的递归写法非常简单,只需要反复将当前区间[left, right]分为两半,对两个子区间[left, mid]与[mid +1, right]分别递归进行归并排序,然后将两个已经有序的合并为有序序列即可。 const int maxn = 100; //将数组A的[L1, R1]与[L2, R2]区间合并为有序区间(此处L2记为R1 + 1) void merge(int A[], int L1, int R1, int L2, int R2) { int i = L1, j = L2; //i指向A[L1], j指向A[L2] int temp[maxn], index = 0; //temp临时存放合并后的数组,index为其下标 while(i <= R1 && j <= R2) { if(A[i] <= A[j]) { //如果A[i] <= A[j] temp[index++] = A[i++]; //将A[i]加入序列temp } else { //如果A[i] > A[j] temp[index++] = A[j++];//将A[j]加入序列temp } } while(i <= R1) temp[index++] = A[i++]; //将[L1, R1]的剩余元素加入序列temp while(j <= R2) temp[index

全排列算法--递归&字典序实现(Java)

允我心安 提交于 2019-11-29 05:00:19
全排列算法-递归&字典序实现 全排列: 从n个不同元素中任取m(m≤n)个元素,按照一定的顺序排列起来,叫做从n个不同元素中取出m个元素的一个排列。当m=n时所有的排列情况叫全排列。 例如: 1 、2 、3三个元素的全排列为: {1,2,3},{1,3,2},{2,1,3},{2,3,1},{3,1,2},{3,2,1}。 解法1(递归) 如下图:要对1、2、3、4进行排序,第一个位置上的元素有四种可能:1或2或3或4,假如已经确定了第一个元素为4,剩下的第二个位置上可以是1、2、3,很显然这具有递归结构,如果原始要排列的数组顺序为1、2、3、4,现在只要分别交换1、2,1、3,1、4然后对剩下的3个元素进行递归的排列。 package com.xxx; /** * create by ziqiiii */ public class Test { static public void main(String[] args) { int[] a= {1,2,3}; permutation(a,0); } public static void permutation(int a[],int start ) { //如果已经到了数组的最后一个元素,前面的元素已经排好,输出。 if(start == a.length-1){ for(int i = 0;i < a.length; i++)

第八周学习总结

寵の児 提交于 2019-11-29 03:30:26
这周是暑期的最后一周,这周主要是pta作业的收尾工作,因为大多数题目是对字符串的处理,所以主要是学习了一些字符串的处理,比如处理位数过大的数字要进行加减乘除可以运用逻辑的方法,然后可以利用数组从而写出程序。然后这周还学习了一点算法,算是对数据结构有了一定认知,因为写了一个超时的程序,所以一定是算法有些繁琐,主要的原因就是递归的次数太多了,所以导致超时了,然后优化了一遍。然后对于uml还是不太理解,所以为了开学的测试还是要多看看。 来源: https://www.cnblogs.com/ljpljm/p/11443576.html

排序算法--归并排序法

孤人 提交于 2019-11-29 03:15:40
package com.maiya; import java.util.Arrays; /** * 排序算法--归并排序法 * 归并排序算法通过递归地平分值列,直至所有的子列都只有一个元素,然后按照次序 * 合并这些子列,从而实现对值列的排序。 * 归并排序算法的一般实现策略为:首先将值列分为大致相同的两个部分,然后递归地 * 对各个子列进行递归分解。重复对值列的递归分解过程,直至满足递归地基本条件, * 即值列按照定义的次序分解为多个只包含一个元素的子列。然后,在控制递归调用结 * 构,该算法将两次递归调用中产生的两个有序子列合并为一个有序子列。 * * @param nums 待排序数组 * @return 输出有序数组 * @author WHF */ public class Sort2 { // 归并排序的实现 public static void main(String[] args) { int[] nums = { 14, 7, 10, 5, 9, 1, 21, 3, 6, 15}; Sort2.sort(nums, 0, nums.length-1); System.out.println(Arrays.toString(nums)); } public static int[] sort(int[] nums, int low, int high) { int

浅谈对递归算法的理解……

妖精的绣舞 提交于 2019-11-29 00:52:54
递归: 所谓递归,就是既有传递,又有回归,与其说是传递与回归,初学不如理解是一种 “循序递进”与“规律约束”。 为什么这样说,因为递归算法相比较于循环在代码结构方面个人认为更加简洁清晰,清晰易懂,递归注重的是一种有序的规律,所以在每个程序开始之前,我们只要能找到一个使程序循序递进的规律;并且在整个过程都在用此规律进行传递,但是递归算法也有很大的缺点,会造成内存空间不足,从而形成内存溢出;所以针对这种缺点,就会引入“规律约束”,在每一次算法的的开始之前,先对算法进行一个规律约束,而这种约束可以理解为一个“归期”;即到这个归期不得已而为之…… eg:1 计算1+2+3+4+……+100的值。 function fn(n){ if(n==1)return 1; //归期 return n+fn(n-1); //规律 } console.log(fn(100)); eg:2 计算n 和 1/n!的阶乘。 1. n!function fn(n){ if(n==1)return 1; //归期 return n*fn(n-1); //规律 } console.log(fn(5));2. 1/n! function fn(n){ if(n==1)return 1; //归期 return 1/n*fn(n-1); //规律 } console.log(fn(5)); eg:3 斐波拉契数列

递归算法

孤街醉人 提交于 2019-11-29 00:35:37
fun(n) = f(n-t)+f(n-1); 需要验证下周期性。 其实,递归函数的工作过程就是自己调用自己。有一些问题用递归就很容易解决,简单的你自己都会吃惊。 我们做事情,一般都是从头开始的,而递归却是从末尾开始的。比如上面的函数吧,当n>3时,它显然只能求助于n-1,n-2。而(n-1)>2,(n-2)>2时,它们就求助于:(n-1)-1,(n-1)-2;(n-2)-1,(n-2)-2;然后··············直到(n-k)<3,(n-k-1)<3时,函数Febc终于有了返回值1 了,它再从头开始计算,然后一直算到n 为止。 通过上面的例子,我们知道递归一定要有一个停止的条件,否则递归就不知道停止了。在上面的例子中, if(n<3) return (1); 就是停止的条件。 然而,使用递归的代价是十分巨大的:它会消耗大量的内存!!递归循环时它用的是堆栈,而堆栈的资源是十分有限的。上面的例子你只能用一个很小的n值。如果n=20,即Febc(20)的话,它将调用Febc(n)函数10000多次!!!而上面一个例子用循环也是十分容易写的: /*using turboc2*/ int febc(int); main() { int n; scanf("%d",&n); febc(n); } int febc(int n) { int a[3],i; a[0]=a[1]=a[2

动态规划快速入门

不羁的心 提交于 2019-11-28 23:50:51
更多内容,欢迎关注微信公众号:全菜工程师小辉。公众号回复关键词,领取免费学习资料。 动态规划算法一直是面试手撕算法中比较有挑战的一种类型。很多的分配问题或者调度问题实际上都可能用动态规划进行解决。(当然,如果问题的规模较大,有时候会抽象模型使用动归来解决,有时候则可以通过不断迭代的概率算法解决查找次优解) 所以,动归很重要,至少算法思想很重要。 什么是动态规划? 通过把原问题分解为相对简单的子问题的方式求解复杂问题的方法。动态规划常常适用于有重叠子问题和最优子结构性质的问题。 最优子结构:当问题的最优解包含了其子问题的最优解时,称该问题具有最优子结构性质。 重叠子问题:在用递归算法自顶向下解问题时,每次产生的子问题并不总是新问题,有些子问题被反复计算多次。动态规划算法正是利用了这种子问题的重叠性质,对每一个子问题只解一次,而后将其解保存在一个表格中,在以后尽可能多地利用这些子问题的解。 不理解不用怕,结合后面题目来理解这些概念。这些概念完全是已经会动归的人来总结出来的,所以先理解动归,然后再来看这些文绉绉的概括。 分治与动态规划 共同点: 二者都要求原问题具有最优子结构性质,都是将原问题分而治之,分解成若干个规模较小(小到很容易解决)的子问题。然后将子问题的解合并,形成原问题的解。 不同点: 分治法将分解后的子问题看成相互独立的,通过用递归来做。

动态规划快速入门

不羁岁月 提交于 2019-11-28 23:49:11
更多内容,欢迎关注微信公众号:全菜工程师小辉。公众号回复关键词,领取免费学习资料。 动态规划算法一直是面试手撕算法中比较有挑战的一种类型。很多的分配问题或者调度问题实际上都可能用动态规划进行解决。(当然,如果问题的规模较大,有时候会抽象模型使用动归来解决,有时候则可以通过不断迭代的概率算法解决查找次优解) 所以,动归很重要,至少算法思想很重要。 什么是动态规划? 通过把原问题分解为相对简单的子问题的方式求解复杂问题的方法。动态规划常常适用于有重叠子问题和最优子结构性质的问题。 > 最优子结构:当问题的最优解包含了其子问题的最优解时,称该问题具有最优子结构性质。 > 重叠子问题:在用递归算法自顶向下解问题时,每次产生的子问题并不总是新问题,有些子问题被反复计算多次。动态规划算法正是利用了这种子问题的重叠性质,对每一个子问题只解一次,而后将其解保存在一个表格中,在以后尽可能多地利用这些子问题的解。 不理解不用怕,结合后面题目来理解这些概念。这些概念完全是已经会动归的人来总结出来的,所以先理解动归,然后再来看这些文绉绉的概括。 分治与动态规划 共同点: 二者都要求原问题具有最优子结构性质,都是将原问题分而治之,分解成若干个规模较小(小到很容易解决)的子问题。然后将子问题的解合并,形成原问题的解。 不同点: 分治法将分解后的子问题看成相互独立的,通过用递归来做。

经典递归java编写的算法

旧时模样 提交于 2019-11-28 19:55:52
1.斐波那契数列 生兔子 题目:古典问题:3个月起每个月都生一对兔子,小兔子长到第三个月后每个月又生一对兔子,假如兔子都不死,问每个月的兔子总数为多少? 分析:首先我们要明白题目的意思指的是每个月的兔子总对数;假设将兔子分为小中大三种,兔子从出生后三个月后每个月就会生出一对兔子, 那么我们假定第一个月的兔子为小兔子,第二个月为中兔子,第三个月之后就为大兔子,那么第一个月分别有1、0、0,第二个月分别为0、1、0, 第三个月分别为1、0、1,第四个月分别为,1、1、1,第五个月分别为2、1、2,第六个月分别为3、2、3,第七个月分别为5、3、5…… 兔子总数分别为:1、1、2、3、5、8、13…… 于是得出了一个规律,从第三个月起 , 后面的兔子总数都等于前面两个月的兔子总数之和,即为斐波那契数列。 public static void main(String[] args) { for(int i = 1;i<=12;i++){ System.out.println("第"+i+"个月兔子共"+f(i)+"对"); } } //递归方法 public static int f(int x){ if(x<3){ return 1; }else{ return f(x-1)+f(x-2); } } 来源: https://www.cnblogs.com/zxrxzw/p