目录

算法的特征

算法设计的要求

时间复杂度


算法的特征

一个算法应该具有以下五个重要的特征:

有穷性

(Finiteness)

算法的有穷性是指算法必须能在执行有限个步骤之后终止;一个算法总是需要(输入合法的情况下)在有限的步骤结束,即每个算法需要在有穷的时间内完成。

确切性

(Definiteness)

算法的每一步骤必须有确切的定义;任何条件下,算法只有唯一的一条执行路径,即对于相同的输入只能得到相同的输出。

输入项

(Input)

一个算法有0个或多个输入,以刻画运算对象的初始情况,所谓0个输入是指算法本身定出了初始条件;

输出项

(Output)

一个算法有一个或多个输出,以反映对输入数据加工后的结果。没有输出的算法是毫无意义的;

可行性

(Effectiveness)

算法中执行的任何计算步骤都是可以被分解为基本的可执行的操作步骤,即每个计算步骤都可以在有限时间内完成(也称之为有效性)。

算法设计的要求

解决一个问题的方法可能有很多,但能称得上算法的,首先它必须能彻底解决这个问题(称为准确性),且根据其编写出的程序在任何情况下都不能崩溃(称为健壮性)。

在满足准确性和健壮性的基础上,还有一个重要的筛选条件,即通过算法所编写出的程序的运行效率。程序的运行效率具体可以从 2 个方面衡量,分别为:

  • 程序的运行时间。
  • 程序运行所需内存空间的大小。

算法涉及的要求主要有以下几个方面

1) 正确性

正确性(Correctness)指的是该算法能够满足预先指定的功能与性能的需求,即能够得到正确答案。

2)健壮性

健壮性(Robustness)指的是当输入数据不合法时,算法也能做出相关的处理,而不是产生不可预计的效果。

3)可读性

可读性(Readability)指的是算法是可以阅读,理解和交流的。

4)耗时低,占用空间少

运行时间(Running time)与占用空间(Storage space)概念,在设计算法时,我们总是希望能够更少地使用时间和空间达成我们的目标。

一个算法的评价主要从时间复杂度和空间复杂度来考虑。

时间复杂度

算法的时间复杂度是指执行算法所需要的计算工作量。

一般来说,计算机算法是问题规模n的函数f(n),算法的时间复杂度也因此记做:t=o(f(n))

因此,问题的规模n越大,算法执行的时间的增长率与f(n)的增长率正相关,称作渐进时间复杂度

实际场景中,我们更喜欢用一个估值来表示算法所编程序的运行时间。
也就是说,表示一个算法所编程序运行时间的多少,用的并不是准确值(事实上也无法得出),而是根据合理方法得到的预估值。
那么,如何预估一个算法所编程序的运行时间呢?很简单,先分别计算程序中每条语句的执行次数,然后用总的执行次数间接表示程序的运行时间。
以一段简单的 C 语言程序为例,预估出此段程序的运行时间:

for(int i = 0 ; i < n ; i++)     //<- 从 0 到 n,执行 n+1 次
{a++;                         //<- 从 0 到 n-1,执行 n 次
}

可以看到,这段程序中仅有 2 行代码,其中:

  • for 循环从 i 的值为 0 一直逐增至 n(注意,循环退出的时候 i 值为 n),因此 for 循环语句执行了 n+1 次;
  • 而循环内部仅有一条语句,a++ 从 i 的值为 0 就开始执行,i 的值每增 1 该语句就执行一次,一直到 i 的值为 n-1,因此,a++ 语句一共执行了 n 次。

因此,整段代码中所有语句共执行了 (n+1)+n 次,即 2n+1 次。数据结构中,每条语句的执行次数,又被称为该语句的频度。整段代码的总执行次数,即整段代码的频度。

再举一个例子:

for(int i = 0 ; i < n ; i++)           // n+1
{ for(int j = 0 ; j < m ; j++)       // n*(m+1){num++;                         // n*m}
}

计算此段程序的频度为:(n+1)+n*(m+1)+n*m,简化后得 2*n*m+2*n+1

值得一提的是,不同程序的运行时间,更多场景中比较的是在最坏条件下程序的运行时间。以上面这段程序为例,最坏条件即指的是当 n、m 都为无限大时此段程序的运行时间。
要知道,当 n、m 都无限大时,我们完全就可以认为 n==m。在此基础上,2*n*m+2*n+1 又可以简化为 2*n2+2*n+1,这就是此段程序在最坏情况下的运行时间,也就是此段程序的频度。

