算法基础复习笔记

本文探讨了算法在计算机科学中的基础地位,包括算法的定义、特性、描述方法,以及数据结构与程序的关系。重点讲述了算法设计的一般步骤,如问题理解、数学建模、详细设计、算法描述和验证,同时强调了时间复杂性和空间复杂性的分析在算法选择和优化中的重要性。
摘要由CSDN通过智能技术生成
  • 算法是程序设计的根基。计算机技术的发展日新月异,新的开发语言不断出现,编程工具不断更新,但是基本的算法策略却不会有太大改变。所以,熟练掌握基本的算法策略是最重要的。
  • 算法最初的定义:即所谓的一组确定的、有效的、有限的解决问题的步骤。注意,这个定义中没有包括“正确”一词。
  • 一个算法,就是一个有穷规则的集合,其中之规则规定了一个解决某一个特定类型的问题的运算序列。------D.E.Knuth, 当代著名计算机科学家。
  • 对于计算机科学来说,算法指的是对特定问题求解步骤的一种描述,是若干条指令的有穷序列,并具有以下特性:
  1. 输入。有零个或者多个输入,由外界提供或自己产生。
  2. 输出。有一个或者多个输出。算法是为解决某问题而设计的,其最终的目的就是获得问题的解,没有输出的算法是无意义的。
  3. 确定性。组成算法的每条指令必须有明确的定义,必须无歧义。在任何条件下,对于相同的输入只能得到相同的输出结果。
  4. 有限性。算法中的每条指令的执行次数都是有限的,执行每条指令的时间也是有限的。也就是说,在执行若干条指令之后,算法将结束。
  5. 可行性。一个算法是可行的,即算法中描述的操作都可以通过已经实现的基本运算执行有限次后实现。换句话说,要求算法中有待实现的运算都是基本的,每种运算至少在原理上能由人用纸和笔在有限的时间内完成。
  • 算法的描述方法:
  1. 自然语言
  2. 图形
  3. 程序设计语言
  4. 伪代码
  • 算法、数据结构和程序的区别:
  1. 算法是程序设计的精髓,程序是算法用某种程序设计语言的具体实现,程序设计的实质就是构造解决问题的算法。
  2. 算法+数据结构=程序。     -------   瑞士计算机科学家,N.Wirth
  3. 数据结构是算法设计的基础。
  • 只有正确把握算法的内涵,加上选择合适的数据结构,才能写出高质量的代码,生成优秀的程序。
  • 算法设计的一般过程如下:
  1. 充分理解要解决的问题:在算法设计的时候,一定要搞清楚算法要求处理的问题、实现的功能、预期获得的结果等。
  2. 数学模型的拟制:算法设计时,首先要根据问题的描述,建立符合要求的数学模型,并设计相关的约束条件等。
  3. 算法详细设计:算法详细设计指的是把算法具体化,即设计出算法的详细规格说明。在此设计阶段,要选择算法的设计策略,并确定合理的数据结构。
  4. 算法描述:根据前三部分的工作,采用描述工具将算法的具体过程描述出来。
  5. 算法思路的正确性验证:通过对一系列与算法的工作对象有关的引理、定理和公式进行证明,来验证算法所选择的设计策略及设计思路是否正确。
  6. 算法分析:算法分析是对算法的效率进行分析,主要分析时间效率和空间效率。相比而言,人们更加关心时间效率。
  7. 算法的计算机实现和测试:采用程序设计语言来实现算法并上机运行和测试,从而时间两个目的:1.对算法实现代码的正确性进行验证。2.对所要解决的问题进行求解。
  8. 文档资料的编制:撰写算法的整个设计过程,存档。
  • 对于计算计科学来说,算法分析是对时间复杂性和空间复杂性进行分析,其对算法的设计、选用和改进有着重要的指导意义和实用价值:
  1. 对于任意给定的问题,设计出复杂性尽可能低的算法是在设计时考虑的一个重要目标
  2. 当给定的问题存在多种算法时,选择算法复杂度最低者是在选用算法时应遵循的一个重要原则。
  3. 算法分析有助于对算法进行改进。
  • 时间复杂性是对算法运行时间长短的度量。度量的方法通常有两种:事后统计法和事前分析估计法
  • 撇开与计算机硬、软件有关的因素,一个特性算法的运行时间将只依赖于问题的规模(通常用正整数n表示)和他的输入序列I。因此,算法的运行时间可表示为二者的函数,T(n, I)。通常情况下,人们只考虑3种情况下的时间复杂性,即最坏情况、最好情况和平均情况,并分别记为T_{max}(n)T_{min}(n)T_{avg}(n)
  • 针对特定的输入序列,算法的时间复杂性只与问题的规模n有关,几乎所有的算法,规模越大所需的运行时间就越长。当n不断变化时,运行时间也会不断变化,故人们通常将算法的运行时间记为T(n)
  • 空间复杂性是对一个算法在运行过程中所占用的存储空间大小的度量,一般记为S(n)。注:n是问题规模。通常,与算法运行时所占用的存储空间相关的因素有以下3种因素,其中,第三种因素时算法设计的时候着重要考虑的。
  1. 存储算法本身所占用的存储空间。
  2. 算法的输入输出数据所占用的存储空间。
  3. 算法在运行过程中所需的辅助变量占用的存储空间,即辅助空间或临时空间。
