【数据结构与算法篇】之时间复杂度与空间复杂度

news2024/10/6 16:14:25


❤️博客主页: 小镇敲码人
🍏 欢迎关注:👍点赞 👂🏽留言 😍收藏
🌞友友们暑假快乐,好久不见呀!!!💖💖💖
🍉 有人曾经问过我这样一个问题,“人终其一身,执着追求的东西究竟是什么?”我是这样回答的,”我们终其一生都在寻找着那个和我们灵魂极其契合的人,可最后才发现,那个人只有也只能是自己,学会在无聊时消遣自己是非常重要的“,所以无论目前屏幕上的你深处怎样的绝境之中,请不要放弃自己,好好的爱自己就是度过绝境的最佳武器!!!😸😸😸

一、时间复杂度

1.1时间复杂度的定义

         在计算机与科学中,算法的时间复杂度(time complexity)是一个函数,它定性的描述算法的运行时间,表示一个程序来回执行的次数,但不定量。这个函数的自变量是算法输入值的字符串的长度,即 N N N。时间复杂度常用大O符号表述,只包括那个幂次最高的项数。使用这种方式时,时间复杂度可被称为是渐近的,也就是 lim ⁡ N → ∞ O ( N ) \lim\limits_{N\rarr\infin}O(N) NlimO(N)时的情况。例如,如果一个算法对于任何大小为 N N N的输入,它至多需要 5 N 3 N^3 N3 + 3 N 3N 3N 的时间运行完毕,那么它的渐近时间复杂度是 O ( N 3 ) O(N^3) O(N3)

  • 注意:时间复杂度不计算时间,只计算程序的执行次数。

常见的时间复杂度包括:

  • 常数时间复杂度( O ( 1 ) ) O(1)) O(1)):算法的执行时间与输入规模无关,常数级别的执行时间。
  • 线性时间复杂度( O ( N ) O(N) O(N)):算法的执行时间与输入规模线性相关,随着输入规模的增加而线性增长。
  • 对数时间复杂度( O ( l o g N ) O(log N) O(logN)):算法的执行时间与输入规模的对数关系,通常是二分查找等算法的时间复杂度。
  • 平方时间复杂度( O ( N 2 ) O(N^2) O(N2)):算法的执行时间与输入规模的平方相关,通常是嵌套循环等算法的时间复杂度。
  • 线性对数时间复杂度 ( O ( N ∗ l o g N ) ) (O(N*log N)) (O(NlogN)) :它表示随着输入规模 N 的增加,算法的执行时间以 N 乘以 log N 的速度增长,线性对数时间复杂度常常出现在一些高效的排序算法(如快速排序和归并排序)以及一些分治算法中。

注意:嵌套循环的算法时间复杂度不一定是 O ( N 2 ) O(N^2) O(N2)

通过分析算法的时间复杂度,我们可以更好地理解算法的性能特点,并进行算法的选择和优化。

1.2 常见的时间复杂度的计算

1.2.1 常数时间复杂度( O ( 1 ) ) O(1)) O(1))

    int main()
    {
      int a = 0;
      a += 1;
      printf("%d",&a);
      return 0;
    }

这段代码执行了四次操作。我们逐行分析代码的执行过程:

1.int a = 0;:这行代码初始化了整数变量a,将其赋值为 0。
2. a += 1;:这行代码将变量 a的值增加 1,现在 a 的值为 1。
3.printf("%d", &a);:这行代码使用 printf 函数打印变量 a 的值的内存地址,格式化输出为十进制整数。
4. return 0;:在 main 函数的结尾,使用 return 语句将返回值设为 0。
因此,代码执行了四次操作。

  • 若对于一个算法 T ( n ) T(n) T(n)的上界与输入大小无关,则称其具有常数时间,记作O(1)时间,故而这个算法的时间复杂度为 O ( 1 ) O(1) O(1)

