数据结构:时间复杂度和空间复杂度

我们知道代码和代码之间算法的不同,一定影响了代码的执行效率,那么我们该如何评判算法的好坏呢?这就涉及到了我们算法效率的分析了。

📖一、算法效率

所谓算法效率的分析分为两种:第一种时间效率,又称时间复杂度。第二种空间效率,又称空间复杂度。其中,时间复杂度主要衡量的是一个算法的运行速度,而空间复杂度主要衡量一个算法所需要的额外空间。

📖二、时间复杂度 

🐬1、概念

算法的时间复杂度其实是一个数学函数,它描述了该算法的运行时间,然而实际上,我们并不能准确的,将一个算法所耗费的时间算出来,只有在机器上跑起来,才能够得到,但是一段代码可能有多个算法,难道我们要每个都上机器上跑吗?这显然是不现实的,因此我们在这种情况下就得到了时间复杂度的分析方式:一个算法所花费的时间与其中语句的执行次数成正比例,因此我们将算法中的基本操作的执行次数,为算法的时间复杂度,并且我们将时间复杂度的表示方法称为大O的渐进表示法

🐬2、大O的渐进表示法 

我们将大O符号作为用于描述函数渐进行为的数学符号表示形式为:O(?)

?: 算法中的基本操作的执行次数

现在我们了解了大O的渐进表示法的使用,那么我们接下来看一下这段代码

public class  Test{
    public static void main(String[] args) {
        int count = 0;
        for (int i = 0; i < n; i++) {
            count++;
        }
        System.out.println(count);
    }
}

我们可以明确发现算法中的基本操作的执行次数为n次,那么我们的时间复杂度就为O(n)

再来看下面这段代码

public class  Test{
    void func1(int N){
        int count = 0;
        for (int i = 0; i < N ; i++) {
            for (int j = 0; j < N ; j++) {
                count++;
            }
        }
        for (int k = 0; k < 2 * N ; k++) {
            count++;
        }
        int M = 10;
        while ((M--) > 0) {
            count++;
        }
        System.out.println(count);
    }
    public static void main(String[] args) {
        
    }
}

我们可以发现第一个for循环的执行一次第二个for循环就执行N次,因此上面一共执行了N*N=N^2次,中间的for循环,显然是执行了2N次,而最后的while循环,由于M=10,因此执行了10次,那么这段代码的总体执行次数为(N^2+2N+10)次,那么我们的时间复杂度就是O(N^2+2N+10)次吗?

其实不是的,这时其实又涉及到了另一个方法:推导大O阶方法 

🐬3、推导大O阶方法 

  1. 用常数1取代运行时间中的所有加法常数。
  2. 在修改后的运行次数函数中,只保留最高阶项。
  3. 如果最高阶项存在且不是1,则去除与这个项目相乘的常数。得到的结果就是大O阶。

那么我们还是以上面的代码为例,我们的执行次数为N^2+2N+10,根据规则用常数1,取代所有常数:N^2+2N+1,在修改后的运行次数函数中,只保留最高阶项:N^2,如果最高阶项存在且不是1,则去除与这个项目相乘的常数:(N^2)/1 = N^2

最后根据这个规则我们就得到了最终的时间复杂度为:O(N^2)

通过上面我们会发现大O的渐进表示法去掉了那些对结果影响不大的项,简洁明了的表示出了执想次数。因此我们在实际中一般情况关注的是算法的最坏运行情况.

🐬4、常见的时间复杂度

术语
O(1)常数阶
O(N)线性阶
O(N^2)平方阶
O(logN)对数阶
O(NlogN)NlogN阶
O(N^3)立方阶
O(2^N)指数阶

从上往下时间复杂度不断增大 。

🐬5、实例

好了现在我们已经成功的了解了什么是时间复杂度和时间复杂度的表示方法了,接下来我能一起看几道经典例子。

📌(1)执行次数明确

