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

数据结构与算法目录(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. django框架预备知识

    内容: 1.web预备知识 2.django介绍 3.web框架的本质及分类 4.django安装与基本设置 1.web预备知识 HTTP协议:https://www.cnblogs.com/wyb6 ...

  2. python装饰器(docorator)详解

    引言: 装饰器是python面向对象编程三大器之一,另外两个迭代器.生成器只是我现在还没有遇到必须使用的场景,等确实需要用到的时候,在补充资料:装饰器在某些场景真的是必要的,比如定义了一个类或者一个函 ...

  3. HTML5 Canvas ( 绘制一轮弯月, 星空中的弯月 )

    <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...

  4. SpringBoot 常用注解(持续更新)

    SpringBoot 常用注解 @SpringBootApplication @Bean @ComponentScan @ControllerAdvice @ExceptionHandler @Res ...

  5. python 冷知识点

    # int could accept parameters in bool type.int(True) # result is 1 int(False) # result is 0 reprlib. ...

  6. centos7 jenkins 安装

    前提: 安装了 jdk ,我的是jdk8 第一步: https://jenkins.io/download/ 下载 可以下载 rpm文件, 标红处, 也可以下载war包(Generic Java pa ...

  7. 多字段非连续模糊查询java实现

    工作需要,写了一个实现数据库多字段模糊查询的方法,背景是输入用户的信息,如用户的userid,姓名,拼音等,可以查出相关的用户 具体如下 1. 操作一张表,可以设置表前缀 2. 可以实现中文的不连续查 ...

  8. Session的作用和使用场景

    1.session何时被创建? 客户首次访问服务器时,回话session对象被创建并分配一个唯一的Id,同时id号发送到客户端,并存入cookie,使得客户端session对象和服务器端一致. 2.如 ...

  9. SQL 数据库事务 存储过程练习

    数据库事务: 数据库事务(Database Transaction) 是指作为单个逻辑工作单元执行的一系列操作. 事务处理可以确保除非事务性单元内的所有操作都成功完成,否则不会永久更新面向数据的资源. ...

  10. HTML 练习 做简历表

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...