【数据结构】复杂度详解


目录

(一)算法的复杂度

(二)时间复杂度

(1)练笔+解释:

i,示例1

ii,示例2

iii,二分查找

 iv,斐波那契

(三)空间复杂度

 练笔+解释:

i,冒泡排序

ii,斐波那契

(四)常见复杂度对比:


正文开始:

        我们为什么要讨论复杂度呢?因为复杂度能够衡量一个程序算法的好坏,关乎你写的程序能否在你的这台计算机上执行,如果能够执行,执行的效率又怎么样?如果程序的空间复杂度太大,可能根本无法在计算机上执行,因为计算机没有足够大的空间;如果时间复杂度太大,那么在有限的时间内可能根本没办法得到答案;因此,讨论复杂度是必要的。

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

(一)算法的复杂度

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


(二)时间复杂度

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

        时间复杂度并不是表示一个程序解决问题需要花多少时间,而是当问题规模扩大后,程序需要的时间长度增长得有多快。也就是说,对于高速处理数据的计算机来说,处理某一个特定数据的效率不能衡量一个程序的好坏,而应该看当这个数据的规模变大到数百倍后,程序运行时间是否还是一样,或者也跟着慢了数百倍,或者变慢了数万倍。(来自 <什么是P问题、NP问题和NPC问题 | Matrix67: The Aha Moments>)

         我们计算时间复杂度时,我们其实并不一定要计算精确的执行次数,而只需要大概执行次数,那么这里我们使用大O的渐进表示法。

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


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

大O的渐进表示法去掉了那些对结果影响不大的项,简洁明了的表示出了执行次数。
有些算法的时间复杂度存在最好、平均和最坏情况:


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


        在实际中一般情况关注的是算法的最坏运行情况。

 

(1)练笔+解释:

i,示例1

//在这个函数中,count++一共被执行了多少次?
void Fun_example1(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;
    }

    printf("%d\n", count);
}

         在Fun_example1函数中,count++语句一共被执行了F(N)=N^2+2*N+10次;随着N的增大,N^2对时间复杂度的影响逐渐凸显,因此N^2是最高阶项,保留最高结项得到Fun_example1的时间复杂度为O(N^2)。


ii,示例2

//这个函数呢,count++被执行了多少次?
void Func_example2(int N)
{
    int count = 0;

    for (int k = 0; k < 2 * N ; ++ k)
    {
        ++count;
    }

    int M = 10;

    while (M--)
    {
        ++count;
    }

    printf("%d\n", count);
}

        在Fun_example2函数中,count++语句一共被执行了F(N)=2*N+10次;随着N的增大,2*N对时间复杂度的影响逐渐凸显,因此2*N是最高阶项,保留最高阶项并去掉最高阶项的系数得到Fun_example1的时间复杂度为O(N)。


iii,二分查找

//二分查找的时间复杂度是多少?
int BinarySearch(int* a, int n, int x)
{
    assert(a);

    int begin = 0;
    int end = n-1;

    // [begin, end]:begin和end是左闭右闭区间,因此有=号
    while (begin <= end)
    {
    int mid = begin + ((end-begin)>>1);

    if (a[mid] < x)
        begin = mid+1;
    else if (a[mid] > x)
        end = mid-1;
    else
        return mid;
    }
    return -1;
}

        二分查找的基本操作最好执行一次,最坏执行O(logN)次,时间复杂度按照最坏的算,是O(logN)。(在算法分析中,如果没有特殊说明,logN表示以二为底N的对数)


 iv,斐波那契

 斐波那契

//你能计算斐波那契的时间复杂度吗?
long long Fib(size_t N)
{
    if(N < 3)
        return 1;

    return Fib(N-1) + Fib(N-2);
}

 当n=3时,递归展开图如图:

 当n=4,递归展开图如图:

        

当n=5,递归展开图如图: 

         我在作图的时候其实是挺方便的,做n=5的图只需将n=4与n=3的图放在下边即可,这就是复用。但是计算机在计算的时候不会像我这样复用已经计算出来的结果,对于递归的每一层,计算机都会从最开始的第一层算到这一层。换句话说:我可以n的值为3和4的图链接起来,形成n=5的图;计算机在计算n=5的递归值时,计算机不会将n的值为3和4的递归结果加起来得到5,而是从n=1或2算到n=3的结果,在同样算到n=4的结果,在这之后再相加得到n=5的值。

(这预示着斐波那契递归算法的效率是极低的!)

随着n的增大:

递归树越来越接近满二叉树,它比满二叉树缺少了一部分:

         假设递归树的高度为h,那么整个递归过程的时间复杂度可以近似表示为每一层的节点数乘以高度h。因此,时间复杂度可以表示为:

T(n) = O(2^0) + O(2^1) + O(2^2) + ... + O(2^h)

        由于每一层的节点数是逐渐减少的,可以将上述等式转化为以下形式:

T(n) ≤ O(2^0) + O(2^1) + O(2^2) + ... + O(2^(h-1)) + O(2^h)

(你也可以对等比数列求和)

        我们知道,对于任意正整数k,2^k ≥ k。因此,上述等式可以进一步简化为:

T(n) ≤ O(h2^h)

        由于递归树的高度h与输入规模n之间存在一个关系h = O(log n),因此可以将上述等式进一步简化为:

T(n) ≤ O(log n * 2^log n) = O(n log n)

所以,使用递归方式求解斐波那契数列的时间复杂度可以表示为O(n log n)。


(三)空间复杂度

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

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


空间复杂度与时间复杂度不同的是:

        空间的销毁是归还使用权,操作系统仍然可以使用,因此时间是逐渐积累的,是一去不复返的;而空间是可以重复利用的。

 练笔+解释:

i,冒泡排序

// 计算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;
    }
}

         开辟了常数个额外空间,所以空间复杂度为O(1)。


ii,斐波那契

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

        递归调用了N次,开辟每个栈帧开辟了常数个空间,空间复杂度为O(N)。


        而斐波那契的空间是动态的,既有开辟又有释放,按照最大的占用空间算,空间复杂度为O(N)。

(四)常见复杂度对比:

 


完~

未经作者同意禁止转载

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

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

相关文章

带使能控制的锂电池充放电解决方案

一、产品概述 TP4594R 是一款集成线性充电管理、同步升压转换、电池电量指示和多种保护功能的单芯片电源管理 SOC&#xff0c;为锂电池的充放电提供完整的单芯片电源解决方案。 TP4594R 内部集成了线性充电管理模块、同步升压放电管理模块、电量检测与 LED 指示模块、保护模块…

企业指标体系建设与管理:运用MECE原则与战略地图,打造完美闭环

在数字化时代&#xff0c;数据已经成为企业的核心资产。为了更好地利用这些数据&#xff0c;企业需要建立一套科学、完整、高效的指标体系。而在这个过程中&#xff0c;MECE原则&#xff08;Mutually Exclusive, Collectively Exhaustive&#xff0c;即“相互独立&#xff0c;完…

day04-Maven-SpringBootWeb入门

文章目录 01. Maven1.1 课程安排1.2 什么是Maven1.3 Maven的作用1.4 Maven模型1.5 Maven仓库1.6 Maven安装1.6.1 下载1.6.2 安装步骤 2 IDEA集成Maven2.1 配置Maven环境2.1.1 当前工程设置2.1.2 全局设置 2.2 创建Maven项目2.3 POM配置详解2.4 Maven坐标详解2.5 导入Maven项目 …

探索Ubuntu命令行:常见问题与解决方案

一、引言 Ubuntu&#xff0c;作为一款流行的Linux发行版&#xff0c;其命令行界面&#xff08;CLI&#xff09;为用户提供了丰富的功能和灵活性。然而&#xff0c;对于新手来说&#xff0c;命令行可能会带来一些挑战。本文将探讨一些在使用Ubuntu命令行时可能遇到的问题及其解决…

#QT(DEMO)

1.IDE&#xff1a;QTCreator 2.实验&#xff1a;打印"hello wolrd" 3.记录 &#xff08;1&#xff09;创建一个新工程&#xff1a; 新建好一个工程存放文件夹&#xff08;路径不能有中文&#xff09;,然后按下图配置 &#xff08;2&#xff09;点击widgets.ui拖入以…

数学建模【多元线性回归模型】

一、多元线性回归模型简介 回归分析是数据分析中最基础也是最重要的分析工具&#xff0c;绝大多数的数据分析问题&#xff0c;都可以使用回归的思想来解决。回归分析的任务就是&#xff0c;通过研究自变量X和因变量Y的相关关系&#xff0c;尝试去解释Y的形成机制&#xff0c;进…

一篇了解电阻的使用

目录 一、电阻理论基础 1.电阻的定义 2.欧姆定律 3.电阻决定式 4.电阻的串并联​编辑 5.电阻的功率 6.温度对电阻的影响 二、电阻的选型 1.安装方式 2.电阻值 &#xff08;1&#xff09;电阻值的标称 &#xff08;2&#xff09;电阻值的确定 &#xff08;3&#x…

图片上的物品怎么抠出来?这三种方法教你快速消除

怎么把图片上的物品抠出来&#xff1f;这是一个在设计、摄影和后期制作中经常遇到的问题。在很多设计项目中&#xff0c;我们可能需要从一张图片中扣出某个物品&#xff0c;以便在其他背景中使用&#xff0c;或者将其与其他图像组合在一起。今天&#xff0c;我们就来分享三种常…