算法的渐进复杂性
  • 【定义】设算法的运行时间为T(n),如果存在T^{*}(n),使得

\lim_{n \to \infty }\frac{T(n)-T^{*}(n)}{T(n)}=0

就称T^{*}(n)为算法渐进时间复杂性。

  • 【定义】若存在两个正常数c和n_{0},使得当n\geqslant n_{0}时,都有T(n)\leqslant cf(n),则称T(n)=O(f(n)),即f(n)T(n)的上界。换句话说,在n满足一定条件的范围内,函数T(n)的阶数不高于函数f(n)的阶。
  • 常见的几类时间复杂性有:
  1. O(1):常数阶时间复杂性
  2. O(n)O(n^{2})O(n^{3})、……:多项式阶时间复杂度
  3. O(2^{n})O(n!)O(n^{n}):指数时间阶时间算法。这类算法的运行效率低,根本不实用。
  4. O(nlogn)O(logn):对数时间算法

以上几种时间复杂性的关系:

O(1)<O(logn)<O(n)<O(nlogn)<O(n^{2})<O(n^{3})<O(2^{n})<O(n!)<O(n^{n})

  • 【定义】若存在两个正常数c和n_{0},使得当n\geqslant n_{0}时,都有T(n)\geqslant cf(n),则称T(n)=\Omega (f(n)),即f(n)T(n)的下界。换句话说,在n满足一定的范围内,函数T(n)的阶不低于函数f(n)的阶。它的概念与O是相对的。
  • 【定义】若存在3个正常数c_{1}c_{2}n_{0},使得当n\geqslant n_{0}时,都有c_{2}f(n)<T(n)<c_{1}f(n),则称T(n)=\Theta (f(n))\Theta意味着在满足一定条件的范围内,函数T(n)f(n)的阶相同。由此可见,\Theta用来表示算法的精确阶。
  • 【定理】若T(n)=a_{m}n^{m}+a_{m-1}n^{m-1}+\cdots +a_{1}n^{1}+a_{0}(a_{i}>0, 0\leqslant i\leqslant m)是关于n的一个m次多项式,则T(n)=O(n^{m}),且T(n)=\Omega (n^{m}),因此有T(n)=\Theta (n^{m})
  • 非递归算法的运行时间T(n)建立的依据
  1. 选择某种能够用来衡量算法运行时间的依据
  2. 依照该依据求出运行时间T(n)的表达式
  3. 采用渐进符号表示T(n)
  4. 获得算法的渐进时间复杂性,进行进一步的比较和分析