1.2.2 线性时间复杂度( O ( N ) O(N) O(N)

int main()
{
  int n = 0;
  scanf("%d",&n);
  int sum = 1;
  for(int i = 1;i < n;;i++)
    sum *= i;
  printf("%d",sum);
  return 0;
}

这段代码的执行过程如下:

  1. int n = 0;:这行代码声明了一个整数变量 n,并将其初始化为 0。
  2. scanf("%d",&n);:这行代码使用 scanf 函数从标准输入中读取一个整数,并将其赋值给变量 n。
  3. int sum = 1;:这行代码声明了一个整数变量 sum,并将其初始化为 1。
  4. for(int i = 1;i < n;i++):这行代码开始一个 for 循环,循环变量 i 的初始值为 1,循环条件为 i < n。
  5. sum *= i;:这行代码将变量 sum 与变量 i 相乘,并将结果赋值给 sum。
  6. printf("%d",sum);:这行代码使用 printf 函数打印变量 sum 的值。
  7. return 0;:在 main 函数的结尾,使用 return 语句将返回值设为 0。
  8. for循环中,变量 i 的初始值为 1,每次循环 i 的值递增 1,直到达到 n 的值。因此,for 循环的执行次数为 n - 1。在循环中,执行了一次乘法操作 sum *= i,共执行了 n - 1 次。
  • 故而程序的执行次数为: T ( N ) = 5 + 2 ∗ ( N − 1 ) = 2 N + 3 , T(N)=5+2*(N-1)=2N+3, TN=5+2(N1)=2N+3, lim ⁡ N → ∞ T ( N ) = O ( N ) \lim\limits_{N\rarr\infin}T(N)=O(N) NlimT(N)=O(N)

1.2.3 对数时间复杂度( O ( l o g N ) O(log N) O(logN)

#include <stdio.h>

void logarithmicAlgorithm(int n) {
    int i = 1;
    while (i < n) {
        printf("%d\n", i);
        i *= 2;  // 对数时间复杂度的关键步骤
    }
}

int main() {
    int n = 16;
    logarithmicAlgorithm(n);
    return 0;
}

这段代码的执行过程如下:

  1. main函数中,声明一个整数变量 n 并赋值为 16。
  2. 调用logarithmicAlgorithm()函数,并将变量 n 作为参数传递给该函数。
  3. 进入logarithmicAlgorithm函数。
  4. logarithmicAlgorithm 函数中,声明一个整数变量 i 并赋值为 1。
  5. 进入 while 循环,检查条件 i < n 是否满足。由于此时 i 的初始值为 1,且 1 小于 16,条件成立,进入循环体。
  6. 在循环体内,使用printf 函数打印变量 i 的值。
  7. 执行i *= 2,将 i 的值乘以 2。
  8. 回到循环的开头,再次检查条件 i < n。如果条件仍然成立,继续执行循环体;如果条件不成立,跳出循环。
  9. 当 i 的值达到或超过 n(即 16)时,条件 i < n 不再满足,跳出循环。
  10. 退出logarithmicAlgorithm函数。
  11. 回到 main函数,继续执行后续的代码。执行return 0; 语句,结束程序。
  • while循环的判断执行次数为x, 2 = N , ⇒ 2 x − 1 = l o g 2 N + 1 2 = N,\rArr 2^{x-1} = log_2N+1 2=N,2x1=log2N+1
    while循环内的执行次数为 2 ∗ l o g 2 N 2*log_2N 2log2N
  • 故而程序的执行次数为: T ( N ) = 7 + 3 ∗ l o g 2 N , T(N)= 7+3 * log_2N, TN=7+3log2N, lim ⁡ N → ∞ T ( N ) = O ( l o g N ) \lim\limits_{N\rarr\infin}T(N)=O(logN) NlimT(N)=O(logN)

1.2.4 平方时间复杂度( O ( N 2 ) O(N^2) O(N2)

#include <stdio.h>

void quadraticAlgorithm(int n) {
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= n; j++) {
            printf("(%d, %d)\n", i, j);
        }
    }
}

int main() {
    int n = 3;
    quadraticAlgorithm(n);
    return 0;
}

这段代码的执行过程如下:

  1. main函数中声明一个整数变量n,并赋值为3。
  2. 调用quadraticAlgorithm()函数,并把变量n作为形参传递给函数。
  3. 进入函数quadraticAlgorithm()
  4. 外部for循环的判断执行次数为n+1,外部循环循环一次内部for循环判断的执行次数为n+1,printf语句的执行次数为n。

故而外部for循环的执行次数就为n+1,内部for循环的总执行次数就为n*(n+1),内部for循环的printf语句的总执行次数为 n 2 n^2 n2

  1. 退出函数quadraticAlgorithm()
  2. 继续执行main函数中的return 0;语句,结束程序。
  • 故程序的执行次数为: T ( N ) = 1 + 1 + 1 + ( N + 1 ) + N ∗ ( N + 1 ) + N ∗ N + 1 + 1 = 2 N 2 + 2 N + 6 , T(N) =1+1+1+(N+1)+N*(N+1)+N*N+1+1=2N^2+2N+6, T(N)=1+1+1+(N+1)+N(N+1)+NN+1+1=2N2+2N+6, lim ⁡ N → ∞ T ( N ) = O ( N 2 ) \lim\limits_{N\rarr\infin}T(N)=O(N^2) NlimT(N)=O(N2)

1.3 常见的函数的时间复杂度


以下图片整理了一些常用的时间复杂度类。表中, p o l y ( x ) = x O ( 1 ) poly(x) = xO(1) poly(x)=xO(1),也就是 x 的多项式。也可以访问网页版点击此处跳转
在这里插入图片描述在这里插入图片描述

二、空间复杂度

2.1 空间复杂度的定义

      在计算机科学中,一个算法或程序的空间复杂度定性地描述该算法或程序运行所需要的存储空间大小。空间复杂度是相应计算问题的输入值的长度的函数,它表示一个算法完全执行所需要的存储空间大小。和时间复杂度类似,空间复杂度通常也使用大O记号来渐进地表示。例如: O ( n ) 、 O ( n α ) 、 O ( n ∗ l o g n ) 、 O ( 2 n ) O(n)、{\displaystyle O(n^{\alpha })}、O(n*logn)、O(2^n) O(n)O(nα)O(nlogn)O(2n)
      空间复杂度用于评估算法在执行过程中所需的额外空间或内存的量级或增长趋势。它主要关注算法在运行过程中所使用的额外存储空间,包括算法使用的数据结构、临时变量、递归调用等。

  • 注意:空间复杂度不计算空间,只计算变量的个数

常见的空间复杂度包括:

  • 常数空间复杂度 ( O ( 1 ) ) (O(1)) (O(1)):算法使用固定的额外空间,不随输入的增加而变化。
  • 线性空间复杂度 ( O ( n ) ) (O(n)) (O(n)):算法使用的额外空间与输入规模成线性关系。
  • 平方空间复杂度 ( O ( n 2 ) ) (O(n^2)) (O(n2)):算法使用的额外空间与输入规模成平方关系。
  • 对数空间复杂度 ( O ( l o g n ) ) (O(logn)) (O(logn)):算法使用的额外空间与输入规模成对数关系。

2.2 常见的空间复杂度的计算

  • 就是去算变量和函数调用开辟的栈帧的个数之和

2.2.1 常数空间复杂度 ( O ( 1 ) ) (O(1)) (O(1))

void printHello() {
    printf("Hello, world!\n");
}
  • 函数调用一次,开辟一个栈帧,空间复杂度为 O ( 1 ) O(1) O(1)

2.2.2 线性空间复杂度 ( O ( n ) ) (O(n)) (O(n))

void printNumbers(int n) {
    int *arr =(int*)malloc(n * sizeof(int));
    // 执行其他操作...
    free(arr);
}

  • 开辟了一个动态数组,变量的个数与 n n n成正比,取极限,和时间复杂度一样,常数可以忽略,空间复杂度为 O ( n ) O(n) O(n)

2.2.3 平方空间复杂度 ( O ( n 2 ) ) (O(n^2)) (O(n2))

void printPairs(int n) {
    int **matrix = (int**)malloc(n * sizeof(int *));
    for (int i = 0; i < n; i++) {
        matrix[i] = (int*)malloc(n * sizeof(int));
    }
    // 执行其他操作...
    for (int i = 0; i < n; i++) {
        free(matrix[i]);
    }
    free(matrix);
}

  • 开辟了一个二维的动态数组,变量的个数与 n 2 n^2 n2成正比,取极限,忽略常数,空间复杂度为 O ( n 2 ) O(n^2) O(n2)

2.2.4 对数空间复杂度 ( O ( l o g n ) ) (O(logn)) (O(logn))

// 递归二分查找函数
int binarySearch(int arr[], int low, int high, int target) {
    if (low <= high) {
        int mid = low + (high - low) / 2;

        if (arr[mid] == target) {
            return mid;
        } else if (arr[mid] < target) {
            return binarySearch(arr, mid + 1, high, target);
        } else {
            return binarySearch(arr, low, mid - 1, target);
        }
    }
    return -1; // 如果找不到目标元素,返回-1
}

    数组是提前排好序的递增数组,假设同时存在的栈帧最多为x个,因为只有找不到或者找到了target函数才会返回,此时区间长度要么是1,要么没找到不构成区间了,函数调用产生的栈帧才会开始销毁,有 2 x = n → x = l o g 2 n 2^x=n\to x=log_2n 2x=nx=log2n,也就是最多开辟了 l o g 2 n log_2n log2n个栈帧。

  • 故取极限,空间复杂度 T ( N ) 为 T(N)为 T(N)$ lim ⁡ N → ∞ T ( N ) = O ( l o g N ) \lim\limits_{N\rarr\infin}T(N)=O(logN) NlimT(N)=O(logN)

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

蓝桥杯专题-试题版含答案-【荷兰国旗问题】【正三角形的外接圆面积】【比较字母大小】【车牌号】

点击跳转专栏>Unity3D特效百例点击跳转专栏>案例项目实战源码点击跳转专栏>游戏脚本-辅助自动化点击跳转专栏>Android控件全解手册点击跳转专栏>Scratch编程案例点击跳转>软考全系列点击跳转>蓝桥系列 &#x1f449;关于作者 专注于Android/Unity和各种游…

SSTI模板注入

目录 1、原理简述 2、常用payload及相关脚本 &#xff08;1&#xff09;.__class__ &#xff08;2&#xff09;.__class__.__base__ &#xff08;3&#xff09;.__class__.__base__.__subclasses__() &#xff08;4&#xff09;.__class__.__base__.__subclass…

【周末闲谈】浅谈“AI+算力”

随着人工智能技术的飞速发展&#xff0c;“AI算力”的结合应用已成为科技行业的热点话题&#xff0c;甚至诞生出“AI算力最强龙头“的网络热门等式。该组合不仅可以提高计算效率&#xff0c;还可以为各行各业带来更强大的数据处理和分析能力&#xff0c;从而推动创新和增长。 文…

ue4:Dota总结—HUD篇

1.绘制ui&#xff1a; DrawMoney&#xff1a; DrawPower&#xff1a; 点击ui响应事件&#xff1a; 点击响应显示对应的模型&#xff1a; 点击ui拖动模型跟随鼠标移动&#xff1a; 显示ui&#xff1a;PlayerContrler&#xff1a;

【JAVA】Java 开发环境配置(WIndows篇)

个人主页&#xff1a;【&#x1f60a;个人主页】 系列专栏&#xff1a;【初始JAVA】 文章目录 前言下载JDK配置环境变量JAVA_HOME 设置PATH设置CLASSPATH 设置变量设置参数 前言 在前篇中我们介绍了JAVA语言的诞生与发展&#xff0c;现在是时候去学习使用他们了。 下载JDK 首先…

常微分方程(ODE)求解方法总结(续)

常微分方程&#xff08;ODE&#xff09;求解方法总结&#xff08;续&#xff09; 1 隐式方法2 多步法2.1 二阶方法2.1.1 非自启动修恩方法2.2 开型和闭型积分公式2.3 高阶多步法 1 隐式方法 常微分方程&#xff08;ODE&#xff09;求解方法总结 里面介绍了我称为“正常思路”的…

Jira UI Locations及注意事项总结

issue view ui locations : https://developer.atlassian.com/server/jira/platform/issue-view-ui-locations/#issue-operations-bar-locations1.问题操作栏Issue Operations Bar Locations模块分为两部分: opsbar-operationsflopsbar-transitions两个location.共同定义了问题…

【力扣】111、二叉树的最小深度

111、二叉树的最小深度 给定一个二叉树&#xff0c;找出其最小深度。 最小深度是从根节点到最近叶子节点的最短路径上的节点数量。 说明&#xff1a;叶子节点是指没有子节点的节点。 // var minDepth function(root){if(!root) return 0;const stack [ [ root ,1] ];//…

零拷贝详解

目录 一、什么是零拷贝 二、传统的IO执行流程 三、零拷贝相关的知识点回顾 1、内核空间&用户空间 2、用户态&内核态 3、上下文切换 4、虚拟内存 5、DMA技术 四、零拷贝实现的几种方式 1、mmapwrite实现的零拷贝 2、sendfile实现的零拷贝 3、sendfileDMA sc…

MySQL原理探索——23 MySQL是怎么保证数据不丢的

今天这篇文章&#xff0c;我会继续介绍在业务高峰期临时提升性能的方法。从文章标题“MySQL 是怎么保证数据不丢的”&#xff0c;你就可以看出来&#xff0c;今天我介绍的方法&#xff0c;跟数据的可靠性有关。 在前面文章&#xff0c;我都着重介绍了 WAL 机制&#xff08;你可…

ElementUI plus框架Table表格cell-style属性的使用

官方文档说明&#xff1a; 例&#xff1a;设置单元格文字居中 Object方式&#xff1a; function方式&#xff1a;

安全 --- http报文包详解及burp简单使用

HTTP HTTP&#xff08;超文本传输协议&#xff09;是今天所有web应用程序使用的通信协议。最初HTTP只是一个为了获取基本文本的静态资源而开发的简单协议&#xff0c;后来对其进行扩展和利用&#xff0c;使其发展为能够支持如今常见的复杂分布式应用程序。 &#xff08;1&…

PADS-LAYOUT菜单及工具使用

目录 1菜单栏 1.1文件菜单 1.2编辑菜单 1.3查看菜单 1.4设置菜单 1.5工具菜单 1.6帮助菜单 2工具栏 2.1标准工具栏 2.2绘图工具栏 2.3设计工具栏 2.4尺寸标注工具栏 2.5ECO工具栏 3系统配置 3.1全局选项 3.2设计选项 3.3栅格和捕获选项 3.4显示选项 3.5布线选…

【UnityDOTS 六】预制实例化成Entity

预制实例化成Entity 前言 从Authoring模式中&#xff0c;如何通过预制件来实例化一个对应的Entity对象到DOTS系统中。 一、Authoring模式与Runtime模式 Authoring创作模式&#xff1a;即我们熟悉的方便操作的创建预制的模式 Runtime模式&#xff1a;运行模式&#xff0c;即在…

Three.js教程:网格模型

推荐&#xff1a;将 NSDT场景编辑器 加到你的3D工具链 工具集&#xff1a; NSDT简石数字孪生 网格模型(三角形概念) 本节课给大家演示网格模型Mesh渲染自定义几何体BufferGeometry的顶点坐标,通过这样一个例子帮助大家建立**三角形(面)**的概念 三角形(面) 网格模型Mesh其实…

Spring Boot 中的 XA 事务

Spring Boot 中的 XA 事务 在现代化的应用程序开发中&#xff0c;事务管理是一个重要的话题。事务管理可以确保数据的一致性和完整性&#xff0c;同时也可以避免数据丢失和冲突等问题。在分布式环境中&#xff0c;XA 事务是一种常用的事务管理方式。在本文中&#xff0c;我们将…

基于麦克风阵列模块I2s6路slot数字音频信号的ADSP/STM32F4处理

hezkz17进数字音频系统研究开发交流答疑 1麦克风阵列 2 ADAU1452 DSP 输入接口 3 PCM数据算法处理

uni-app获取节点的相关信息

获取单个节点&#xff1a; selectorQuery.select(selector) 在当前页面下选择第一个匹配选择器 selector 的节点&#xff0c;返回一个 NodesRef 对象实例&#xff0c;可以用于获取节点信息。 selector 说明&#xff1a; selector 类似于 CSS 的选择器&#xff0c;但仅支持下列…

Jenkins 参数化构建

目录 前言&#xff1a; 以下是Jenkins官方的介绍&#xff1a; 首先新建一个自由风格的job&#xff0c;然后勾选“This project is parameterized”&#xff0c;如下图&#xff1a; 勾选参数构建 choice parameterized&#xff1a; 选项&#xff1a; 使用参数&#xff1a;…