数据结构之算法复杂度

news/2024/9/21 14:03:02/

目录

前言

一、复杂度的概念

二、时间复杂度

三、大O的渐进表示法

四、空间复杂度

五、常见复杂度对比

总结



前言

        本文主要讲述数据结构中的算法复杂度


一、复杂度的概念

算法在编写成可执行程序后,运行时需要耗费时间资源和空间(内存)资源。因此衡量一个算法的好坏,一般是从时间和空间两个维度来衡量的,即时间复杂度空间复杂度

  • 时间复杂度主要衡量一个算法的运行快慢。
  • 空间复杂度主要衡量一个算法运行所需要的额外空间。

        在计算机发展的早期,计算机的存储容量很小。所以对空间复杂度很是在乎。但是经过计算机行业的迅速发展,计算机的存储容量已经达到了很高的程度。所以我们如今已经不需要再特别关注⼀个算法的空间复杂度。


二、时间复杂度

在计算机科学中,算法的时间复杂度是一个函数式T(N),它定量描述了该算法的运行时间。时间复杂度是衡量程序的时间效率。

那么为什么不去计算程序的运行时间呢?

  1. 因为程序运行时间和编译环境和运行机器的配置都有关系,比如同一个算法程序,用⼀个老编译器进行编译和新编译器编译,在同样机器下运行时间不同。
  2. 同一个算法程序,用⼀个老低配置机器和新高配置机器,运行时间也不同。
  3. 并且时间只能程序写好后测试,不能写程序前通过理论思想计算评估。

那么算法的时间复杂度是一个函数式T(N),到底是什么呢?

答:这个T(N)函数式计算了程序的执行次数。

通过c语言编译链接章节学习,我们知道算法程序被编译后生成二进制指令,程序运行,就是cpu执行这些编译好的指令。那么我们通过程序代码或者理论思想计算出程序的执行次数的函数式T(N),假设每句指令执行时间基本一样(实际中有差别,但是微乎其微),那么执行次数和运行时间就是等比正相关, 这样也脱离了具体的编译运行环境。执行次数就可以代表程序时间效率的优劣。比如解决一个问题的算法a程序T(N)=N,算法b程序T(N)=N^2,那么算法a的效率⼀定优于算法b。

示例:

//请计算⼀下Func1中++count语句总共执行了多少次?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--){++count;}
}

画图表示:

解析:实际中我们计算时间复杂度时,计算的也不是程序的精确的执行次数,精确执行次数计算起来还是很麻烦的(不同的⼀句程序代码,编译出的指令条数都是不⼀样的),计算出精确的执行次数意义也不大, 因为我们计算时间复杂度只是想比较算法程序的增长量级,也就是当N不断变大时T(N)的差别,上面我们已经看到了当N不断变大时常数和低阶项对结果的影响很小,所以我们只需要计算程序能代表增长量级的大概执行次数,复杂度的表示通常使用大O的渐进表示法。


三、大O的渐进表示法

大O符号(BigOnotation):是用于描述函数渐进行为的数学符号

推导大O阶规则:

  1. 时间复杂度函数式 T(N) 中,只保留最高阶项,去掉那些低阶项,因为当 N 不断变大时, 低阶项对结果影响越来越小,当 N 无穷大时,就可以忽略不计了。
  2. 如果最高阶项存在且不是 1 ,则去除这个项目的常数系数,因为当 N 不断变大,这个系数对结果影响越来越小,当 N 无穷大时,就可以忽略不计了。
  3. T(N) 中如果没有 N 相关的项目,只有常数项,用常数 1 取代所有加法常数

通过大O渐进表示法,我们可以推出上述 Func1 的时间复杂度了:(因为主要是++count的运行次数,所以时间复杂度也是主要计算它的运行次数)

 

示例1:

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

画图表示:


示例2:

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

画面表示:

解释:如果M>>N,则时间复杂度可以为O(M),反之N>>M,则时间复杂度可以写成O(N),如果M==N,则时间复杂度为O(M+N)


示例3:

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

画图表示:


示例4:

//计算strchr的时间复杂度?const char* strchr(const char* str, int character)
{const char* p_begin = str;while (*p_begin != character){if (*p_begin == '\0')return NULL;p_begin++;}return p_begin;
}

画图表示:

通过上面我们会发现,有些算法的时间复杂度存在最好、平均和最坏情况。

  • 最坏情况:任意输入规模的最大运行次数(上界)
  • 平均情况:任意输入规模的期望运行次数
  • 平均情况:任意输入规模的期望运行次数

大O的渐进表示法在实际中一般情况关注的是算法的上界,也就是最坏运行情况。

因此示例4的时间复杂度应该为:O(N)


示例5:冒泡排序

//计算BubbleSort的时间复杂度?void BubbleSort(int* a, int n)
{assert(a);for (size_t end = n; end > 0; --end){int exchange = 0;for (size_t i = 1; i < end; ++i){if (a[i - 1] > a[i]){Swap(&a[i - 1], &a[i]);exchange = 1;}}if (exchange == 0)break;}
}

画图表示:


示例6:对数的计算

//求时间复杂度void func5(int n)
{int cnt = 1;while (cnt < n){cnt *= 2;}
}

画图表示:

注:log 的底数可写可不写,如果底数为10可写成 lg


示例7:递归的计算

//计算阶乘递归Fac的时间复杂度?long long Fac(size_t N)
{if (0 == N)return 1;return Fac(N - 1) * N;
}

画图表示:


四、空间复杂度

空间复杂度也是一个数学表达式,是对一个算法在运行过程中因为算法需要额外临时开辟的空间。

空间复杂度计算规则基本跟时间复杂度类似,也使用大O渐进表示法

注意:函数运行时所需要的(函数栈帧)栈空间(存储参数、局部变量、一些寄存器信息等)在编译期间已经确定好 了,因此空间复杂度主要通过函数在运行时候显式申请的额外空间来确定。

空间复杂度计算示例

示例1:冒泡排序

//计算BubbleSort的空间复杂度?void BubbleSort(int* a, int n)
{assert(a);for (size_t end = n; end > 0; --end){int exchange = 0;for (size_t i = 1; i < end; ++i){if (a[i - 1] > a[i]){Swap(&a[i - 1], &a[i]);exchange = 1;}}if (exchange == 0)break;}
}

画图表示:

示例2:递归函数

//计算阶乘递归Fac的空间复杂度?long long Fac(size_t N)
{if (N == 0)return 1;return Fac(N - 1) * N;
}

画图表示:


五、常见复杂度对比

常见的复杂度有:n、logn、n*logn、n的平方、n的三次方、2的n次方、n的阶乘

解析:很明显,n的平方、n的三次方、2的n次方、n的阶乘这些复杂度都比较高。而n、logn、n*logn这些复杂度就比较低,算法的效率比较高。


总结

        以上就是本文的全部内容,感谢支持


http://www.ppmy.cn/news/1528422.html

相关文章

并发容器(Map、List、Set)实战及其原理分析

1. JUC包下的并发容器 Java的集合容器框架中&#xff0c;主要有四大类别&#xff1a;List、Set、Queue、Map&#xff0c;大家熟知的这些集合类ArrayList、LinkedList、HashMap这些容器都是非线程安全的。 所以&#xff0c;Java先提供了同步容器供用户使用。同步容器可以简单地…

【24华为杯数模研赛赛题思路已出】国赛F题思路丨附参考代码丨免费分享

2024年华为杯研赛F题解题思路 F题 X射线脉冲星光子到达时间建模 问题1 1.1题目分析 问题1 要求我们建立卫星轨道根数与其位置和速度关系的数学模型。轨道根数&#xff08;或轨道参数&#xff09;包括偏心率 e 、角动量 h 、轨道倾角 i 、真近点角 θ 、升交点赤经Ω 和近地点…

华为云ROMA Connect聚焦创新,在Gartner®峰会发布智能集成新视角

9月9日-9月10日&#xff0c;Gartner全球应用创新及商业解决方案峰会在伦敦举行&#xff0c;围绕企业应用策略、智能平台工程和生成式AI&#xff0c;来自全球的1700业内专家共同探讨新趋势带来的机遇和挑战。华为云ROMA Connect发表 “人工智能”主题演讲之一&#xff0c;展现新…

关于网络、模型、算法的一些理论知识补充(重新在概念上定义自己研究的方向!!!)

其实&#xff0c;我之前有点分不太清这些网络、模型、算法到底是谁是谁&#xff0c;谁又包含谁&#xff1f;就比如说&#xff0c;我导师问我想搞什么&#xff0c;我说我想研究算法&#xff0c;但是我好像又不是特别清楚&#xff0c;算法究竟是个什么玩意&#xff1f;我想做的东…

mysql学习教程,从入门到精通,SQL ORDER BY 子句(14)

1、SQL ORDER BY 子句 在本教程中&#xff0c;您将学习如何对SELECTSQL查询返回的数据进行排序。 1.1、对结果集排序 通常&#xff0c;当您使用SELECT语句从表中获取数据时&#xff0c;结果集中的行没有任何特定的顺序。如果要按特定顺序排列结果集&#xff0c;则可以在语句…

Spring Boot-分布式系统问题

Spring Boot 在分布式系统中的常见问题及解决方案 随着互联网的发展&#xff0c;系统规模和复杂度越来越大&#xff0c;分布式系统成为应对高并发、大数据量场景的重要架构选择。Spring Boot 作为一种轻量级的开发框架&#xff0c;广泛应用于构建微服务和分布式系统中。然而&a…

navicat无法连接远程mysql数据库1130报错的解决方法

出现报错&#xff1a;1130 - Host ipaddress is not allowed to connect to this MySQL serve navicat&#xff0c;当前ip不允许连接到这个MySQL服务 解决当前ip无法连接远程mysql的方法 1. 查看mysql端口&#xff0c;并在服务器安全组中放开相应入方向端口后重启服务器 sud…

PHP:强大的Web开发语言

PHP&#xff1a;强大的Web开发语言 一、PHP 简介及优势 PHP 的基本概念 PHP&#xff08;PHP: Hypertext Preprocessor&#xff09;即 “超文本预处理器”&#xff0c;是一种通用开源脚本语言&#xff0c;最初由 Rasmus Lerdorf 于 1994 年创建。它可以在服务器上执行&#xf…