递归

浅谈如何学习数据结构与算法[@初学者]

自闭症网瘾萝莉.ら 提交于 2020-02-07 01:57:52
导语 所谓“数据结构”,一般来说是“数据结构与算法”,是NOIPer/NOIer、本科生、硕士生、程序员都会学的一门课程,是程序员的必修课。 数据结构为什么要学? 我们使用计算机,希望它能帮助我们解决各种各样的问题,但随着发展—— 我们希望它运行得更快, 希望它能处理更多数据,希望它做一些原本不可能的事情…… 计算机科学不断改变着这个世界,但代价可能是高昂的。 好的算法设计可以做得更好,而且可能很便宜;劣质的算法就不得不花费更高昂的代价。 事实上,我们可能认为提高算力就能忽略劣质算法的影响。诚然,我们也在努力提高计算机算力,但即使强如超级计算机,也无法挽救一个错误的算法。 希望很多人能正视这个问题,因为数据结构与算法真的值得学习。 学科基础 学习数据结构与算法不需要太多的基础知识,但需要你熟练掌握一门编程语言。 至少给你C/C++/Java/Python的代码你能看得懂,让你用自己熟练的编程语言能轻松实现,这样就很棒了。 至于二分查找、冒泡排序、数组之类的内容我觉得是一个刚刚入门计算机科学的孩纸就应该会的,所以就很基础,没啥可说的,该会,对吧?(比如你连冒泡排序都不会,你咋学快排啥的,对吧?) 最好有一些经验积累,我在学数据结构之前就能在一定程度上运用Java的集合框架,看过比如java.util.ArrayList啊,java.util.LinkedList这样的类的源码

Java学习笔记(二)

不羁岁月 提交于 2020-02-07 00:18:24
流程控制语句 条件语句 if ifelse ifelseifelse swich(多值判断) 循环语句 while for 递归 递归结构包括两个部分: 定义递归头,没有头递归将进入死循环,也就是递归结束的条件 递归体,什么时候需要调用自身的方法 任何用递归能解决的问题都能用迭代来解决,递归不强调效率,在高性能的情况下尽量避免使用递归,花时间又耗内存 面相过程和面相对象 相辅相成的关系 OOA OOD 面相对象适合开发大型的软件 面相对象是宏观上的把控,微观处理上仍然是面相过程 构造方法,用于创建这个类的对象,无参的构造方法可以有系统的自动创建 栈 栈描述的是方法执行的内存模型,每个方法被调用的时候都会创建一个栈帧,存储局部变量、操作数、方法出口等 JVM为每一个线程创建一个栈,用于存放该线程执行方法的信息(实际参数,局部变量等) 栈属于线程私有,不能实现线程间的共享 先进后出,后进先出 栈由系统自动分配,速度快,是一个连续的内存空间 堆 用于存储创建好的对象和数组,数组也是对象 JVM只有一个堆,被所有的线程共享 是一个不连续的内存分配空间,分配灵活,速度慢 方法区(静态区) JVM只有一个方法区,所有线程共享 方法区实际也是堆,只是用于存储类、常量相关的信息 用来存放程序中永远不变或者唯一的内容 垃圾回收机制 Java引入垃圾回收机制,C++内存管理问题得到解决,提高了开发效率

2017-2018-2 《程序设计与数据结构》第11周学习总结

混江龙づ霸主 提交于 2020-02-06 14:07:14
20172312 2017-2018-2 《程序设计与数据结构》第10周学习总结 教材学习内容总结 本周的十三章其实不是很难(或者说我个人认为不是很难),感觉本周的难点更偏向于实验,尤其是第三,四项实验的难度,相当之大。 本周内容: 对象具有良好定义的接口,这是一种实现集合的机制。 动态数据结构的大小规模可以随需要而改变。 通过存储更改对象引用来实现一个链表管理。 通过仔细操作对象引用,实现插入和删除操作。 队列是一种先进先出的线性数据结构,堆栈则是后进后出。 教材学习中的问题和解决过程 问题1:在数据结构的动态结构当中,对于动态结构的大小规模变化不是很了解。 问题1解决方案: https://blog.csdn.net/fengfeng2861285642/article/details/52304083 链表从本质上讲可以理解为“动态的对象数组”。链表可以实现对象的增加、删除、查询等等一系列的操作,可以实现动态扩充。如下为链表的实现: 代码调试中的问题和解决过程 本周的代码没有遇到太大的问题,基本上就是些大小写错误,以及编码不规范。(话说那个代码规范能删了不,每次都提醒我起名不对。) 代码托管 上周考试错题总结 1.穿越迷宫递归比迭代要容易得多。false A.递归是吸引人的一个原因是它自动回溯到最后一个决定的要点。在穿越迷宫时,当到达死胡同时

