Ⅱ数据结构的性能衡量——复杂度

1.复杂度的概念

        复杂度是用来描述算法的强弱优劣的,定性的衡量代码的好与坏,进而从多个代码进行择优选择,其就是对代码的资源利用效率的衡量尺度。

2.复杂度的分类

数据结构在对数据的管理时是要考虑对现有资源的利用效率的,而程序运行时消耗的资源无外乎时间与内存空间。故作为效率衡量标准的复杂度又可分为两类——衡量运行快慢的时间复杂度与衡量算法运行所要空间的空间复杂度

        时间复杂度(次数):算法中基本语句的执行总次数(名词解释:基本语句,一次便利中使用次数最多的语句。总:不是一次结果且是要在最坏,最多的情况下。)其本质是问题规模N 与执行次数 方(N)的函数关系式         为什么是次数而不是具体的时间?其实用时间也是可以的,但没必要且不准确,因为对算力强大的CPU而言,运算时间在同一量级内并没有明显差别,几近于无,而且一种类型的数据不能无限大的。         那为什么说不准确呢?同样的代码在性能不同的设备上所用的时间也是不同的,故代码实际的运算时间不具有参考价值,而用次数就能屏蔽设备不同而造成的干扰。时间复杂度的量级(本人按自己理解的叫法,不具有官方性,),时间复杂度有时按次数的量级来划分运算速率的快慢的,同一量级内运算时间几乎相同,不同的复杂度运算时间迥异。

        空间复杂度(个数):额外临时占用的储存空间的大小,也就是    一个算法中,变量额外开辟的空间最多时的个数。空间复杂度记录了一个算法编译时最大的栈帧深度,这对于函数栈帧时是否溢出很重要,如果算法的空间复杂度过大那样就要考虑溢出问题且开辟栈帧也需要时间,所以即使两算法的时间复杂度相同,因为开栈次数不同也有差别,所需要的时间也就不同。这也是递归与迭代的区别,递归用时一般多于迭代,当然并不是说迭代就优于递归,递归在分治子问题上有不可代替的作用。

        空间复杂度的两大类情况,①.O(1),即为开辟的空间的个数与问题规模无关;②O(N),即为开辟的空间与问题规模N有关,此类大部分为递归问题;

2.1时间复杂度的求法

        求出正确的复杂度就意味着,能判断代码的性能 。那明白并熟练求解复杂度,无论是在实际应用中,还是考试测验中都是十分必要的。复杂度的求解的核心是明白代码运行逻辑,明确内部基本语句的执行次数而不是看代码的实现结构。

        大O的渐进表示(Big o notation)法(求出运行次数的数量级):

                           1.明确基本语句,兼顾其他语句。一串代码中一次执行中执行次数最多的基本语句,其他的为基本与语句。

                           2.确定问题规模N,改代码段中改定执行次数N,N可以为原始的数据,也可为代码中指定的执行次数。※注意,有时问题规模不止一个,这时就要比较几个的大小,几近相同则合并,相较甚远则省略小的。

                           3.整理代码整体运行逻辑。此时要考虑遍历是的最坏情况。

       ⑴ 并列结构——和;如下O(M+N)

int main () 
{
   int i=0;

    .....
   while(i<m)
  {
     .....
     i++;
  }
   while(i<n)
  {
     .....
     i++;
  }

}

       ② 嵌套结构——大部分连乘,也就是指数,本质还是和;如下,O(M*N)

int main () 
{
   int i=0;

    .....
   while(i<m)
  {
     .....
     for(int j = 0;j<n;j++)
      {
        ......
        j++;
      }
     i++;
  }
   

}

        当然不是所有循环结构都是如此,如下,O(1)

int main () 
{
   int i=0;

    .....
   while(i<4566666)
  {
     .....
     for(int j = 0;j<4200000000;j++)//常量最大42亿
      {
        ......
        j++;
      }
     i++;
  }
   

}

        ③每次对半分= 下一次是上一次的两倍(也就是层序结构)—连除,及时对数运算,㏒(m)N,注1:因为在纯文文件中对数的底数难以显示,且此类情况大多数为二路递归(B树为多路递归),所以用log N表示log(2)N,其他m路递归为㏒(m)N;