力扣刷题记录--463. 岛屿的周长

题目链接&#xff1a;463. 岛屿的周长 - 力扣&#xff08;LeetCode&#xff09; 题目描述 我的代码实现 class Solution {public int islandPerimeter(int[][] grid) { int result0; int rowgrid.length; int colgrid[0].length; for(int i0;i<row;i){for(int j0;j<col…

FPGA时序约束与分析--数据到达路径和数据需求路径

文章目录 前言一、定义二、时序模型三、公式推导前言 时序约束的定义–设计者根据实际的系统功能,通过时序约束的方式提出时序要求; FPGA 编译工具根据设计者的时序要求,进行布局布线;编译完成后, FPGA 编译工具还需要针对布局布线的结果,套用特定的时序模型( FPGA 器件…

Git 初试 安装

Git初识 遇到问题&#xff1a; 在生活和学习中&#xff0c;我们会遇到这样的问题&#xff0c;比如上交论文的时候&#xff0c;老师让你改了一遍又一遍&#xff0c;结果改到最后一版的时候&#xff0c;说你这个还不如你第一版的或者前几版的&#xff0c;老师又说&#xff0c;把…

美女街拍3000张高清图

美女街拍3000张高清图&#xff0c;需要的可以直接下载 2.资源下载 ​途径一&#xff1a;点击以下链接直接下载 美女街拍3000张高清图 途径二&#xff1a;直接长按住以下图片识别进去下载即可

揭秘App访问量背后的秘密:数据统计与分析

在移动互联网时代&#xff0c;App已成为人们日常生活的重要组成部分。对于App运营者来说&#xff0c;了解用户的访问量、行为习惯等数据至关重要。本文将深入探讨如何精准统计App访问量&#xff0c;为运营者提供有价值的数据支持。 一、App访问量统计的重要性 访问量是衡量A…

jmeter 二次开发详解

背景&#xff1a; JMeter 是一个功能强大的性能测试工具&#xff0c;但它可能无法满足特定项目或组织的特定需求。通过进行二次开发&#xff0c;可以定制 JMeter&#xff0c;使其适应具体项目的需求。例如&#xff0c;可能需要添加自定义的 测试元件、报告生成器或结果分析器…

Springboot+vue的船舶监造系统(有报告)。Javaee项目,springboot vue前后端分离项目。

演示视频&#xff1a; Springbootvue的船舶监造系统&#xff08;有报告&#xff09;。Javaee项目&#xff0c;springboot vue前后端分离项目。 项目介绍&#xff1a; 本文设计了一个基于Springbootvue的船舶监造系统&#xff0c;采用M&#xff08;model&#xff09;V&#xff…

温湿度传感器SHT21

SHT21是一款基于IIC的温湿度传感器&#xff0c;它的引脚及定义如下&#xff1a; 标准的IIC器件&#xff0c;没有其他多余的引脚&#xff0c;应用框图如下&#xff1a; 温度的测量范围是-40到125℃&#xff0c;湿度测量范围0-100%RH&#xff0c;具体参数及采样精度见下图&#x…

鸿蒙ArkTs开发问题总结

版本问题 现阶段鸿蒙ArkTs开发主要分为两个版本 HarmonyOS3.x.x(API9)及HarmonyOS4.x.x(API10) 一下简称为 API9,API10 官方现在所有案例均以 HarmonyOS4.x.x(API10) 为基础请注意选择分支 API9&HarmonyOS3.x.x 鸿蒙开发编译器默认下载的为public版本SDK不是全量SDK需要…

【Linux】输入系统应用

# 前置知识 (1)输入子系统分为三层&#xff0c;分别是事件处理层、核心层、设备驱动层&#xff1b; (2)鼠标移动、键盘按键按下等输入事件都需要通过设备驱动层→核心层→事件处理层→用户空间&#xff0c;层层上报&#xff0c;直到应用程序; 事件处理层 (1)事情处理层主要是负…

Windows10蓝牙开关按钮不见了问题??

Windows10蓝牙开关按钮不见了问题&#xff1f;&#xff1f;此类问题一般是系统更新不及时的bug&#xff0c;遗漏掉了蓝牙相关驱动插件 试过很多方法&#xff0c;直接下载一个驱动人生即可&#xff0c;主要通过官网下载 下载这个就行 打开软件自动扫描就可以了 最后查看结果

Linkedln领英账号限制问题|通过代理IP安全使用Linkedln

LinkedIn是跨境外贸必备的拓客工具&#xff0c;世界各地的许多专业人士都使用领英来作为发布和共享内容的主要工具&#xff0c;这使得它成为跨境出海必备的渠道工具。 但是不少做外贸的朋友都知道&#xff0c;领英账号很容易遭遇限制封禁&#xff0c;但如果善用工具&#xff0…