如果比较以上 2 段程序的运行时间,即比较 2n+1 和 2*n2+2*n+1 的大小,显然当 n 无限大时,前者要远远小于后者,如上图所示

事实上,对于一个算法(或者一段程序)来说,其最简频度往往就是最深层次的循环结构中某一条语句的执行次数。例如 2n+1 最简为 n,实际上就是 a++ 语句的执行次数;同样 2n2+2n+1 简化为 n2,实际上就是最内层循环中 num++ 语句的执行次数。

数据结构推出了大 O 记法(注意,是大写的字母 O,不是数字 0)来表示算法(程序)的运行时间。发展至今,此方法已为大多数人所采纳。

用大 O 记法表示上面 2 段程序的运行时间,则上面第一段程序的时间复杂度为 O(n),第二段程序的时间复杂度为 O(n2)。

常用的几种时间复杂度,以及它们之间的大小关系:

O(1)常数阶 < O(logn)对数阶 < O(n)线性阶 < O(n2)平方阶 < O(n3)(立方阶) < O(2n) (指数阶)

空间复杂度

算法的空间复杂度是指算法需要消耗的内存空间。其计算和表示方法与时间复杂度类似,一般都用复杂度的渐近性来表示。同时间复杂度相比,空间复杂度的分析要简单得多。

和时间复杂度类似,一个算法的空间复杂度,也常用大 O 记法表示。

要知道每一个算法所编写的程序,运行过程中都需要占用大小不等的存储空间,例如:

  • 程序代码本身所占用的存储空间;
  • 程序中如果需要输入输出数据,也会占用一定的存储空间;
  • 程序在运行过程中,可能还需要临时申请更多的存储空间。

首先,程序自身所占用的存储空间取决于其包含的代码量,如果要压缩这部分存储空间,就要求我们在实现功能的同时,尽可能编写足够短的代码。
程序运行过程中输入输出的数据,往往由要解决的问题而定,即便所用算法不同,程序输入输出所占用的存储空间也是相近的。
事实上,对算法的空间复杂度影响最大的,往往是程序运行过程中所申请的临时存储空间。不同的算法所编写出的程序,其运行时申请的临时存储空间通常会有较大不同。

举个例子:

int n;
scanf("%d", &n);
int a[10];

通过分析不难看出,这段程序在运行时所申请的临时空间,并不随 n 的值而变化。而如果将第 3 行代码改为:

int a[n];

此时,程序运行所申请的临时空间,和 n 值有直接的关联。
所以,如果程序所占用的存储空间和输入值无关,则该程序的空间复杂度就为 O(1);反之,如果有关,则需要进一步判断它们之间的关系:

  • 如果随着输入值 n 的增大,程序申请的临时空间成线性增长,则程序的空间复杂度用 O(n) 表示;
  • 如果随着输入值 n 的增大,程序申请的临时空间成 n2 关系增长,则程序的空间复杂度用 O(n2) 表示;
  • 如果随着输入值 n 的增大,程序申请的临时空间成 n3 关系增长,则程序的空间复杂度用 O(n3) 表示;
  • 等等。

在多数场景中,一个好的算法往往更注重的是时间复杂度的比较,而空间复杂度只要在一个合理的范围内就可以。