int main () 
{
   int i = 0;
   while (i<m)
   {
    ....
    i *= 2;//意思是每次变化两倍 
   
    }
    //或者
   int i = m;
   while (i >0)
   {
    .....
    i/=2;//意思是每次变化一半
   }
   //注意,此时的执行次数不为m,而是log(2)N

}

        ④递归——递归一次的执行次数*递归次数(一路递归,为1*N;二路递归,递归次数=2*层序-1)

#define _CRT_SECURE_NO_WARNINGS 1

#include <stdio.h>
#define num 5

int add(int n)
{
    if (n < 0)
        return 1;
    return add(--n) + add(--n);
}
int main()
{
    printf("%d", add(num));
}

                          4.写出解析式     ,F(N,,,,,,)   

        由数据管理的逻辑,写出解析式。

                           5.化简,用大O渐进表示法

①抓大头,留数据规模N,,,,,的决定项,比较各规模大小 ,(同变看指,不同看值,远大于就略小,相同合并,值不同都要)

②合并同类项,去除系数.当N过大时,系数对解析式影响不大,几近于无。

③以O(去系数项之和),注决定项为常数时则为1,因为CPU运算极快而数据不能无限大。

2.2 空间复杂度的求法

        实际上,求空间复杂度是较为简单的,只要看变量的空间与问题规模是否相关,然后进行选择即可,那是哪个空间呢?其实任何一个都可以,因为变量的空间都是早函数栈帧就已开辟了,内部无论执行什么变量,(如果不考虑内部的算法所占用的空间大于函数栈帧的空间大小,但如果超过了又该怎么办呢?是报错呢,还函数的空间在增大呢),都不会引起函数空间的再变化(函数调用时,形参与实参所处的空间不在一处),故与其说是变量的空间个数不如说是函数空间的个数。

2.2.1补充知识——递归与迭代的区别

        迭代与递归都要实现循环执行代码的功能,而两者又有不同,迭代无需开辟空间,递归要进行函数栈帧,这使得递归在同样的时间复杂度下处于劣势,而递归的分治功能又因为空间复杂度较高面临着栈溢出stack overflow问题(当然随着技术的迭代,递归的可执行深度——层数愈发深了。),所以用迭代实现递归结构是要我们掌握的(也就是用层序来模拟实现前中后序,用广度遍历实现深度遍历),

2.2.2 递归的空间复杂度理解

        递归结构会实现函数的复用,即每次调用开辟栈帧,函数结束结束栈帧销毁,后有调用。可概括为,调——销——调——销.......。栈顶的区域重复的次数更多,过程中的函数同地址同空间。

3.时间复杂度与空间复杂度的对比认识

        时间复杂度:时间是累计的,一去不复返的,所以要记录重复的情况,故要的是次数。如,递归的时间复杂度为(2^层数-1),此处要把递归过程图解出来,也就是画图;

        空间复杂度:空间是可以重复利用的,因为每次用完即销毁,所以可以重复利用,故要的是个数,递归的空间复杂度为层数。(8M的内存在debug下最多有4000,release版本下最多20000层)

4.复杂度在值上的对比        

545154541                                               O(1)                                                常数阶

4*n+5                                                       O   (N)                                                  线性阶

3*n^2+5*n+5                                            O  (N^2)                                                平方阶

3*log(2)n+5                                         O(log N)                                            对数阶

3*n*log(2)n+5                                           O(N*logN)                                         N*logNj阶

n^3+2*n^2+.....                                          O(N^3)                                                  立方阶

//插入函数图

5.降低复杂度的手段

        1.左手换右手,空间换时间,时间换空间。

        空间换时间:通常的手段使用再开一个空间,让数据在原空间与新空间之间来回跳,避免在一个空间时的数据移动问题。

        时间换空间:(后期补上)

        2.更加优秀的算法逻辑,这样的算法设计时思路应避免暴力求解,思路越是巧妙,过程愈发高效,个人建议考虑建立层序结构(把递归整个过程分成多层,如上图)。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值