数据结构与算法笔记(二)

一、算法的概念
1.算法的定义
    算法是一系列指令的集合,是为了解决特定问题的一系列操作。是一个明确的计算过程,一般具有如下特征:
    a.有输入和输出,输入一个待解决的数据集合,输出一个处理后的数据集合。
    b.可行性,一个算法必然是可行的,能在有限的时间和空间下完成。
    c.有穷性,即算法执行的指令的个数,处理的数据量,执行指令的时间必须是有终点的,可以在有限时间内完成的。
    d.确定性,即相同的输入,应该有唯一确定的输出。
    一个算法的好坏一般由复杂度作为评判依据:即时间复杂度和空间复杂度,时间复杂度指计算机执行算法所需的计算工作量(计算时间)。空间复杂度指计算机 执行这个算法所需的空间(一般指内存空间)。
 
二、时间复杂度
1.时间复杂度定义
    时间频度:一个算法花费的时间有算法中语句的执行次数成正比,语句越多,花费时间也就越多,算法中执行语句的次数就称之为时间频度,用T(n)表示,n为问题的规模。
    时间复杂度:一般而言我们仅仅想知道算法的规模,并不想知道算法具体执行了多少次,为此引入了时间复杂度的概念。一般情况下,算法中时间频度为函数T(n),若存在某个函数f(n),当n接近无穷大时,T(n)/f(n)接近一个常数,则称其为T(n)的同量级函数:T(n)=O(f(n)),O(f(n))就称之为时间复杂度。
    例如:有算法时间频度为T1(n)=20n^2+6n+5,T2(n)=3n^2+15n,T3(n)=n^2的算法,当n接近无穷大时,T1(n)和T2(n)的系数、低阶项和常数项对其大小的影响越来越小,甚至可以忽略。
9f2ab277dd29c5caa2d6b8be613e30a0b21.jpg
 
 
    因此,时间复杂度就是时间频度去掉其高阶系数和所有低阶项后的函数。
 
2.最坏时间复杂度与平均时间复杂度
    平均时间复杂度:算法所有可能的输入等概率出现的情形下,算法的期望运行时间。
    最坏时间复杂度:即算法执行了最多次数的语句,花费了该算法最多的时间,它是该算法在运行时间的上边界。最坏时间复杂度以T(n)=O(n)表示,一个算法的运行时间不可能大于O(n)。
    一般没有特殊说明下,讨论的均是最坏时间复杂度。这是因为平均事件复杂度难以计算且大部分算法的平均时间复杂度和最坏时间复杂度是一样的。
    为了进一步说明算法的时间复杂度,我们定义 Ο、Ω、Θ符号。
Ο(欧米可荣)符号给出了算法时间复杂度的上界( 最坏情况  <=),比如T(n) =O(n2)。
Ω(欧米伽)符号给出了时间复杂度的下界( 最好情况 >=),比如T(n) =Ω(n2)。
    而Θ(西塔)给出了算法时间复杂度的精确阶( 最好和最坏是同一个阶  =),比如T(n) =Θ(n2)。
 
3.时间复杂度的计算
    我们无需去计算时间频度,再简化得到时间复杂度,这样过于麻烦,可以直接采用如下步骤来计算时间复杂度:
    a.找出算法中的基本语句,即执行次数最多的语句,通常是循环体中的语句(层数最多的循环体语句)。
    b.计算出基本语句的执行次数的数量级,即找出最高阶项的数量级,因为时间复杂度忽略低阶项和系数,因此,基本语句的数量级就体现了该算法的时间复杂度。
    c.将基本语句执行次数的数量级放入O(欧米可荣)记号中,即得到该算法的时间复杂度。
    举例:
 
int i=0;
//因为i=0为基本语句,且只执行了1次,数量级为常数,因此时间复杂度为O(1)

int res=0,n=10;
for(int i=0;i<n;i++){
    res++;
}
//基本语句为res++或者i++,执行次数为n,n的数量级为一次幂,因此时间复杂度为O(n)

int res=0,n=10;
for(int i=0;i<n;i++){
    for(int j=0;i<n;j++){
        res++;
    }
}
//基本语句为res++,执行次数为外层循环n,内层循环也为n,数量级为n*n=n^2,因此时间复杂度为O(n^2)

int res=0,n=1000;
for(int i=1;i<n;i*=2){
    res++;
}
//基本语句为res++或者i*=2,执行次数为2^x=n,即x=log2n,n的数量级为log2n,因此时间复杂度为O(log2n)

int res=0,n=1000;
for(int i=1;i<n;i*=2){
   for(int j=1;i<n;j++){
        res++;
    }
}
//基本语句为res++,执行次数外层循环为log2n,内层循环为n,n的数量级为nlog2n,因此时间复杂度为O(nlog2n)

 

 
常见的时间复杂度级别有:常数阶O(1),対数阶O(n*log2n),线性阶O(n),线性对数阶O(n*log2n),平方阶O(n^2),立方阶O(n^3),指数阶O(2^n)等。其效率越来越低。
 
三、空间复杂度
1.空间复杂度的定义
    一个算法所占用的存储空间包含三个方面:程序本身所占用的空间,输入的数据元素所占用的空间,辅助变量所占用的空间,其中输入数据的占用空间取决于问题本身,与算法无关,而程序本身占用的空间一般比较小且相对固定,因此一格算法的空间复杂度仅与辅助变量关系比较密切。
     空间复杂度是对一个算法在运行过程中临时占用的存储空间大小的量度,一般也作为问题规模n的函数,以数量级形式给出,记作: S(n) = O(g(n))。
 
int fun(int n){   
   int i,j,k,s;
   s=0;
   for (i=0;i<=n;i++)           
       for (j=0;j<=i;j++)     
            for (k=0;k<=j;k++)     
                s++;
   return s;
}
//由于算法中临时变量的个数与问题规模n无关,所以空间复杂度均为S(n)=O(1)。

void fun(int a[],int n,int k){   //数组a共有n个元素
   int i;
   if (k==n-1)
      for (i=0;i<n;i++)  
           printf(“%d\n”,a[i]);  //执行n次
      else{  
           for (i=k;i<n;i++)
               a[i]=a[i]+i*i;      //执行n-k次
               fun(a,n,k+1);
      }
}
//递归调用,每次调用本身都要分配空间,fun(a,n,0)的空间复杂度为O(n)。

 

 
注意:
    a.空间复杂度相比时间复杂度分析要少.
    b.对于递归算法来说,代码一般都比较简短,算法本身所占用的存储空间较少,但运行时需要占用较多的临时工作单元; 若写成非递归算法,代码一般可能比较长,算法本身占用的存储空间较多,但运行时将可能需要较少的存储单元。

转载于:https://my.oschina.net/bzhangpoorman/blog/3014753

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值