算法系列教程04 - 算法相关的基础概念
本系列前面两篇讲的都是一些背景知识,从这一篇开始我们正式讲算法,从算法的一些基本概念讲起。
什么是算法
通过上一篇对图灵机原理的讲解,我们知道,一个计算问题描述的是输入/输出之间的关系,如果根据给定的输入能设计一个程序计算出期望的输出,就认为这个问题可解。这个程序的计算过程就是用算法来描述的,通过算法这个工具我们就容易设计出这样的一个程序。
确切地说,算法是有限步骤的计算过程,该过程取某个值或集合作为输入,并产生某个值或集合作为输出。
算法的正确与错误
如果算法对于每个输入都可以正确的停机,则称该算法是正确的,并称正确的算法解决了给定的计算问题。一个不正确的算法对于某个输入可能根本不停机,也可能以不正确的结果停机,比如一个排序问题:
输入:一个长度为n的数组(a1,a2,a3...)
输出:输入数组排序后的一个数组(b1,b2,b3....),满足:b1≤b2≤b3
如果根据这个问题设计出来的算法交给图灵机运行输出的结果与人们的期望相反(比如输出:b3,b2,b1…),那么这个算法就是错误的。
随机访问机模型
针对同一计算问题,可以设计出多种算法,其中有好有坏,我们可以通过预测算法需要的资源来筛选出好的算法。虽然有时我们关心内存、带宽这类硬件资源,但通常我们度量的是运行时间。
度量算法的运行时间,人们通常用的是随机访问机模型(Random-Access Machine, RAM)。在 RAM 模型中:
- 指令一条接着一条执行的,没有并发操作。
- 指令包含了真实计算机的常见指令:算数指令(加法,减法,乘法,除法,取余等)、数据移入指令(装入,存储,复制)和控制命令(条件与无条件转移、子程序调用与返回);
- 每条指令所用的时间均为常量。
RAM 模型假定的观点是,运行每行伪代码所需的时间是一个常量时间,虽然真实计算机执行一行代码与另一行代码需要不同的常量时间。依此,一个算法在特定输入上的运行时间不是指现实意义的时间,而是执行指令的次数。
比如下面这段 foo 函数的代码:
// prettier-ignorefunction foo(n) {for (let i = 0; i < n; i++) { // 2n+1 次console.log('Hello, World!') // n 次 }return 0 // 1 次}
上面的代码需要执行 2n + 1 + n + 1 = 3n + 2 次指令,也就是说执行时间是 3n + 2,如果用一个时间函数来表示,就是 T(n) = 3n + 2。
算法的时间复杂度
根据 RAM 模型,一个算法可以在给定的输入规模 n 下分析出一个运行时间的函数 T(n)。研究 T(n) 常用的一种策略是分析输入规模 n 增大的情况下 T(n) 的变化(如线性增长、指数增长等)。如果用 f(n) 来表示 T(n) 的增长速度,那么 f(n) 和 T(n) 的关系我们约定用一个大 O 来表示,即:
T(n) = O(f(n))
这就是 大 O 表示法。由于输入规模 n 的增长率与 f(n) 的增长率是正相关的,所以称作 渐近时间复杂度(Asymptotic Time Complexity),简称 时间复杂度。相对应的,还有空间复杂度,这里我们不作讨论。
当 n 足够大时或趋于无穷大时,T(n) 的常数部分就变得不重要,我们真正关心的是运行时间的 增长量级 或 增长率。如果用 f(n) 来表示增长数度,上面 foo 示例代码的增长速度可以表示为 f(n) = n,把它代入到 T(n) = O(f(n)) 就是:
T(n) = O(n)
这时,我们称 foo 的时间复杂度为 O(n)。
常见的时间复杂度有:
- 常数阶 O(1),
- 对数阶 O(log2^n),
- 线性阶 O(n),
- 线性对数阶 O(nlog2^n),
- 平方阶 O(n^2),
- 立方阶 O(n^3),
- k 次方阶 O(n^k),
- 指数阶 O(2^n)。
随着问题规模 n 的不断增大,上述时间复杂度不断增大,算法的执行效率也越低。大 O 表示法只是一种估算,当输入规模足够大的时候才有意义。
注意,大 O 表示法考虑的是最坏的情况。比如,从一个长度为 n 的数组中找一个值等于 10 的元素,开始遍历扫描这个数组,有可能第 1 次就扫到了,也有可能是第 n 次才扫到。这里最坏的情况是 n 次,所以时间复杂度就是 O(n)。
大部分情况下你用直觉就可以知道一个算法的大 O 表示。比如,如果用一个循环遍历输入的每个元素,那么这个算法就是 O(n);如果是用循环套循环,那就是 O(n^2),以此类推。
参考:《算法导论,第三版》
算法系列教程04 - 算法相关的基础概念相关推荐
- 查找算法系列之复杂算法:哈希查找
查找算法系列之复杂算法:哈希查找 眼下为止已经介绍了顺序查找.二分查找.分块查找.二叉排序树.见作者之前的文章: http://blog.csdn.net/u010025211/article/det ...
- 【算法系列】卡尔曼滤波算法
系列文章目录 ·[算法系列]卡尔曼滤波算法 ·[算法系列]非线性最小二乘求解-直接求解法 ·[算法系列]非线性最小二乘求解-梯度下降法 ·[算法系列]非线性最小二乘-高斯牛顿法 ·[算法系列]非线性最 ...
- React + webpack 开发单页面应用简明中文文档教程(一)一些基础概念
React + webpack 开发单页面应用简明中文文档教程(一)一些基础概念 React 入门系列教程导航 React + webpack 开发单页面应用简明中文文档教程(一)一些基础概念 Rea ...
- python机器学习案例系列教程——聚类算法总结
全栈工程师开发手册 (作者:栾鹏) python教程全解 一.什么是聚类? 聚类(Clustering):聚类是一个人们日常生活的常见行为,即所谓"物以类聚,人以群分",核心的思想 ...
- python机器学习案例系列教程——GBDT算法、XGBOOST算法
全栈工程师开发手册 (作者:栾鹏) python数据挖掘系列教程 GBDT概述 GBDT也是集成学习Boosting家族的成员,但是却和传统的Adaboost有很大的不同.回顾下Adaboost,我们 ...
- 排序算法系列:归并排序算法
概述 上一篇我们说了一个非常简单的排序算法--选择排序.其复杂程序完全是冒泡级的,甚至比冒泡还要简单.今天要说的是一个相对比较复杂的排序算法--归并排序.复杂的原因不仅在于归并排序分成了两个部分进行解 ...
- 分治法的关键特征_算法系列之常用算法之一----分治算法
一.基本概念 在计算机科学中,分治法是一种很重要的算法.分治算法,字面上的解释是"分而治之",分治算法主要是三点: 1.将一个复杂的问题分成两个或更多的相同或相似的子问题,再把子问 ...
- 实时音视频面视必备:快速掌握11个视频技术相关的基础概念
本文作者Ahab,原题"视频相关的理论知识与基础概念",收录时有修订和改动. 1.引言 随着移动互联网的普及,实时音视频技术已经在越来越多的场景下发挥重要作用,已经不再局限于IM中 ...
- 音视频面试必备:一文搞懂视频相关的基础概念
1.引言 随着移动互联网的普及,实时音视频技术已经在越来越多的场景下发挥重要作用,已经不再局限于IM中的实时视频聊天.实时视频会议这种功能,在远程医疗.远程教育.智能家居等等场景也司空见惯. 虽然实时 ...
最新文章
- np.vstack()和np.hstack()
- jquery的html代码中a的onclick的正确显示的代码
- 需求文档可以不签字吗之三-一个实例
- VTK:可视化算法之MarchingCases
- ashx一般处理程序
- Spring Cloud 之 Ribbon,Spring RestTemplate 调用服务使用Hystrix熔断器
- C++新特性探究(五):for循环、范围for语句
- Python 正则表达式模块 - re
- python字典功能默写_新华字典APP每天只能免费查两字,完整版卖40元!网友嫌贵...
- 【深度学习】模型平均误差分析
- 还在为满意的渐变色发愁吗?10+个网站帮你解决烦恼
- 天使投资、风险投资VC、私募基金PE 与“A轮、B轮、C轮融资”的关系
- 极速掌握HTML(一)基础入门
- 计算机utp,UTP网线
- Android点9图机制及在聊天气泡中的应用
- 4016: 辉夜的夜空明珠
- FFT(快速傅里叶变换)摘要
- 应届生什么专业方向就业面广?
- qlist 嵌套_QList内存释放
- 关系规范化之满足第三范式3NF的函数依赖保持分解算法