其中,步骤1是最关键的,它是其他步骤能够进行的前提。通常衡量算法运行时间的依据是基本语句,所谓基本语句是指对算法的运行时间贡献最大的原操作语句,其重复执行的次数与算法的运行时间成正比,多数情况下是算法最深层循环内的语句中的原操作。通常采用基本语句的执行次数对运行时间T(n)进行度量。

  • 当算法的时间复杂性既依赖问题规模又依赖问题输入序列时,需要从最好、最坏和平均情况三方面进行讨论。实践表明,可操作性最好且最有实际价值的是最坏情况下的时间复杂性,它表明算法的运行时间最坏能坏到什么程度。如果输入数据呈等概率分布,要以平均情况来作为运行时间的衡量。
  • 递归算法求解问题的一般步骤如下:
  1. 分析问题、寻找递归关系。找出大规模问题和小规模问题的关系。换句话说,如果一个问题能用递归方法解决,它必须可以向下分解 为若干个性质相同的规模较小的问题。
  2. 找出停止条件,该停止条件用来控制递归何时终止,在设计递归算法时需要给出明确的结束条件。
  3. 设计递归算法、确定参数,即构建递归体。递归算法的运行过程包含两个阶段:递推和回归。递推指的是将原问题不断分解为新的子问题,逐渐从未知向已知推进,最终达到已知的条件,即递归结束的条件。回归指的是从已知的条件出发,按照递推的逆过程,逐一求值回归,最后达到递推的开始处,即求得问题的解。
  • 线性表的存储方式:
  1. 顺序表(数组):随机存取
  2. 链表:对空间的利用上较合理,实现数据元素的插入和删除操作时,不需要移动数据元素。
  • 栈的特性是后进先出,有两种存储表示方式:即顺序栈和链栈。
  • 队列的特性是先进先出,有两种存储表示方式:即顺序存储结构(循环队列)和链式存储结构(链队列)。
  • 树结构中的重要术语:
  1. 父结点:若一个结点有子树,则该结点为父结点(或称为双亲节点)。
  2. 孩子结点:若某结点有子树,则其子树的根为该结点的孩子结点。
  3. 兄弟结点:同一个结点的孩子结点
  4. 层次:结点的层次是从根结点开始定义的,根结点的层次为1,其余结点的层次是其父结点的层次加1。
  5. 结点的深度:结点所在的层次减1。
  6. 树的高度(深度):树中结点的最大深度。
  7. 度:结点拥有的子树数目称为该结点的度,即一个结点的孩子数目就是该结点的度。
  8. 叶子结点:度为0的结点。
  9. 森林:森林是m(m\geqslant 0)颗互不相交的树的集合,对树中每个结点而言,其子树的集合即为森林。
  10. 二叉树:二叉树:二叉树是一种非常重要的树状结构,它的特点是每个结点至多只有两颗子树,并且,二叉树的子树有左右之分,其次序有时不能任意颠倒。
  • 树的存储结构:
  1. 顺序存储结构---双亲表示法:以一组连续的空间来存储树中的结点,并将树中的所有结点从上到下、从左到右依次编号,并用该编号作为结点在顺序存储中的位置。树中每个结点包含两个域,即数据域(data)和双亲域(parent)。数据域存放结点的数据,双亲域存放双亲(父)结点在顺序存储中的位置编号。
  2. 链式存储结构---孩子表示法:把每个结点的孩子结点排列起来,看成一个线性表,且以单链表作为存储结构,则n个结点有n个孩子链表(叶子结点的孩子链表为空表)。而n个头指针又组成另外一个线性表。为了便于查找,可采用顺序存储结构。与双亲表示法相反,孩子表示法便于那些涉及孩子的操作的实现,却不适用于对双亲结点进行操作。
  3. 链式存储结构---孩子兄弟表示法:孩子兄弟表示法又称二叉树表示法或二叉链表表示法,即以二叉链表作为树的存储结构,链表中结点的两个域分别指向该结点的第一个孩子结点和下一个兄弟结点。如果为每个结点增加一个parent域,则同样能方便地实现对双亲的操作。
  • 图是一种数据结构,可以用二元组表示,图中的数据元素通常称为顶点(或结点),数据元素之间的关系称为边,其形式化定义为G=(V,E)。

其中,集合V是顶点集,即它是顶点的有穷非空集合;集合E是边集,即它是V中两个顶点之间的关系的有穷集。

  • 根据边是否有方向,图分为有向图和无向图。
  • 20
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值