算法和算法评价


1 算法的基本概念

算法(Algorithm)是对特定问题求解步骤的一种描述,它是指令的有限序列,其中的每条指令表示一个或多个操作。一般具有下列5个重要特性:

  1. 有穷性:一个算法必须在执行有穷步之后结束,且每一步都可在有穷时间内完成。
  2. 确定性:算法中每条指令必须有确切的含义,对于相同的输入只能得到相同的输出。
  3. 可行性:算法中描述的操作都可以通过已经实现的基本运算执行有限次来实现。
  4. 输入:一个算法有零个或多个输入,这些输入取自于某个特定的对象的集合。
  5. 输出:一个算法有一个或多个输出,这些输出是与输入有着某种特定关系的量。


2 算法效率的度量

算法效率的度量是通过时间复杂度和空间复杂度来描述的。

2.1 算法运行时间的估算

算法执行时间需通过依据该算法编制的程序在计算机上运行时所消耗的时间来度量,而度量一个程序的执行时间通常有两种方法:

  1. 事后统计的方法:先运行一次程序,然后测量算法程序的运行时间。这种方法非常直接,也有一些明显的缺陷:一是必须先运行一次程序,如果程序运行时间很长,就会消耗大量时间;二是依赖于特定计算机的运行速度,依赖于算法程序实现的质量,依赖于编译器编译的效率,有太多的无关因素影响度量标准,因此人们常常采用事前分析估算的方法。
  2. 事前分析估算的方法:一个用高级程序语言编写的程序在计算机上运行时所消耗的时间取决于下列因素:
    1. 依据的算法选用何种策略
    2. 问题的规模
    3. 书写程序的语言,对于同一个算法,语言越低级,执行效率就越高
    4. 编译程序所产生的机器代码的质量
    5. 机器执行指令的速度

我们可以发现,同一个算法在用不同的语言实现,或者用不同的编译程序编译,或者是在不同计算机上运行时,效率都会不同。这说明用绝对的时间来衡量算法的效率是不合适的。我们希望找到一个不依赖与这些无关因素的度量标准。在上述5个条件中抛开与外部环境有关的因素,我们可以认为一个特定算法“运行工作量”的大小,只依赖于问题的规模。

对于一个规模固定的问题,我们可以尝试去统计算法每一步操作的执行次数,用这个指标来衡量算法的效率。实际操作后,我们会发现这种做法过于困难,而且常常是没有必要的。我们应该做的是找出算法中最重要的操作,即所谓的基本操作(Baisc Operation),它们对总运行时间的贡献最大,然后计算它们的运行次数。根据以上原则,我们就不难发现一个算法中的基本操作往往是算法最内层循环中最费时的操作。例如,大部分排序算法是通过比较待排序的元素和交换元素这两步来工作的,对于这类算法,比较和交换就是基本操作。再比如,我们想用一个for循环重复累加来计算数列{1,2,3,…,100}\{1, 2, 3, \dots, 100\}{1,2,3,…,100}的和,加法运算就是这个算法的基本操作。

这样我们就建立起一个分析算法时间效率的框架:对于输入规模为nnn的算法,统计它的基本操作执行次数,来对其效率进行度量。

我们约定copc_{op}cop​为特定计算机上一个算法基本操作的执行时间,而C(n)C(n)C(n)是该算法需要执行基本操作的次数。这样,对运行在特定计算机上的算法程序的运行时间可以用下列公式计算:
T(n)≈copC(n)T(n) \approx c_{op}C(n) T(n)≈cop​C(n)

2.2 算法的最优、最差和平均效率

我们在上一节提到以算法输入规模为参数的函数可以合理地度量算法的效率。但是也有许多算法的运行时间不仅取决于输入的规模,还取决于特定的输入细节。例如,我们用下列算法来查找一个包含nnn个元素的数组中大小为KKK的元素:

算法 SequentialSearch(A[0, 1, ..., n-1], K)// 用顺序查找在给定的数组中查找给定的值// 输入:数组A[0, 1, ..., n-1]和查找键K// 输出:返回第一个匹配K的元素的下标,如果没有匹配元素则返回-1i ← 0while i < n and A[i] ≠ K doi ← i +1if i < n return ielse reurn -1