void func(int N) {
        int count = 0;
        for (int k = 0; k < 100; k++) {
            count++;
        }
    }
 System.out.println(count);

在这段代码中我们明确的可以发现我们的算法基本操作的执行次数为100次,根据规则我们要用常数1取代所有常数,因此我们这段代码的时间复杂度应为O(1)。 而在这里我们其实也得出了一个结论,只有执行次数明确,我们就可以说这段算法的时间复杂度为O(1)(注意:并不是说整体代码的时间复杂度,只是单指这段算法)。

📌(2)冒泡排序

void bubbleSort(int[] array) {
        for (int end = array.length; end > 0; end--) {
            boolean sorted = true;
            for (int i = 1; i < end; i++) {
                if (array[i - 1] > array[i]) {
                    Swap(array, i - 1, i);
                    sorted = false;
                }
            }
            if (sorted == true) {
                break;
            }
        }
    }

首先我们将数组的长度看作N,对于一些初学者来说, 一个for循环执行一次另一个for循环执行N-1次,我们N=5为例4+3+2+1+0=10,最后为O(1)这显然是没有问题的,但是当他等于N时我们用这种方法显然是没有办法计算的,然而我们知道,算法中的基本操作的执行次数,为算法的时间复杂度,那么这段代码的基本操作是什么呢?,显而易见,就是两个数的交换,那么我们就知道了其实他的交换次数就是我们的执行次数。

其中我们根据他的交换次数得出的规律发现他是一个以1为公差的等差数列,因此利用等差数列求和公式就能得出他的总次数,最后根据规则得到他的时间复杂度为O(N^2) 

📌(3)二分查找

 int binarySearch(int[] array, int value) {
        int begin = 0;
        int end = array.length - 1;
        while (begin <= end) {
            int mid = begin + ((end-begin) / 2);
            if (array[mid] < value)
                begin = mid + 1;
            else if (array[mid] > value)
                end = mid - 1;
            else
                return mid;
        }
        return -1;
    }

二分查找又称折半查找,原理是先取中间数,将中间数与我们要找的数进行比较,如果不是在进行折半,知道找到,这题我们其实可以将他看成一个纸条,我们要找一段纸条的长度,如果我们先将他这半一次,就得到了这是最好的情况时间复杂度就为O(1),但是如果我们要找X次才能找到,那么O(X),才是我们的时间复杂度,那么X等于什么呢?我们可以想象找一次纸条就要折半,如果一次找到那么乘于一次2就等于他的长度,X次找到就是乘于X个2即2^X=N。那么

logN在算法分析中表示是 底数为2,对数为N,因此时间复杂度为O(logN)。 

📌(4)递归

long factorial(int N) {
        return N < 2 ? N : factorial(N-1) * N;
    }

我们来看这段代码,我们发现他是一段递归,而对于他的时间复杂度,我们先把N看成是1,当N=1时,我们执行次数为1,当N=2时,执行次数为2,当N=3时,执行次数为3,因此当这段代码为N时,我们总体的执行次数应为N,所以我们的时间复杂度为O(N)

📖三、空间复杂度 

🐬1、概念  

空间复杂度是对一个算法在运行过程中临时占用存储空间大小的量度。空间复杂度计算规则基
本跟时间复杂度类似,也使用大O渐进表示法。 

📌(1)

他的临时空间变量, 就是三个临时变量,所以空间复杂度为O(1)

📌(2)

他的临时空间变量为n+1,所以空间复杂度为O(n)。

📌(3) 

根据上面所学N为几就会执行几次,同样也会开辟几个临时空间,因此他的临时空间变量为N,所以空间复杂度为O(N)


好的今天我们要分享的就到这里了,我们下一篇在见!

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

《Vue3实战教程》39:Vue3无障碍访问

