递归算法

快速排序的递归非递归

匿名 (未验证) 提交于 2019-12-03 00:27:02
快速排序: 即一趟快速排序的过程,返回基准。基准:平分数据段 时间复杂度:好情况(无序的数据):O(nlog2n) 坏(有序):O(n2) 空间复杂度:O(log2n) 算法稳定性:不稳定 原理:采用分治思想,在待排序的序列中选取一个值作为一个基准值,按照这个基准值得大小将这个序列划分成两个子序列,基准值会在这两个子序列的中间,一边是比基准小的,另一边就是比基准大的。这样快速排序第一次排完,我们选取的这个基准值就会出现在它该出现的位置上。这就是快速排序的单趟算法,也就是完成了一次快速排序。然后再对这两个子序列按照同样的方法进行排序,直到只剩下一个元素或者没有元素的时候就停止,这时候所有的元素都出现在了该出现的位置上。 例:一趟排序(以6为基准) 0 1 2 3 4 5 arr[]: 6 2 7 3 8 9 low=0 high=5 tmp=6 6 2 7 3 8 9 low=0 high=3 tmp=6 arr[high]=3 < tmp=6 3 2 7 6 8 9 low=0 high=3 tmp=6 arr[low]=arr[high]3 3 2 7 6 8 9 low=2 high=3 tmp=6 arr[low]=7 > tmp=6 3 2 6 7 8 9 low=2 high=3 tmp=6 arr[high]=arr[low]7 6的位置已确定 //递归 int

蓝桥杯之VIP试题 FJ的字符串