六. python进阶(递归)

浪尽此生 提交于 2020-02-06 13:25:06
一 .递归 在函数内部,可以调用其他函数。如果一个函数在内部调用自身本身,这个函数就是递归函数 。 递归函数: 一个会调用自身的函数称为递归函数凡是循环能干的事情 递归都能干方式: 写出临界条件 我这一次和上一次的关系 假设当前函数已经能用 调用自身计算上一次结果 在求出本次的结果 必须有一个明确的结束条件; 每次进入更深一层递归时,问题规模相比上次递归都应有所减少 相邻两次重复之间有紧密的联系,前一次要为后一次做准备(通常前一次的输出就作为后一次的输入)。 递归效率不高,递归层次过多会导致栈溢出(在计算机中,函数调用是通过栈(stack)这种数据结构实现的,每当进入一个函数调用,栈就会加一层栈帧,每当函数返回,栈就会减一层栈帧 。由于栈的大小不是无限的,所以,递归调用的次数过多,会导致栈溢出 import sys print(sys.setrecursionlimit(1000)) # sys.setrecursionlimit() #设置最大递归层数 print(sys.getrecursionlimit()) #获取最大递归层数 # RecursionError: maximum recursion depth exceeded while calling a Python object 递归的错误 最大的深度 def aa(): print("1111") aa()

重温快速排序(递归与非递归实现)

本小妞迷上赌 提交于 2020-02-06 10:37:10
算法基本过程 简单讲,就是 分治 。选一个基准元素,将序列分割成两部分,使得左边的都比基准小,右边的都比基准大。此时基准元素位置确定了,左右两侧也相对有序。再把左右子序列看成独立的序列,选基准,分割成左边小,右边大的两部分,一直分到无法再划分下去。 快排快在哪? 相比于冒泡排序每一轮只把一个元素冒泡到序列的一端。快排虽然每一轮也只能确定一个元素的最终位置,但它用分治的思路,每一轮使得左右两侧变得相对有序。 实现细节 基准元素的选择 一般会选择第一个元素作为基准,为了避免逆序数列的极端情况,也可以随机选择一个元素作为基准,并让基准元素和首元素交换位置 元素交换的过程 双边循环 单边循环 双边循环 //左右2个指针 //右指针开始往左移动,直到发现比pivot小的,停止移动 //左指针往右移动,直到发现比pivot大的,此时交换左右指针 //回到第二行的步骤 //最后将pivot和左子序列的最后一个元素交换 public void quickSortDual ( int [ ] arr , int left , int right ) { if ( left >= right ) return ; int pivot = arr [ left ] ; int posLeft = left + 1 ; int posRight = right ; boolean moveRight =

方法的调用:递归

*爱你&永不变心* 提交于 2020-02-06 06:58:21
1、静态方法与非静态方法 静态方法和非静态方法的区别是: 静态方法有static;非静态方法没有。 如:静态方法: public class students { //静态方法 public static void say(){ System.out.println("学生说话了"); } } 调用静态方法: public static void main(String[] args) { students.say(); } 非静态方法: public class Student { //非静态方法 public void say(){ System.out.println("学生说话了"); } 调用非静态方法: public static void main(String[] args) { //实例化这个类 new //对象类型 对象名=对象值 // Student student=new Student(); student.say(); } 都是非静态方法或静态方法,则方法a可以在直接调用方法b: public void a(){ b(); } public void b(){ } 若a是静态,b不是,则不行: //和类一起加载的 public static void a(){ b(); } //类实例化之后才存在 public void b(){ } 2、形参与实参

递归(再理解)

a 夏天 提交于 2020-02-06 04:30:03
递归(递推) 递归就在于反复调用自身函数,但是每次把问题范围缩小,直到缩小到可以直接得到边界数据的结果,然后再在返回的路上求出对应的解。(所以, 递归很适合用来实现分治的思想 ) 递归的逻辑中一般有两个重要概念: 递归边界 递归式 其中递归式是将原问题分解为若干个子问题的手段,而递归边界则是分解的尽头。 经典例子:求解n的阶乘 n! = 1 * 2 * 3 * 4 * ··· * n ,这个式子写成递推式就是 n! = (n-1) * n,于是就把规模为n的问题转换为求解规模为n-1的问题。如果用函数F(n)表示n!,就可以写成F(n)=F(n-1) * n (即递归式),这样规模就变小了。 那么,如果把F(n)变为F(n-1),又把F(n-1)变为F(n-2),这样一直减小规模,什么时候是尽头呢?由于0! = 1,因此不妨以F(n) = 1作为递归边界,即当规模减小至n = 0的时候开始“ 回头 ”。 个人感觉这个“ 回头 ”是一些题中的关键点。 于是,可以有一下代码: # include <iostream> using namespace std ; int J ( int n ) { if ( n == 0 ) return 1 ; //当到达递归边界F(0)时,返回F(0) == 1 else return J ( n - 1 ) * n ; //没有到达递归边界时

Java 递归补充_知识点

泪湿孤枕 提交于 2020-02-06 04:28:20
Java 递归补充_知识点 执行步骤:首先执行Main方法 —> f(5) —> f(4) —> f(3) —> f(2) —>返回了值给f(3) (返回后才调用f(1))—> f(1) —> 返回了值给f(3) —> f(3)的值为2所以返回给 f(4) ,f(3)返回后f(4)调用f(2)的值,计算f(2)的值,f(2)返回值,返回值为1。f(4)返回后f(5)才会调用f(3),f(3)调用时调用f(2),f(2)返回1时,f(3)继续调用f(1),f(1)返回,f(3返回),f(5)返回,main方法继续执行。 添加了判断的代码(if),代码的健壮性 来源: CSDN 作者: 丨沫沫然丶 链接: https://blog.csdn.net/weixin_42814000/article/details/104185752

八皇后问题递归回溯法

穿精又带淫゛_ 提交于 2020-02-06 02:53:03
写在前面:最开始接触是数据结构老师在提到过,后来在学python时老师也有提到过,出于好奇就去思考了这个问题,当然,小白的我还是在B站懒猫老师的帮助下学会啦,真棒哈哈哈哈哈哈 这里主要问题是在于判断对角线上是否能放,表示上对角线d1[],表示下对角线d2[],根据老师所说加上自己的理解,同一个下对角线上 n-col+7相同(n表示行,col表示列) 同理,上对角线上n+col 相同 由以上可得判断的标准为(flag[col]&&d1[n-col+7]&&d2[n+col]==ture),只要符合这个就能判断是否能放入棋子 place[n]=col;//摆放皇后 flag[col]=false;//宣布占领第col列 d1[n-col+7]=false;//占领上对角线 d2[n+col]=false;//占领下对角线 #include<stdio.h> #include <stdbool.h> int place[8]={0}; //第n个皇后所占位置的列号 bool flag[8]={1,1,1,1,1,1,1,1}; //标志数组,表示第col列是否可占,1表示不冲突 bool d1[15]={1,1,1,1.1,1.1,1,1,1,1,1,1,1,1}; bool d2[15]={1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}; //表示下对角线是否可占 int

python基础 3 函数和代码的复用

跟風遠走 提交于 2020-02-06 00:34:25
函数和代码的复用 函数的定义和使用 可选参数,必选参数。如果传入的数量不够后面的默认为可选参数,所以必要的参数位置放在前面。 可变参数:*b. (def fact (n,*m) ) 返回值 可以不返回 返回一个 返回多个 (元组接收) 全局变量与局部变量 局部变量与全局变量不会相同,如果需要表示全局变量需要加上global标识符。 组合类型的变量(指针类型来实现),如果在函数内并没有创建该名称的组合类型的变量,那么对该组合类型变量的调用就是对全局变量进行调用。 lambda函数: 代码复用与函数递归 模块化设计 紧耦合 松耦合 递归 链条 计算过程存在递归链条 基例 存在一个或多个不需要再次递归的基例 实例: 汉诺塔操作递归 斐波那契 科赫雪花绘制 来源: CSDN 作者: Fasthand_ 链接: https://blog.csdn.net/qq_43390703/article/details/104188720