假设我们数组中没有我们要找的元素KKK,或是元素KKK在数组的最后一位,我们就需要遍历完整个数组;假设数组第一位就是我们要找的元素KKK,那么算法只需要执行一步。 很明显,对于相同规模的数组,算法的运行时间也会产生很大的差异。

  • 最差效率 (Worst-case Efficiency):指当输入规模为nnn时算法在最坏情况下的效率。分析算法的最差效率有助于我们了解算法运行时间的上界,换句话说,在任何情况下,算法的运行时间不会超过最坏输入情况下的运行时间Cworst(n)C_{worst}(n)Cworst​(n)。
  • 最优效率 (Best-case Efficiency):指当输入规模为nnn时算法在最优情况下的效率。最优效率的分析不如最差效率分析重要,但是它也不是毫无用处。有些算法对于一些接近最优输入的有用输入类型,也可以获得类似最优效率的良好性能。因此我们可以对输入数据进行刻意挑选来获得算法更好的性能。其次,如果一个算法的最优效率都不能满足要求,我们就可以立刻放弃对该算法的研究,不必进一步分析。
  • 平均效率 (Average-case Efficiency):无论是最差还是最优效率,都不能体现出在“随机”情况下算法的效率,因此我们还需要平均效率。

2.3 渐进符号和基本效率类型

在上文我们用T(n)T(n)T(n)或t(n)t(n)t(n)来表示算法的运行时间,C(n)C(n)C(n)来表示基本操作的次数,现在我们加入g(n)g(n)g(n)来表示和基本操作次数相比较的函数。

2.3.1 符号OOO

如果存在大于0的常数ccc和非负的整数n0n_0n0​,使得对于所有的n≥n0n \ge n_0n≥n0​,有t(n)≤cg(n)t(n) \le cg(n)t(n)≤cg(n),则说函数t(n)t(n)t(n)包含在O(g(n))O(g(n))O(g(n))中,记作t(n)∈O(g(n))t(n) \in O(g(n))t(n)∈O(g(n))


非正式来说,O(g(n))O(g(n))O(g(n))是增长次数小于等于g(n)g(n)g(n)的函数集合,例如,我们可以说100n+5∈O(n2)100n+5 \in O(n^2)100n+5∈O(n2)。

2.3.2 符号Ω\OmegaΩ

如果存在大于0的常数ccc和非负的整数n0n_0n0​,使得对于所有的n≥n0n \ge n_0n≥n0​,有t(n)≥cg(n)t(n) \ge cg(n)t(n)≥cg(n),则说函数t(n)t(n)t(n)包含在Ω(g(n))\Omega(g(n))Ω(g(n))中,记作t(n)∈Ω(g(n))t(n) \in \Omega(g(n))t(n)∈Ω(g(n))

Ω(g(n))\Omega(g(n))Ω(g(n))是增长次数大于等于g(n)g(n)g(n)的函数集合,例如n3∈Ω(n2)n^3 \in \Omega(n^2)n3∈Ω(n2)

2.3.3 符号Θ\ThetaΘ

如果存在大于0的常数c1c_1c1​,c2c_2c2​和非负的整数n0n_0n0​,使得对于所有的n≥n0n \ge n_0n≥n0​,有c2g(n)≤t(n)≤c1g(n)c_2g(n) \le t(n) \le c_1g(n)c2​g(n)≤t(n)≤c1​g(n),则说函数t(n)t(n)t(n)包含在Θ(g(n))\Theta(g(n))Θ(g(n))中,记作t(n)∈Θ(g(n))t(n) \in \Theta(g(n))t(n)∈Θ(g(n))


Θ(g(n))\Theta(g(n))Θ(g(n))是增长次数等于g(n)g(n)g(n)的函数集合。例如,12n(n−1)∈Θ(n2)\frac{1}{2}n(n-1) \in \Theta(n^2)21​n(n−1)∈Θ(n2)。

2.3.4 渐进符号的特性

根据渐进符号的正式定义,我们可以得到下列定理:

一、加法规则
如果t1(n)∈O(g1(n))t_1(n) \in O(g_1(n))t1​(n)∈O(g1​(n))并且t2(n)∈O(g2(n))t_2(n) \in O(g_2(n))t2​(n)∈O(g2​(n)),则
t1(n)+t2(n)∈O(maxg1(n),g2(n))t_1(n) +t_2(n) \in O(max{g_1(n), g_2(n)}) t1​(n)+t2​(n)∈O(maxg1​(n),g2​(n))
二、乘法规则
如果t1(n)∈O(g1(n))t_1(n) \in O(g_1(n))t1​(n)∈O(g1​(n))并且t2(n)∈O(g2(n))t_2(n) \in O(g_2(n))t2​(n)∈O(g2​(n)),则
t1(n)×t2(n)∈O(g1(n))×O(g2(n))∈O(g1(n)×g2(n))t_1(n) \times t_2(n) \in O(g_1(n)) \times O(g_2(n)) \in O(g_1(n) \times g_2(n)) t1​(n)×t2​(n)∈O(g1​(n))×O(g2​(n))∈O(g1​(n)×g2​(n))
(对于符号Ω\OmegaΩ和Θ\ThetaΘ,类似的断言也成立。)

这些特性意味着算法的整体效率是由具有较大增长次数的部分所决定的,即它效率较差的那一部分。例如,我们使用下述这个两部分算法来检查数组中是否含有相等元素:1. 应用某种已知的排序算法对数组进行排序, 2. 扫描该有序数组,比较相邻元素是否相等。假设第一部分的比较次数不会超过12n(n−1)\frac{1}{2}n(n-1)21​n(n−1)(属于O(n2)O(n^2)O(n2)),而算法的第二部分比较次数不超过n−1n-1n−1 (因此属于O(n)O(n)O(n)),该算法的整体效率应该属于O(max{n2,n})=O(n2)O(max \{ n^2, n \}) = O(n^2)O(max{n2,n})=O(n2)。

2.4 时间复杂度

在了解了渐进符号后,我们就可以来定义时间复杂度了。

一个语句的频度是指该语句在算法中被重复执行的次数。我们通常将算法中所有语句的频度之和记为T(n)T(n)T(n),它是该算法问题规模nnn的函数,时间复杂度主要分析T(n)T(n)T(n)的数量级。因为在算法中基本操作的频度和T(n)T(n)T(n)在同一个数量级,所以我们使用算法中基本操作的频度f(n)f(n)f(n)来分析算法的时间复杂度:
T(n)=O(f(n))T(n) = O(f(n)) T(n)=O(f(n))
没有特殊说明的情况下,我们说的时间复杂度都是指最差时间复杂度。如果一个算法的时间复杂度T(n)=O(f(n))T(n) = O(f(n))T(n)=O(f(n)),那么我们说该算法的问题规模为nnn,其执行时间和f(n)f(n)f(n)成正比。

时间复杂度由问题规模nnn和输入的初始状态共同决定。

2.5 空间复杂度

算法的空间复杂度S(n)S(n)S(n)定义为该算法所耗费的存储空间,它是问题规模nnn的函数。记为:
S(n)=O(g(n))S(n) = O(g(n)) S(n)=O(g(n))
算法原地工作是指算法所需的辅助空间为常量,即O(1)O(1)O(1)。


相关章节

第一节 【绪论】数据结构的基本概念
第二节 【绪论】算法和算法评价
第三节 【线性表】线性表概述
第四节 【线性表】线性表的顺序表示和实现
第五节 【线性表】线性表的链式表示和实现
第六节 【线性表】双向链表、循环链表和静态链表
第七节 【栈和队列】栈
第八节 【栈和队列】栈的应用
第九节 【栈和队列】栈和递归
第十节 【栈和队列】队列

