算法复杂度解析:时间与空间的衡量

一、什么是算法复杂度

算法复杂度是用来衡量一个算法的好坏的,算法复杂度可以分为时间复杂度和空间复杂度。

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

二、时间复杂度

简单来说,时间复杂度就是基本语句的执行次数。

我们通常使用O()来表示一个算法的复杂度,O()是用来描述函数渐进应为的数学符号。

大O的使用有以下几点规则:

  1. 只保留最高阶项,去掉低阶项。--> 当N不断变大时,低阶项的影响越来越小,N无穷大时,可以忽略不计

  2. 去除常数系数。 --> 当N不断变大时,系数对结果影响越来越小,N无穷大时,可以忽略不计

  3. 如果只有常数项,用常数1取代所有加法常数。

1. 例1

cpp 复制代码
void Func1(int N) 
{ 
    int count = 0; 
    for (int k = 0; k < 2 * N ; ++ k) 
    { 
        ++count; 
    } 
    int M = 10; 
    while (M--) 
    { 
        ++count; 
    } 
    printf("%d\n", count); 
}

观察上面代码,可以发现该程序的操作次数为 2N+10 ,根据大O的使用规则可以得出,该算法的时间复杂度为 O(N)

2.例2

cpp 复制代码
void Func2(int N) 
{ 
    int count = 0; 
    for (int k = 0; k < 100; ++ k) 
    { 
        ++count; 
    } 
    printf("%d\n", count); 
}

观察上方代码,可以发现该程序的操作次数为 100 ,根据大O的使用规则可以得出,该算法的时间复杂度为 O(1)

3.例3

cpp 复制代码
const char * strchr ( const char * str, int character)
 {
     const char* p_begin = s;
     while (*p_begin != character)
     {
        if (*p_begin == '\0')
        return NULL;
        p_begin++;
     }
     return p_begin;
 }

strchr函数用于在字符串中查找指定字符首次出现的位置。观察上方代码可以发现当要查找的字符在字符串不同位置时,程序的操作次数时不一样的,所以strchr的时间复杂度存在 最好、最坏、平均情况。⼤O的渐进表⽰法在实际中⼀般情况关注的是算法的上界,也就是最坏运⾏情况。

strchr执行的基本操作次数:

  1. 最好情况:如果要查找的字符在字符串第一个位置,则为 1

  2. 最坏情况:如果要查中的字符在字符串最后一个位置,则为N

  3. 平均情况:如果要查找的字符在字符串中间位置,则为N/2

所以,strchr的时间复杂度分为:

1.最好情况:O(1)

2.最坏情况:O(N)

3.平均情况:O(N)

4.例4

cpp 复制代码
void func3(int n)
 {
    int cnt = 1;
    while (cnt < n)
    {
        cnt *= 2;
    }
 }

观察上面代码,可以发现 2^x=n(x为操作次数)。 该程序的操作次数为 log n ,根据大O的使用规则可以得出,该算法的时间复杂度为 O(log n)

⼀般情况下不管底数是多少都可以省略不写,即可以表⽰为log n

5.例5

cpp 复制代码
long long Fac(size_t N) 
{ 
    if(0 == N) 
        return 1; 
    return Fac(N-1)*N; 
}

调⽤⼀次Fac函数的时间复杂度为O(1) 。 ⽽在Fac函数中,存在 n 次递归 调⽤Fac函数 因此阶乘递归的时间复杂度为: O(n)。

三、空间复杂度

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

1.例1

cpp 复制代码
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; 
    } 
}

BubbleSort额外申请的空间有 exchange 等有限个局部变量,使⽤了常数个额外空间 因此空间复杂度为O(1)

2.例2

cpp 复制代码
long long Fac(size_t N) 
{ 
    if(N == 0) 
        return 1; 
    return Fac(N-1)*N; 
}

Fac递归调⽤了N次,额外开辟了N个函数栈帧, 每个栈帧使⽤了常数个空间。 因此空间复杂度为:O(N)。

四、常见复杂度

|------------|------------------------|
| 复杂度 | 常见场景 |
| O(1) | 操作次数与输入规模无关,固定次数 |
| O(log n) | 每次操作将问题规模缩小一半(底数通常为 2) |
| O(n log n) | 线性时间与对数时间的乘积,常见于分治思想算法 |
| O(n) | 操作次数与输入规模成正比 |
| O(n^2) | 操作次数与输入规模的平方成正比 |
| O(2^n) | 操作次数随输入规模呈指数级增长(基数为 2) |
| O(n!) | 操作次数随输入规模呈阶乘级增长,效率极低 |

相关推荐
SuperByteMaster4 小时前
keil 工程 .gitignore配置文件
c语言
ZC跨境爬虫5 小时前
跟着 MDN 学 HTML day_9:(信件语义标记)
前端·css·笔记·ui·html
OBiO20138 小时前
Cell | 突破AAV载体容量限制!路中华/姜玉武/刘太安团队开发AAVLINK系统实现大基因递送
笔记
老花眼猫8 小时前
编制椭圆旋转绘图函数
c语言·经验分享·青少年编程·课程设计
智者知已应修善业9 小时前
【51单片机2个按键控制流水灯运行与暂停】2023-9-6
c++·经验分享·笔记·算法·51单片机
sakiko_9 小时前
UIKit学习笔记5-使用UITableView制作聊天页面
笔记·学习·swift·uikit
Alice-YUE10 小时前
【js高频八股】防抖与节流
开发语言·前端·javascript·笔记·学习·ecmascript
iCxhust11 小时前
微机原理实践教程(C语言篇)---A002流水灯
c语言·开发语言·单片机·嵌入式硬件·51单片机·课程设计·微机原理
小陈phd11 小时前
TensorRT 入门完全指南(一)——从核心定义到生态工具全解析
人工智能·笔记
是上好佳佳佳呀11 小时前
【前端(十一)】JavaScript 语法基础笔记(多语言对比)
前端·javascript·笔记