如果您有疑问&#xff0c;请观看视频教程《Vue3实战教程》 无障碍访问​ Web 无障碍访问 (也称为 a11y) 是指创建可供任何人使用的网站的做法——无论是身患某种障碍、通过慢速的网络连接访问、使用老旧或损坏的硬件&#xff0c;还是仅处于某种不方便的环境。例如&#xff0c;…

GESP2024年6月认证C++五级( 第三部分编程题(1)黑白格)

参考程序&#xff08;二维前缀和&#xff09; #include <iostream> #include <vector> #include <algorithm> using namespace std;int main() {int n, m, k;cin >> n >> m >> k;// 输入网格图vector<vector<int>> grid(n, v…

二、SQL语言,《数据库系统概念》,原书第7版

文章目录 一、概览SQL语言1.1 SQL 语言概述1.1.1 SQL语言的提出和发展1.1.2 SQL 语言的功能概述 1.2 利用SQL语言建立数据库1.2.1 示例1.2.2 SQL-DDL1.2.2.1 CREATE DATABASE1.2.2.2 CREATE TABLE 1.2.3 SQL-DML1.2.3.1 INSERT INTO 1.3 用SQL 语言进行简单查询1.3.1 单表查询 …

js按日期按数量进行倒序排序,然后再新增一个字段,给这个字段赋值 10 到1

效果如下图&#xff1a; 实现思路&#xff1a; 汇总数据&#xff1a;使用 reduce 方法遍历原始数据数组&#xff0c;将相同日期的数据进行合并&#xff0c;并计算每个日期的总和。创建日期映射&#xff1a;创建一个映射 dateMap&#xff0c;存储每个日期的对象列表。排序并添加…

用uniapp写一个播放视频首页页面代码

效果如下图所示 首页有导航栏&#xff0c;搜索框&#xff0c;和视频列表&#xff0c; 导航栏如下图 搜索框如下图 视频列表如下图 文件目录 视频首页页面代码如下 <template> <view class"video-home"> <!-- 搜索栏 --> <view class…

【three.js】光源

光源 光源特点 当使用MeshLambertMaterial材质时&#xff0c;会受到光线的影响&#xff0c; 我们代码里面如果没有设置光线&#xff0c;则使用MeshLambertMaterial材质修饰的模型不可见&#xff0c;这个时候&#xff0c;我们添加光线后&#xff0c;便可以看见。 环境光 定义&a…

U8G2库使用案例(stm32)

U8G2官网&#xff1a; 自己移植的U8g2库&#xff0c;OLED库超好用&#xff0c;自己封装了用户层不需要再去查资料使用&#xff0c;注释写的很多很详细&#xff0c;有示例上手就会&#xff0c;初始化也很简单 个人移植的U8g2库&#xff1a; 超简单的stm32 U8g2移植 大家可以自…

Linux 上安装 PostgreSQL

文章目录 前言一、安装PostgreSQL二、修改数据库默认数据存储目录 1.自定义数据存放目录2.修改自定义服务3.初始化数据库4.运行数据库 三、配置数据库信息 四、权限 异常处理 前言 提示&#xff1a;本次博客是centos7.9安装PostgreSQL12版本 名称 版本 Centos 7.9 postg…

HTML——56.表单发送

<!DOCTYPE html> <html><head><meta charset"UTF-8"><title>表单发送</title></head><body><!--注意&#xff1a;1.表单接收程序&#xff0c;放在服务器环境中(也就是这里的www文件目录中)2.表单发送地址&#x…

logback之pattern详解以及源码分析

目录 &#xff08;一&#xff09;pattern关键字介绍 &#xff08;二&#xff09;源码分析 &#xff08;一&#xff09;pattern关键字介绍 %d或%date&#xff1a;表示日期&#xff0c;可配置格式化%d{yyyy-MM-dd HH:mm:ss} %r或%relative&#xff1a;也是日期&#xff0c;不过…

vLLM结构化输出(Guided Decoding)