二、【绪论】算法和算法评价相关推荐

  1. 分类算法学习(二)——贝叶斯算法的原理及简单实现

    1.3.贝叶斯分类的基础--贝叶斯定理 每次提到贝叶斯定理,我心中的崇敬之情都油然而生,倒不是因为这个定理多高深,而是因为它特别有用.这个定理解决了现实生活里经常遇到的问题:已知某条件概率,如何得到两 ...

  2. 标准发布丨央行发布《人工智能算法金融应用评价规范》

    2021-05-11 11:12:26 来源:中国人民银行 为全面提升人工智能技术在金融领域应用和管理水平,推动金融与科技深度融合协调发展,中国人民银行制定了<人工智能算法金融应用评价规范> ...

  3. 二叉搜索树的算法实现

    文章目录 1 二叉搜索树简介 2 二叉搜索树的算法实现 2.1 节点结构体的定义 2.2 二叉搜索树插入节点 2.3 二叉搜索树删除结点 2.4 二叉搜索树搜索 2.5 二叉搜索树的遍历 1 二叉搜索 ...

  4. C语言Catalan number卡特兰数(使用n个键可以搜索多少个二叉搜索树)的算法(附完整源码)

    C语言使用n个键可以搜索多少个二叉搜索树的算法 C语言使用n个键可以搜索多少个二叉搜索树的算法完整源码(定义,实现,main函数测试) C语言使用n个键可以搜索多少个二叉搜索树的算法完整源码(定义,实 ...

  5. C++用二进制交换二个数的实现算法(附完整源码)

    C++用二进制交换二个数的实现算法 C++用二进制交换二个数的实现算法完整源码(定义,实现,main函数测试) C++用二进制交换二个数的实现算法完整源码(定义,实现,main函数测试) #inclu ...

  6. 【数据结构】之算法和算法评价

    1.2算法和算法评价 1.2.1 算法的基本概念 算法(Algorithm〉是对特定问题求解步骤的一种描述,它是指令的有限序列,其中的每条指令表示一个或多个操作.此外,一个算法还具有下列5个重要特性: ...

  7. 字符串匹配算法(二):BM(BoyerMoore)算法、坏字符规则,好后缀规则

    文章目录 BM算法 坏字符规则 好后缀规则 完整代码 BM算法 BM算法的全程叫做Boyer-Moore,是工程上最常用且最高效的字符串匹配算法,有实验统计,它的性能是著名的KMP 算法的 3 到 4 ...

  8. 机器学习实战(二)——k-近邻算法

    文章目录 2.1 k-近邻算法概述 2.1.1 准备:使用python导入数据 2.1.2 从文本文件中解析数据 2.2 示例:使用k-近邻算法改进约会网站的配对效果 2.2.1 准备数据:从文本文件 ...

  9. OpenCV学习(二十) :分水岭算法:watershed()

    OpenCV学习(二十) :分水岭算法:watershed() 参考博客: OpenCV-分水岭算法 图像处理--分水岭算法 OpenCV学习(7) 分水岭算法(1) Opencv分水岭算法--wat ...

最新文章

  1. 【从零开始的ROS四轴机械臂控制】(七)- ROS与arduino连接
  2. SQL语法之基础查询(进阶1)and条件查询(进阶2)
  3. 【设计模式】责任者模式
  4. sockaddr_in中sin_zero的意义,以及sockaddr_in sockaddr in_addr区别联系
  5. 数字图像处理频域滤波实现低通与高通滤波(包含matlab代码)
  6. CCF 201312-3 最大的矩形[比较简单]
  7. Oracle表空间的创建
  8. 我为何不再愿意打一份朝九晚五的工?
  9. 2021最新 武汉互联网公司
  10. LCD屏幕,IPS屏幕,TFT屏幕,SLCD屏幕和AMOLED手机屏幕介
  11. 那些不熟知的系统 开发语言 虚拟机 运行平台
  12. 基于 Spring SSM框架 开发的一套 进存销管理系统
  13. 命运交响曲计算机弹奏,贝多芬命运交响曲弹奏方法和介绍-雅马哈电子琴排行榜...
  14. 和Leo一起做爱线段树的好孩子HDU5238 Calculator
  15. 送给女朋友的3D立体动态相册的实现代码
  16. 子类调用父类构造器《转载》
  17. 转贴一首很感人的诗---孩子快抓紧妈妈的手
  18. Python爬虫爬取小说
  19. 51单片机DS18B20温度传感器及数码管显示温度
  20. CentOS-7安装WPS办公软件

热门文章

  1. android 辅助服务 简书,Android AccessibilityService使用
  2. 原字体_时隔25天,再次更新字体,ios1213
  3. c++的引用是什么意思?怎么回事?
  4. CCF 2016年题目题解 - Python
  5. Linux下CMake简明教程(五)正规一点的组织结构
  6. python elif 用法_Python入门高级教程--Python 条件语句
  7. 81. Leetcode 21. 合并两个有序链表 (排序)
  8. python 包介绍:osmnx
  9. 机器学习中的数学(3)-模型组合(Model Combining)之Boosting与Gradient Boosting
  10. shell 循环判断语法