数据结构——算法复杂度

一、数据结构定义
数据结构(Data Structure)是计算机存储、组织数据的⽅式,指相互之间存在⼀种或多种特定关系的数据元素的集合。没有⼀种单⼀的数据结构对所有⽤途都有⽤,所以我们要学各式各样的数据结构,如:线性表、树、图、哈希等。
算法:
算法(Algorithm):就是定义良好的计算过程,他取⼀个或⼀组的值为输⼊,并产⽣出⼀个或⼀组值作为输出。简单来说算法就是⼀系列的计算步骤,⽤来将输⼊数据转化成输出结果。
二、算法效率
算法效率是衡量一个算法在解决问题过程中性能表现的关键指标,主要体现在时间效率和空间效率这两个核心方面。
1.复杂度的概念:
算法在编写成可执⾏程序后,运⾏时需要耗费时间资源和空间(内存)资源 。因此衡量⼀个算法的好
坏,⼀般是从时间和空间两个维度来衡量的,即时间复杂度和空间复杂度。
时间复杂度主要衡量⼀个算法的运⾏快慢,⽽空间复杂度主要衡量⼀个算法运⾏所需要的额外空间。
2.复杂度的重要性:评估算法性能:准确衡量效率差异 预测算法扩展性 指导算法优化:确定优化方向 对比优化效果 合理选择算法:适配应用场景 平衡资源利用。
三、时间复杂度
定义:在计算机科学中,算法的时间复杂度是⼀个函数式T(N),它定量描述了该算法的运⾏时间。
通常使用大 O 表示法(Big - O notation)来描述时间复杂度。
1.大O的渐进表示法
⼤O符号(Big O notation):是⽤于描述函数渐进⾏为的数学符号
推导⼤O阶规则

  1. 时间复杂度函数式T(N)中,只保留最⾼阶项,去掉那些低阶项,因为当N不断变⼤时,
    低阶项对结果影响越来越⼩,当N⽆穷⼤时,就可以忽略不计了。
  2. 如果最⾼阶项存在且不是1,则去除这个项⽬的常数系数,因为当N不断变⼤,这个系数
    对结果影响越来越⼩,当N⽆穷⼤时,就可以忽略不计了。
  3. T(N)中如果没有N相关的项⽬,只有常数项,⽤常数1取代所有加法常数。
    通过以上⽅法,可以得到 Func1 的时间复杂度为: O ( N 2 )。
    示例:
    // 计算 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);
    }
    Func2执⾏的基本操作次数:
    T (N ) = 2N+ 10
    根据推导规则第3条得出
    Func2的时间复杂度为: O (N)
    // 计算 Func4 的时间复杂度?
    void Func4(int N)
    {
    int count = 0;
    for (int k = 0; k < 100; ++ k)
    {
    ++count;
    }
    printf("%d\n", count);
    }
    Func4执⾏的基本操作次数:
    T (N) = 100
    根据推导规则第1条得出
    Func2的时间复杂度为: O(1)
    总结
    通过上⾯我们会发现,有些算法的时间复杂度存在最好、平均和最坏情况。
    最坏情况:任意输⼊规模的最⼤运⾏次数(上界)。
    平均情况:任意输⼊规模的期望运⾏次数。
    最好情况:任意输⼊规模的最⼩运⾏次数(下界)。
    ⼤O的渐进表⽰法在实际中⼀般情况关注的是算法的上界,也就是最坏运⾏情况。
    四、空间复杂度
    空间复杂度也是⼀个数学表达式,是对⼀个算法在运⾏过程中因为算法的需要额外临时开辟的空间。空间复杂度计算规则基本跟实践复杂度类似,也使⽤⼤O渐进表⽰法。
    注意:函数运⾏时所需要的栈空间(存储参数、局部变量、⼀些寄存器信息等)在编译期间已经确定好了,因此空间复杂度主要通过函数在运⾏时候显式申请的额外空间来确定。
    示例:
    // 计算 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;
    }
    }
    函数栈帧在编译期间已经确定好了,
    只需要关注函数在运⾏时额外申请的
    空间。
    BubbleSort额外申请的空间有
    exchange等有限个局部变量,使⽤了
    常数个额外空间
    因此空间复杂度为 O(1)
    // 计算阶乘递归 Fac 的空间复杂度?
    long long Fac(size_t N)
    {
    if(N == 0)
    return 1;
    return Fac(N-1)*N;
    }
    Fac递归调⽤了N次,额外开辟了N个函数栈帧,
    每个栈帧使⽤了常数个空间
    因此空间复杂度为: O (N)
    五、常见复杂度对比


    总结
    在实际应用中,常常需要在时间复杂度和空间复杂度之间进行权衡。有时候为了提高时间效率,可以适当牺牲空间,比如利用缓存机制增加空间占用以加快数据访问速度;而在空间资源受限的场景下,可能会选择空间复杂度较低但时间复杂度稍高些的算法,确保系统能正常运行。 总之,要依据具体的应用场景、资源条件以及对时间和空间的侧重要求等来综合考虑,选择最优的算法或者对现有算法进行合理的优化,以达到最佳的性能表现。
相关推荐
2501_924731472 小时前
城市路口识别准确率↑31%!陌讯时空建模算法在交通拥堵识别中的突破
人工智能·算法·目标检测·计算机视觉·目标跟踪
熬了夜的程序员2 小时前
【华为机试】208. 实现 Trie (前缀树)
数据结构·算法·华为od·华为
小O的算法实验室4 小时前
2024年ESWA SCI1区TOP,自适应种群分配和变异选择差分进化算法iDE-APAMS,深度解析+性能实测
算法·论文复现·智能算法·智能算法改进
不吃洋葱.5 小时前
左子树之和
算法
金融小师妹6 小时前
基于AI量化模型的比特币周期重构:传统四年规律是否被算法因子打破?
大数据·人工智能·算法
数据智能老司机7 小时前
图算法趣味学——最短路径
数据结构·算法·云计算
快去睡觉~7 小时前
力扣109:有序链表转换二叉搜索树
算法·leetcode·链表
gopher_looklook7 小时前
Go并发实战:singleflight 源码解读与二次封装
数据结构·后端·go
是Dream呀7 小时前
YOLOv8深度解析:从架构革新到应用实践
人工智能·算法
终焉代码8 小时前
【C++】STL二叉搜索树——map与set容器的基础结构
开发语言·数据结构·c++