数据结构和算法(一)复杂度分析

数据结构与算法目录(https://www.cnblogs.com/binarylei/p/10115867.html)

数据结构和算法本身解决的是 "快" 和 "省" 的问题,即如何让代码运行得更快,如何让代码更省存储空间。所以,执行效率是算法一个非常重要的考量指标。那如何来衡量你编写的算法代码的执行效率呢?这里就要用:时间复杂度空间复杂度分析。

复杂度分析是整个算法学习的精髓,只要掌握了它,数据结构和算法的内容基本上就掌握了一半。

1. 时间复杂度

1.1 什么是时间复杂度

一个算法花费的时间与算法中语句的执行次数成正比例,哪个算法中语句执行次数多,它花费时间就多。一个算法中的语句执行次数称为语句频度或时间频度。记为 T(n)。

在刚才提到的时间频度中,n 称为问题的规模,当 n 不断变化时,时间频度 T(n) 也会不断变化。但有时我们想知道它变化时呈现什么规律。为此,我们引入时间复杂度概念。

一般情况下,算法中基本操作重复执行的次数是问题规模 n 的某个函数,用 T(n) 表示,若有某个辅助函数 f(n),使得当 n 趋近于无穷大时,T(n) / f(n) 的极限值为不等于零的常数,则称 f(n) 是 T(n) 的同数量级函数。记作 T(n) = O(f(n)),称 O(f(n)) 为算法的渐进时间复杂度,简称时间复杂度

  • 随着问题规模 n 的增大,常数部分的影响越来越小

    T(n) = 2n2 + 4n +log2n + 4

  • 随着问题规模 n 的増大,增长最快的项影响越来越大

    T(n) = 2n2 + 4n + log2n + 4

  • 渐进时间复杂度只关注增长最快的项

    T(n) = O(n2) // 去除常数系数,去除复杂度小的项

  • logn 一般表示 log2n

有时候,算法中基本操作重复执行的次数还随问题的输入数据集不同而不同,如在冒泡排序中,输入数据有序而无序,其结果是不一样的。此时,我们计算平均值。

1.2 时间复杂度分析

(1)只关注循环执行次数最多的一段代码

(2)加法法则:总复杂度等于量级最大的那段代码的复杂度

(3)乘法法则:嵌套代码的复杂度等于嵌套内外代码复杂度的乘积

实例 1: T(n) = 1 + n + 2n2 = O(n2)

sum = 0;                   // 执行 1 次
for(i = 1; i <= n; i++) // 执行 n 次
for(j = 1;j <= n;j++) // 执行 n^2 次
sum++; // 执行 n^2 次

实例 2:T(n) = 1 + 4n = O(n)

a = 0;  b= 1;                // 执行 1 次
for (i = 1; i <= n; i++) { // 执行 n 次
s = a + b; // 执行 n 次
b = a; // 执行 n 次
a = s; // 执行 n 次
}

实例 3:T(n) = O(log2n)

i = 1;            // 执行 1 次
while (i <= n)
i = i * 2; // 设频度是 f(n),则:2^f(n)<=n; f(n)<=log2n

1.3 常见的时间复杂度

虽然代码千差万别,但是常见的复杂度量级并不多。我稍微总结了一下,这些复杂度量级几乎涵盖了你今后可以接触的所有代码的复杂度量级。对于以下复杂度量级,可以粗略地分为两类,多项式量级和非多项式量级。其中,非多项式量级只有两个:O(2n) 和 O(n!),执行效率也非常低。

  1. 常量阶 O(1)
  2. 对数阶 O(logn)
  3. 线性阶 O(n)
  4. 线性对数阶 O(nlogn)
  5. 平方阶 O(n2) O(n3) O(n4)
  6. 指数阶 O(2n):不常见
  7. 阶乘阶 O(n!):不常见

常见的算法的时间复杂度之间的关系为:

O(1) < O(logn) < O(n) < O(nlogn) < O(n2) < O(2n)<O(n!) < O(nn)

1.4 主定律

1.5 最好、最坏、平均、均摊时间复杂度

  1. 最好情况时间复杂度:代码在最坏情况下执行的时间复杂度。(少使用)
  2. 最坏情况时间复杂度:代码在最理想情况下执行的时间复杂度。(少使用)
  3. 平均时间复杂度:用代码在所有情况下执行的次数的加权平均值表示。(少使用)
  4. 均摊时间复杂度:在代码执行的所有复杂度情况中绝大部分是低级别的复杂度,个别情况是高级别复杂度且发生具有时序关系时,可以将个别高级别复杂度均摊到低级别复杂度上,也叫摊还算法。(极少使用)

下面以一段代码示例,对上述 4 个概念进行简单的分析。

int arr[] = new int[10];
int len = 10;
int i = 0; void add(int element) { // 插入元素时,如果空间不够,先扩容再插入
if (i >= len) {
int newArr[] = new int[len * 2];
for (int j = 0; j < len; ++j) {
newArr[j] = arr[j];
}
arr = newArr;
len = 2 * len;
}
arr[i] = element;
++i;
}

上述示例:最好是 O(1),最坏是O(n),平均和均摊都是O(1)。

摊还算法分析,执行 n 次 O(1) 插入后会执行一次 O(n) 插入,那么我们可以将这次 O(n) 插入公摊到 n 次操作上,这样均摊后仍是 O(1)。

个人体会:平均和平摊基本就是一个概念,平摊是特殊的平均。在分析时间复杂度是 O(1) 还是 O(n) 的时候最简单就是凭感觉,出现 O(1) 的次数远大于出现 O(n) 出现的次数,那么平均平摊时间复杂度就是O(1)。

2.2 空间复杂度

空间复杂度:算法所需存储空间的度量,记作: S(n) = O(f(n)),其中 n 为问题的规模。

我们常见的空间复杂度就是 O(1)、O(n)、O(n2),像 O(logn)、O(nlogn) 这样的对数阶复杂度平时都用不到。如下代码空间复杂度 O(n)。

int i = 0;                     // 申请空间大小为 1
int[] arr = new int[n]; // 申请空间大小为 n 的数组
for (i; i < n; i++) {
arr[i] = i;
}

一个算法在计算机存储器上所占用的存储空间,包括存储算法本身所占用的存储空间,算法的输入输出数据所占用的存储空间和算法在运行过程中临时占用的存储空间这三个方面。如果额外空间相对于输入数据量来说是个常数,则称此算法是原地工作。

算法的输入输出数据所占用的存储空间是由要解决的问题决定的,是通过参数表由调用函数传递而来的,它不随本算法的不同而改变。存储算法本身所占用的存储空间与算法书写的长短成正比,要压缩这方面的存储空间,就必须编写出较短的算法。


每天用心记录一点点。内容也许不重要,但习惯很重要!

Java数据结构和算法(一)概念的更多相关文章

  1. Java数据结构和算法(一)——简介

    本系列博客我们将学习数据结构和算法,为什么要学习数据结构和算法,这里我举个简单的例子. 编程好比是一辆汽车,而数据结构和算法是汽车内部的变速箱.一个开车的人不懂变速箱的原理也是能开车的,同理一个不懂数 ...

  2. Java数据结构和算法(二)——数组

    上篇博客我们简单介绍了数据结构和算法的概念,对此模糊很正常,后面会慢慢通过具体的实例来介绍.本篇博客我们介绍数据结构的鼻祖——数组,可以说数组几乎能表示一切的数据结构,在每一门编程语言中,数组都是重要 ...

  3. Java数据结构和算法 - 堆

    堆的介绍 Q: 什么是堆? A: 这里的“堆”是指一种特殊的二叉树,不要和Java.C/C++等编程语言里的“堆”混淆,后者指的是程序员用new能得到的计算机内存的可用部分 A: 堆是有如下特点的二叉 ...

  4. Java数据结构和算法 - 二叉树

    前言 数据结构可划分为线性结构.树型结构和图型结构三大类.前面几篇讨论了数组.栈和队列.链表都是线性结构.树型结构中每个结点只允许有一个直接前驱结点,但允许有一个以上直接后驱结点.树型结构有树和二叉树 ...

  5. Java数据结构和算法 - 递归

    三角数字 Q: 什么是三角数字? A: 据说一群在毕达哥拉斯领导下工作的古希腊的数学家,发现了在数学序列1,3,6,10,15,21,……中有一种奇特的联系.这个数列中的第N项是由第N-1项加N得到的 ...

  6. Java数据结构和算法 - OverView

    Q: 为什么要学习数据结构与算法? A: 如果说Java语言是自动档轿车,C语言就是手动档吉普.数据结构呢?是变速箱的工作原理.你完全可以不知道变速箱怎样工作,就把自动档的车子从1档开到4档,而且未必 ...

  7. Java数据结构和算法 - 什么是2-3-4树

    Q1: 什么是2-3-4树? A1: 在介绍2-3-4树之前,我们先说明二叉树和多叉树的概念. 二叉树:每个节点有一个数据项,最多有两个子节点. 多叉树:(multiway tree)允许每个节点有更 ...

  8. Java数据结构和算法(一)线性结构

    Java数据结构和算法(一)线性结构 数据结构与算法目录(https://www.cnblogs.com/binarylei/p/10115867.html) 线性表 是一种逻辑结构,相同数据类型的 ...

  9. Java数据结构和算法(一)树

    Java数据结构和算法(一)树 数据结构与算法目录(https://www.cnblogs.com/binarylei/p/10115867.html) 前面讲到的链表.栈和队列都是一对一的线性结构, ...

  10. Java数据结构和算法(四)赫夫曼树

    Java数据结构和算法(四)赫夫曼树 数据结构与算法目录(https://www.cnblogs.com/binarylei/p/10115867.html) 赫夫曼树又称为最优二叉树,赫夫曼树的一个 ...

随机推荐

  1. python高亮显示输出

    知识内容: 1.高亮输出语法 2.高亮输出实例 前言: 在做购物车这道题时遇到了高亮显示输出某些内容的需求,于是就学了一下这方面的知识,以下是python高亮显示输出的使用方法: 购物车链接:  ht ...

  2. java基础:关于java流与文件操作

    1.描述:流是字节数据或字符数据序列.Java采用输入流对象和输出流对象来支持程序对数据的输入和输出.输入流对象提供了数据从源点流向程序的管道,程序可以从输入流对象读取数据:输出流对象提供了数据从程序 ...

  3. diffutils's diff

    比较文件的差异 diff,用来查看两个文件的差异之处,或者两个目录之中的对应文件.倘若比较的不是文本文件,而是二进制文件,只会报告两者不同.输出文本文件的异同时,可以按照多个格式输出,根据使用的选项决 ...

  4. bootstrap3中select2的默认值和下拉框的禁用

    最近做项目用到了select2插件,需求中需要给下拉框设置默认值之后,禁用下拉框,我开始的写法是这样的 <script type="text/javascript"> ...

  5. python学习中的第一个例子

    搭建python 先学习下当小白鼠 1 看下自己的python版本 python -v 2 然后,用pip安装开发Web App需要的第三方库: 异步框架aiohttp: pip3 install a ...

  6. 36. CentOS-6.3安装Mysql集群

    安装要求 安装环境:CentOS-6.3安装方式:源码编译安装 软件名称:mysql-cluster-gpl-7.2.6-linux2.6-x86_64.tar.gz下载地址:http://mysql ...

  7. class(类的使用说明)

    class 的三大特性 封装:内部调用对于外部用户是透明的 继承: 在分类里的属性,方法被自动继承 多态:调用这个功能,可以使多个类同时执行 r1 = Role(r1, 'Alex', 'Police ...

  8. Ambari安装Hadoop集群

    * System Environment:centOS6.7 1.Prepare the Environment 1)Set Up Password-less SSH : (Generate publ ...

  9. requireJS-初识

    浅谈requireJS 2016-04-26 21:44 by 猴子猿, 726 阅读, 0 评论, 收藏, 编辑 项目中大都使用模块化开发,requireJS作为AMD模块开发的典范,所以有必要学习 ...

  10. numpy linspace arange函数

    linspace(start, end, num_of_points), 区间 [start, end],产生一个等差数列,差为:(end-start)/(num_of_point-1). arang ...