数据结构之时间复杂度与空间复杂度

1.算法效率

1.1 如何衡量一个算法的好坏?

比方说我们非常熟悉的斐波拉契数列:

long long Fib(int N)
{if(N < 3)return 1;return Fib(N-1) + Fib(N-2);
}

递归实现方式非常简洁,但一定好吗?如何衡量其好与坏?

1.2算法的复杂度

定义:

算法在编写成可执行程序后,运行时需要耗费时间资源和空间(内存)资源 。因此 衡量一个算法的好坏,一般
是从时间和空间两个维度来衡量的,即时间复杂度和空间复杂度。
时间复杂度主要衡量一个算法的运行快慢,而空间复杂度主要衡量一个算法运行所需要的额外空间。在计算
机发展的早期,计算机的存储容量很小。所以对空间复杂度很是在乎。但是经过计算机行业的迅速发展,计
算机的存储容量已经达到了很高的程度。所以我们如今已经不需要再特别关注一个算法的空间复杂度。

1.3复杂度对于校招的重要性

a50562e16d9d47a7b0e853a2800b38ad.png2.时间复杂度

定义:

在计算机科学中, 算法的时间复杂度是一个函数,它定量描述了该算法的运行时间。一
个算法执行所耗费的时间,从理论上说,是不能算出来的,只有你把你的程序放在机器上跑起来,才能知道。但是我们需要每个算法都上机测试吗?是可以都上机测试,但是这很麻烦,所以才有了时间复杂度这个 分析方式。一个算法所花费的时间与其中语句的执行次数成正比例, 算法中的基本操作的执行次数,为算法的时间复杂度。
就是找到某条基本语句与问题规模N之间的数学表达式,就是算出了该算法的时间复杂度
2.大O的渐进表示法规则

时间复杂度和空间复杂度一般都使用大O的渐进表示法进行表示,大O的渐进表示法规则如下:

1、所有常数都用常数1表示。
2、只保留最高阶项。
3、如果最高阶项存在且不是1,则去除与这个项的系数,得到的结果就是大O阶。

我们就以开头所提及的递归得到斐波拉契数列的代码为例子,如果我们传递了一个参数n,即我们要求f(n)的值,那么应该运行多少次?,如f(n)=f(n-1)+f(n-2),而f(n-1)=f(n-2)+f(n-3) ,f(n-2)=f(n-3)+f(n-4)...
635bb5209010402586f03fb9adbb7937.png因为右下角的递归函数会提前结束,所以图中三角形必定有一块是没有数据的,但是当N趋于无穷时,那缺省的一小块便可以忽略不计,这时总共调用斐波那契函数的次数为:
20210406181445207.png再有等比数列求和,得出2N - 1。
那么用大O渐进表示法表示该函数的时间复杂度为:O(2N) 。
注意: 递归算法的时间复杂度 = 递归的次数 * 每次递归函数中的次数。
再举一个列子:
//计算Func1的时间复杂度
void Func1(int N)
{int count = 0;for (int i = 0; i < 2 * N; i++){for (int j = 0; j < 2 * N; j++){count++;}}for (int k = 0; k < 2 * N; k++){count++;}
}

该函数执行了一个嵌套循环共执行了4 * pow(n,2)次,又单执行一个for循环共执行2*N次