数据结构与算法——算法基础相关推荐

  1. 数据结构与算法之基础概述

    目录 数据结构和算法的重要性 数据结构概述 逻辑结构 存储结构 算法概述 如何理解"大O记法" 时间复杂度 空间复杂度 数据结构和算法的重要性 算法是程序的灵魂,优秀的程序可以在海 ...

  2. 数据结构视频教程 -《零基础学算法》

    打包下载请访问:史上最全的数据结构视频教程系列分享之<零基础学算法>,转载请保留出处和链接! 更多优秀资源请访问:我是码农 本教程主要分为上.下两部分,共10章.上篇用5章的篇幅介绍了算法 ...

  3. 数据结构之排序算法:基础概念

    排序算法:基础概念 思维导图: 排序的定义: 算法的稳定性: 内部排序和外部排序: 思维导图: 排序的定义: 算法的稳定性: 内部排序和外部排序:

  4. 【从蛋壳到满天飞】JS 数据结构解析和算法实现-AVL树(一)

    前言 [从蛋壳到满天飞]JS 数据结构解析和算法实现,全部文章大概的内容如下: Arrays(数组).Stacks(栈).Queues(队列).LinkedList(链表).Recursion(递归思 ...

  5. python数据结构推荐书-「算法与数据结构」从入门到进阶吐血整理推荐书单

    推荐一下「算法与数据结构」从入门到进阶的书单. 一.入门系列 这些书籍通过图片.打比方等通俗易懂的方法来讲述,让你能达到懂一些基础算法,线性表,堆栈,队列,树,图,DP算法,背包问题等,不要求会实现, ...

  6. Algorithm:【Algorithm算法进阶之路】之数据结构二十多种算法演示

    Algorithm:[Algorithm算法进阶之路]之数据结构二十多种算法演示 目录 一.数据结构算法 1.顺序表 2.链表 3.栈和队列 4.串的模式匹配 5.稀疏矩阵 6.广义表 7.二叉树 8 ...

  7. 【从蛋壳到满天飞】JS 数据结构解析和算法实现-堆和优先队列(一)

    前言 [从蛋壳到满天飞]JS 数据结构解析和算法实现,全部文章大概的内容如下: Arrays(数组).Stacks(栈).Queues(队列).LinkedList(链表).Recursion(递归思 ...

  8. 【数据结构】排序算法

    1,概念 在最好情况下,直接插入排序.冒泡排序的 时间复杂度最低. 在评价情况下,直接快速排序.堆排序.归并排序的 时间复杂度最低. 1)插入排序和选择排序 插入排序:直接插入排序.折半插入排序.2- ...

  9. 尚硅谷Java数据结构和java算法,韩顺平数据结构和算法课后作业01

    尚硅谷Java数据结构和java算法,韩顺平数据结构和算法课后作业第一题 要求: 1)在前面的基础上,将稀疏数组保存到磁盘上,比如map.data 2) 恢复原来的数组时,读取map.data进行恢复 ...

  10. 数据结构_dfs深度优先算法入门(C语言)

    数据结构_dfs深度优先算法入门(C语言) 文章目录 数据结构_dfs深度优先算法入门(C语言) 0.闲话 1.个人理解 2.全排列问题(1到n的排列组合) 2.八皇后问题求解 3.二维迷宫 (1)只 ...

最新文章

  1. 百度:2020年十大科技趋势
  2. Nodejs的模块系统以及require的机制
  3. 34. Search for a Range
  4. hdu4038贪心(最快上升倍率,好题)
  5. 群晖 设置 php 服务器,群晖NAS服务器iSCSI管理器配置连接及使用说明
  6. 属性值动态调整_这可能是你见过最牛的CAD粗糙度动态块了!
  7. Python_mlab_3D作图/gif
  8. c语言把一段编码注释,C语言编码规范——着重注意点整理
  9. Linux 初始化系统 systemd - journald 日志
  10. tomcat8安装及配置详细步骤(win10)
  11. KiCad 5 版本体验记录
  12. mysql离散查询_MySQL多表查询与子查询
  13. seo关键词扩展-自动关键词拓展软件免费下载
  14. Hackintosh(黑苹果)bigsur (opencore引导)超级详细教程
  15. R时间序列分析|SP500股指的ARIMA模型预测与残差ARCH效应分析
  16. 语雀转换发布CSDN和语雀导出图片图片无法识别处理(针对typora)
  17. 零代码搭建一个温度传感器数据采集与显示软件
  18. 蓝牙血压计PCBA硬件解决方案
  19. 有限元方法求解二维拉普拉斯方程C++实现
  20. 一个ABAP中级开发工程师应该学习什么

热门文章

  1. 张鑫溢:9.19黄金行情预测行情趋势分析及黄金原油独家操作建议指导.
  2. NodeMCU 通过MQTT 连接阿里云物联网
  3. 10年,20年后,你会是什么样子?
  4. Vue+wangeditor富文本+element——--上传+下载文件+图片预览
  5. ssm+redis缓存配置
  6. 【互联网企业名称由来系列】三:百度
  7. 深耕技术的同时,别忘了走出自己的舒适区
  8. HDU4262 Juggler 线段树
  9. 前端接口报错431解决办法
  10. 简介 FL Studio 中 Fruity Soft Clipper 效果器