简介 vLLM 的结构化输出特性是通过“引导式解码”&#xff08;Guided Decoding&#xff09;实现的&#xff0c;这一功能允许模型在生成文本时遵循特定的格式约束&#xff0c;例如 JSON 模式或正则表达式&#xff0c;从而确保生成的内容符合预期的结构化要求。 后端引擎 启动…

CM3/CM4时钟系统

CM3/4时钟系统 1. CM3时钟系统1.1 输入时钟源------------------A1.2 锁相环PLL------------------B1.3 系统时钟SYSCLK--------C/D/E/F/G 2. CM4时钟系统2.1 输入时钟源------------------A2.2 锁相环PLL------------------B2.3 系统时钟SYSCLK--------C/D/E2.4 时钟信号输出M…

RabbitMQ实现生产者消费者

一.启动MQ 注意管理员身份进入cmd才行,我这里是在本地安装的MQ,推荐使用虚拟机安装 二.思路 官方解释RabbitMQ结构: 自我理解RabbitMQ结构: 其实RabbitMQ的服务器就像邮局一样,我们的生产者和消费者对于这个服务器来说都是消费者,因为服务器都可以向两者发送消息 环境准备 …

MySQL--》如何在SQL中巧妙运用函数与约束,优化数据处理与验证?

目录 函数使用 字符串函数 数值函数 日期函数 流程函数 约束 外键约束 约束规则 函数使用 函数是指一段可以直接被另一段程序调用的程序或代码&#xff0c;在mysql当中有许多常见的内置函数&#xff0c;接下来开始对这些内置函数及其作用进行简单的讲解和使用&#xf…

OpenLinkSaas使用手册-待办事项和通知中心

在OpenLinkSaas工作台上&#xff0c;你可以查看待办事项和未读通知。 待办事项 目前待办事项支持: 个人待办项目待办:在项目中指派给你的任务/缺陷Git待办:在Git仓库中指标给你的Issue,目前只有在AtomGit和Gitee账号登录时才支持。 通知中心 通知中心支持Git通知和邮件通知两种…

【Unity】 HTFramework框架(五十八)【进阶篇】资源及代码热更新实战演示(Deployment + HybridCLR)

更新日期&#xff1a;2025年1月2日。 Github源码&#xff1a;[点我获取源码] 索引 资源及代码热更新实战演示运行演示Demo1.克隆项目工程2.更新子模块3.打开项目4.打开入口场景5.设置远端资源服务器地址6.导入HybridCLR7.初始化HybridCLR8.发布项目9.部署资源版本10.运行Exe11.…

路由基本配置实验

路由器用于实现不同类型网络之间的互联。 路由器转发ip分组的基础是路由表。 路由表中的路由项分为直连路由项、静态路由项和动态路由项。 通过配置路由器接口的ip地址和子网掩码自动生成直连路由项。 通过手工配置创建静态路由项。 热备份路由器协议允许将由多个路由器组…

CTFshow—远程命令执行

29-35 Web29 代码利用正则匹配过滤了flag&#xff0c;后面加了/i所以不区分大小写。 可以利用通配符绕过 匹配任何字符串&#xff0f;文本&#xff0c;包括空字符串&#xff1b;*代表任意字符&#xff08;0个或多个&#xff09; ls file * ? 匹配任何一个字符&#xff08;不…

idea 的 springboot项目spring-boot-devtools 自动编译 配置热部署

1&#xff0c;设置一 2&#xff0c;设置二 设置二&#xff08;旧版本&#xff09; CtrlShiftAlt/ 点击弹出框中Registry... 引入&#xff08;如果报错&#xff0c;换不同的版本&#xff09; <dependency><groupId>org.springframework.boot</groupId><a…

Github拉取项目报错解决

前言 昨天在拉取github上面的项目报错了&#xff0c;有好几个月没用github了&#xff0c;命令如下&#xff1a; git clone gitgithub.com:zhszstudy/git-test.git报错信息&#xff1a; ssh: connect to host github.com port 22: Connection timed out fatal: Could not rea…