那么时间复杂度为4*pow(n,2)+2*n 次用大O渐进表示法:O(pow(n,2);

例2:

//计算Func2的时间复杂度
void Func2(int N)
{int count = 0;for (int k = 0; k < 100; k++){++count;}printf("%d\n", count);
}

该函数内部执行了一个for循环共100次,Func2函数内语句的执行次数不会随着传入的变量N的改变而改变,即执行的次数为常数次。Func2函数的时间复杂度为T(N) = 100 。

由大O渐进表示法,所有的常数都用1来表示,即O(1);

空间复杂度:

空间复杂度是对一个算法在运行过程中临时占用存储空间大小的量度。空间复杂度不是程序占用了多少字节的空间,因为这个也没太大意义,所以空间复杂度算的是变量的个数。空间复杂度计算规则基本跟时间复杂度类似,也使用大O渐进表示法。

例1:

//计算冒泡排序函数的空间复杂度
void BubbleSort(int* a, int N)
{assert(a);for (int i = 0; i < N; i++){int exchange = 0;for (int j = 0; j < N - 1 - i; j++){if (a[j]>a[j + 1]){int tmp = a[j];a[j] = a[j + 1];a[j + 1] = tmp;exchange = 1;}}if (exchange == 0)break;}
}

例2:

//计算阶乘递归函数的空间复杂度
long long Factorial(int N)
{return N < 2 ? N : Factorial(N - 1)*N;
}

阶乘递归函数会依次调用Factorial(N),Factorial(N-1),…,Factorial(2),Factorial(1),开辟了N个空间,所以空间复杂度为O(N) 。同理我们开头所提到的斐波拉契函数也是O(N)。

注:递归算法的空间复杂度通常是递归的深度(即递归多少层)。

感谢你的阅读,下次再见。

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/220866.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Ansible的重用(include和import)

环境 管理节点&#xff1a;Ubuntu 22.04控制节点&#xff1a;CentOS 8Ansible&#xff1a;2.15.6 重用 Ansible提供四种可重用的工件&#xff1a; variable文件&#xff1a;只包含变量的文件task文件&#xff1a;只包含task的文件playbook&#xff1a;可包含play、变量、ta…

【go入门】表单

4.1 处理表单的输入 先来看一个表单递交的例子&#xff0c;我们有如下的表单内容&#xff0c;命名成文件login.gtpl(放入当前新建项目的目录里面) <html> <head> <title></title> </head> <body> <form action"/login" meth…

上海交通大学生存手册

强烈推荐所有大学生去阅读《上海交通大学生存手册》。虽然它可能有些冗长&#xff0c;但非常重要&#xff0c;因为它道出了大学教育的本质。 如果几年前我能够看到这本书&#xff0c;也许我的大学生活会有所不同。现在我将向正在上大学或者将要上大学的你推荐这本书。 无论你…

NX二次开发UF_CURVE_ask_spline_feature 函数介绍

文章作者&#xff1a;里海 来源网站&#xff1a;https://blog.csdn.net/WangPaiFeiXingYuan UF_CURVE_ask_spline_feature Defined in: uf_curve.h int UF_CURVE_ask_spline_feature(tag_t feature_id, tag_t * spline ) overview 概述 Inquire a general spline feature. …

Gee教程1.HTTP基础

标准库启动web服务 Go语言内置了 net/http库&#xff0c;封装了HTTP网络编程的基础的接口。这个Web 框架便是基于net/http的。我们先回顾下这个库的使用。 package mainimport ("fmt""log""net/http" )func main() {//可以写成匿名函数(lambda…

持续集成部署-k8s-配置与存储-存储类:动态创建NFS-PV案例

动态创建NFS-PV案例 1. 前置条件2. StorageClass 存储类的概念和使用3. RBAC 配置4. storageClass 配置5. 创建应用&#xff0c;测试 PVC 的自动配置6. 解决 PVC 为 Pending 状态问题7. 单独测试自动创建 PVC 1. 前置条件 这里使用 NFS 存储的方式&#xff0c;来演示动态创建 …

Java王者荣耀小游戏

Background类 package LX;import java.awt.*; //背景类 public class Background extends GameObject{public Background(GameFrame gameFrame) {super(gameFrame);}Image bg Toolkit.getDefaultToolkit().getImage("C:\\Users\\ASUS\\Desktop\\王者荣耀图片\\Map.jpg&…

【JavaEE初阶】Thread 类及常见方法、线程的状态

目录 1、Thread 类及常见方法 1.1 Thread 的常见构造方法 1.2 Thread 的几个常见属性 1.3 启动⼀个线程 - start() 1.4 中断⼀个线程 1.5 等待⼀个线程 - join() 1.6 获取当前线程引用 1.7 休眠当前线程 2、线程的状态 2.1 观察线程的所有状态 2.2 线程状态和状…

P17C++析构函数

目录 前言 01 什么是析构函数 1.1 举个栗子 02 为什么要写析构函数 前言 今天我们要讨论一下它的“孪生兄弟”&#xff0c;析构函数&#xff0c;它们在某些方面非常相似。 与构造函数相反&#xff0c;当对象结束其生命周期&#xff0c;如对象所在的函数已调用完毕时&…

Redis:持久化RDB和AOF

目录 概述RDB持久化流程指定备份文件的名称指定备份文件存放的目录触发RDB备份redis.conf 其他一些配置rdb的备份和恢复优缺点停止RDB AOF持久化流程AOF启动/修复/恢复AOF同步频率设置rewrite压缩原理触发机制重写流程no-appendfsync-on-rewrite 优缺点 如何选择 概述 Redis是…

An example of a function uniformly continuous on R but not Lipschitz continuous

See https://math.stackexchange.com/questions/69457/an-example-of-a-function-uniformly-continuous-on-mathbbr-but-not-lipschitz?noredirect1

jetpack的简单使用

Jetpack ViewModel&#xff1a; 什么是ViewModel&#xff1f; ViewModel 是 Android 架构组件的一部分&#xff0c;用于帮助开发者管理 UI 数据的持久性和生命周期感知。ViewModel 的主要目的是将 UI 数据与界面控制逻辑分离&#xff0c;以便更好地管理数据的生命周期&#…