匿名 (未验证) 提交于 2019-12-03 00:22:01
问题描述   FJ在沙盘上写了这样一些字符串:   A1 = “A”   A2 = “ABA”   A3 = “ABACABA”   A4 = “ABACABADABACABA”   … …   你能找出其中的规律并写所有的数列AN吗? 输入格式   仅有一个数:N ≤ 26。 输出格式   请输出相应的字符串AN,以一个换行符结束。输出中不得含有多余的空格或换行、回车符。 样例输入 3 样例输出 ABACABA import java.util.Scanner; public class Main { public static void main (String[] args) { Scanner in = new Scanner(System. in ); // 输入行数n int n = in .nextInt(); // 通过递归算法,获得AN字符串 System. out .println(getAN(n)); } //写递归时,从简单的入手,把模型打出来,再带入更多的数进去验算;自己要知道递归的最底层的结果是什么; //递归的下一层会带有递归的上一层的结果,例如: // A1 = “A” // A2 = “ABA” // A3 = “ABACABA” // 递归是独立的一个方法,用到return;通常第一层的结果就是递归最底层的结果。 private static

算法作业-整数划分-递归

匿名 (未验证) 提交于 2019-12-03 00:22:01
正整数的划分问题是将一个正整数n表示成一系列正整数之和:n=n1+n2+…+nk,其中n1≥n2≥…≥nk≥1,k≥1。请编写至少三种不同的求解算法,并对所编写算法的时间效率进行测试和比较。 解法一:递归算法 考虑增加一个自变量:将最大加数n1不大于m的划分个数记作q(n,m),可以建立q(n,m)的如下递归关系: 1,q(n,1) = 1, n≥1; 当最大加数n1不大于1时,任何正整数n只有一种划分形式,即n=1+1+…+1 2,q(n,m) = q(n,n), m≥n; 最大加数n1实际上不能大于n,因此,q(1,m) = 1 3,q(n,n) = 1 + q(n, n-1); 正整数n的划分由n1 = n的划分和n1≤n-1的划分组成 4,q(n,m)=q(n,m-1)+q(n-m,m),n>m>1; 正整数n的最大加数n1不大于m的划分由n1= m的划分和n1≤m-1 的划分组成 正整数n的划分数p(n)=q(n,n)。 算法如下: Java代码如下: package integer_division; public class Integer_division_1 { public static void main(String[] args) { // TODO Auto-generated method stub long startTime = System

数据结构之空间复杂度和空间复杂度

匿名 (未验证) 提交于 2019-12-03 00:22:01
空间复杂度是指 执行这个算法所需要的内存空间。 空间复杂度是函数中创建对象的个数关于问题规模函数表达式,一般情况下用O渐进表示法表示 1.忽略常数,用O(1)表示 2.递归算法的空间复杂度=递归深度*每次递归所要的辅助空间 3.对于单线程来说,递归有运行时堆栈,求的是递归最深的那一次压栈所耗费的空间的个数,因为递归最深的那一次所耗费空间足以容纳它所有递归过程。递归是要返回上一层的,所以它所需要的空间不是一直累加起来的。 时间复杂度是指 执行这个算法所需要的计算工作量。 1.用常数1取代运行时间中的所有加法常数 2.在修改后的运行次数函数中,只保留最高阶项 3.如果最高阶项系数存在且不是1,则去除与这个项相乘的常数 void Test( int n) { int iCount = 0 ; for ( int iIdx = 0 ; iIdx < 10 ; ++iIdx) { iCount++; } } //执行总次数:f(n)=10 + 1 //则O(n)=O(1) int Jie_Cheng( int n) { if (n < 2 ) return 1 ; else int i = n; int tmp = Jie_Cheng(n - 1 ); return n * tmp; } //每次递归次数:2 //递归总次数:n //2*n 所以O(n)=O(n) 文章来源:

图解汉诺塔问题(递归求解)

匿名 (未验证) 提交于 2019-12-03 00:21:02
汉诺塔: 单看这个问题描述有点让人抓瞎,这是当然,无论多么简单的问题描述,在没有建立具体地模型之前都是让人不知所云的,仅仅用生活中的语言去描述一些数学或算法问题往往会让听者产生理解偏差, 这也和每个的理解能力和思维方式有很大关系,这就显示出数学的强大了,数学让问题不再模糊,参数和公式组成的模型让问题不再有理解偏差和误区,只可惜数学没学好,看来以后还得回来把高数、概率论这些给补回来。 说了一些题外话,下面来对汉诺塔问题进行解释和建立模型 下面我用图来描述64个盘子的转移流程 using System; using System.Collections.Generic; namespace 汉诺塔问题_递归解决 { class Program { static void Main(string[] args) { HanNuo(64, 'a', 'b', 'c'); Console.ReadKey(); } /// <summary> /// 汉诺塔问题解决方法 /// </summary> /// <param name="n">汉诺塔的层数</param> /// <param name="a">承载最初圆盘的柱子</param> /// <param name="b">起到中转作用的柱子</param> /// <param name="c">移动到的目标柱子</param>

Fibonacci数列一般方法以及递归调用

匿名 (未验证) 提交于 2019-12-03 00:19:01
一般算法 一般方法 package edu.xatu; import java.util.Scanner ; public class Fibonaci { public static void main(String[] args ) { //求斐波那契 int [] a = new int [10]; for ( int i =0; i < a . length ; i ++) { if ( i <=1) { a [ i ] = 1; } else { a [ i ] = a [ i -1] + a [ i -2]; } } for ( int i =0; i < a . length ; i ++) { System. out .print( a [ i ]+ " " ); } } } 运行结果: 递归调用方法 import java.util.Scanner; public class Fibonacci { //递归调用,n为第n个数 public static int fabonacci( int n ) { if ( n <=1) return 1; return fabonacci ( n -1)+ fabonacci ( n -2); } public static void main(String[] args ) { Scanner s = new

递归算法讲解

匿名 (未验证) 提交于 2019-12-03 00:19:01
一. 引子    大师 L. Peter Deutsch 说过:To Iterate is Human, to Recurse, Divine.中文译为:人理解迭代,神理解递归。毋庸置疑地,递归确实是一个奇妙的思维方式。对一些简单的递归问题,我们总是惊叹于递归描述问题的能力和编写代码的简洁,但要想真正领悟递归的精髓、灵活地运用递归思想来解决问题却并不是一件容易的事情。在正式介绍递归之前,我们首先引用知乎用户李继刚( https://www.zhihu.com/question/20507130/answer/15551917 )对递归和循环的生动解释:    递归:你打开面前这扇门,看到屋里面还有一扇门。你走过去,发现手中的钥匙还可以打开它,你推开门,发现里面还有一扇门,你继续打开它。若干次之后,你打开面前的门后,发现只有一间屋子,没有门了。然后,你开始原路返回,每走回一间屋子,你数一次,走到入口的时候,你可以回答出你到底用这你把钥匙打开了几扇门。    循环:你打开面前这扇门,看到屋里面还有一扇门。你走过去,发现手中的钥匙还可以打开它,你推开门,发现里面还有一扇门(若前面两扇门都一样,那么这扇门和前两扇门也一样;如果第二扇门比第一扇门小,那么这扇门也比第二扇门小,你继续打开这扇门,一直这样继续下去直到打开所有的门。但是,入口处的人始终等不到你回去告诉他答案。   

算法第二章作业

匿名 (未验证) 提交于 2019-12-03 00:13:02
在这一年的打题过程中,从最开始的手敲冒泡排序到现在一直用STL里的sort,排序算法使用的频率可以说是非常高的了,而且各种排序算法的思想和有关的一些数据结构也会经常用到,但之前一直听说sort是基于快排的,就会有疑问――堆排序的最坏最好复杂度都是nlogn,而快排的最坏复杂度是n 2 ,为什么不用堆排呢。国庆这几天断断续续地看完了老师给的博客之后终于明白了这个问题,而且更加深入地了解了sort函数对快排的极致优化。 从平均时间上来说,堆排的时间常数要比快排大,因为堆排会让某些数据出现很多大幅度的无效的移动,而快排则是将每个元素快速地移动到最终位置上或是附近,然后进行小范围的移动,详见 https://www.zhihu.com/question/20842649 http://mindhacks.cn/2008/06/13/why-is-quicksort-so-quick/ 那么std::sort又是怎么实现来尽量避免快排的最坏情况呢,这篇博客给出了详细的解答 http://feihu.me/blog/2014/sgi-std-sort/ 为了让自己看的时候不至于被各种函数名弄晕,做了个图辅助一下 基于个人的理解 __introsort_loop这个函数的主体部分就是快速排序的部分,但它与一般的快排不一样的是,为了尽量减少枢轴为极值引起的递归恶化,它选取了开头、中间

全排列递归算法

匿名 (未验证) 提交于 2019-12-03 00:13:02
转自: https://blog.csdn.net/xiazdong/article/details/7986015 我们可以将这个排列问题画成图形表示,即排列枚举树,比如下图为{1,2,3}的排列枚举树: 从第一个数开始枚举确认,接着进入下一个递归即枚举下一个数,直到最后一个数被确认到达出口。 如确认了第一个数1,则确认第二个数为2,接着确认3,一次递归结束输出123 返回到上一层第二层,确认第二个数的枚举{2,3}只有3没被枚举,确认第二个数为3,接着第三个数为2,输出132; 返回第二层,无可枚举数,再返回上一层即确认第一个数{1,2,3},确认第一个数为2,重复上述,确认第二个数为{1,3},枚举。。。。 直到所有数都枚举完,则递归结束,全排列完成。 核心代码: void perm ( int arr [], int begin , int end ) {    if ( end == begin )  { //一到递归的出口就输出数组,此数组为全排列      for ( int i = 0 ; i <= end ; i ++)    {       printf ( "%d" , arr [ i ]);      }     printf ( "\n" );      return ;    } else    {      for ( int j = begin ;

线程同步锁、死锁、递归锁、信号量、GIL

匿名 (未验证) 提交于 2019-12-03 00:09:02
Ŀ¼ 所有线程同一时间读写同一个数据,有的线程已经对数据进行修改了,造成有的线程拿到的数据时旧的数据,而不是修改后的数据,造成结果不正确,于是引入了同步锁解决问题, 同步锁的原理是同一时间只能有一个线程读写数据。 锁通常被用来实现对共享资源的同步访问。从threading模块导入一个Lock类,为每一个共享资源创建一个Lock对象,当你需要访问该资源时,调用acquire方法来获取锁对象(如果其他线程已经获得了该锁,则当前线程需等待其被释放),待资源访问完后,再调用release方法释放锁。 下面这个例子就需要用到同步锁: from threading import Thread x = 0 def task(): global x for i in range(20000): x=x+1 # t1 的 x刚拿到0 保存状态 就被切了 # t2 的 x拿到0 进行+1 1 # t1 又获得运行了 x = 0 +1 1 # 思考:一共加了几次1? 加了两次1 真实运算出来的数字本来应该+2 实际只+1 # 这就产生了数据安全问题. if __name__ == '__main__': t1 = Thread(target=task) t2 = Thread(target=task) t3 = Thread(target=task) t1.start() t2.start() t3