数据结构与算法-算法和算法评价(C语言版)

目录

一、算法的基本概念

1.1什么是算法

1.2算法的五个特性

1.3“好”算法的特质

二、算法的时间复杂度

2.1时间复杂度

2.2时间复杂度的计算

2.3技巧总结

2.4三种时间复杂度

三、算法的空间复杂度

3.1空间复杂度的计算

3.1.1普通程序

3.1.2递归程序

3.2技巧总结


一、算法的基本概念

1.1什么是算法

    算法(Algorithm)是对特定问题求解步骤的一种描述,它是指令的有限序列,其中的每条指令表示一个或多个操作。

1.2算法的五个特性

    1.有穷性:一个算法必须总在执行有穷步之后结束,且每一步都可在有穷时间内完成。(注意:算法必须是有穷的,但如果说是一个程序那么可以是无穷的)

    2.确定性:算法中每条指令必须有确切的含义,对于相同的输入只能得出相同的输出

    3.可行性:算法中描述的操作都可以通过已经实现的基本运算执行有限次来实现。

    4.输入:一个算法有零个或多个输入,这些输入取自于某个特定的对象的集合。

    5.输出:一个算法有一个或多个输出,这些输出是与输入有着某种特定关系的量。

1.3“好”算法的特质

    1)正确性。算法应能够正确地解决求解问题。

    2)可读性。算法应具有良好的可读性,以帮助人们理解。

    3)健壮性。输入非法数据时,算法能适当地做出反应或进行处理,而不会产生莫名其妙的输出结果。

    4)高效率低存储量需求

算法效率的度量:时间复杂度、空间复杂度

二、算法的时间复杂度

2.1时间复杂度

事前预估算法时间开销T(n)与问题规模 n 的关系(T 表示 “time”)

2.2时间复杂度的计算

int dizi(int n)
{
   int fzd = 0;
  for(int i = 0;i < n;i++)
   {
     for(int j = 0; j<n; j++)
      {
        fzd++; 
      }
   }//有两层循环,每次循环n次
 
 
  for(int k = 0; k<n; k++)
   {
     ++fzd;
   }//一层循环,循环n次
  
  for(int l = 0;l<10;l++)
   {
     ++fzd;
   }//循环了10次
 
return dizi;
}

对于上述代码我们进行时间复杂度的计算:有两层for循环,每次循环n次+一层for循环,循环n次+循环10次。可以列出时间复杂度的表达式为n*n+n+10

当用大O表示法表示时,只代表是一种估算而非准确值(只保留阶数高的部分,常数项系数也可以忽略)。所以表达式就变为了O(n*n)

结论:1)可以只考虑阶数高的部分( 用大O记法表示
           2) 问题规模足够大时,常数项系数也可以忽略
           3) 顺序执行的代码只会 影响常数项,可以忽略
           4) 只需挑循环中的一个 基本操作分析它的执行次数与 n 的关系即可
           5)如果有多层嵌套循环,只需关注最深层循环循环了几次

2.3技巧总结

    1)加法规则
        T ( n ) = T 1 ( n ) + T 2 ( n ) = O ( f ( n )) + O ( g ( n )) = O ( max ( f ( n ), g ( n )))
     ( 多项相加只保留最高阶的项,且系数变为1
   2)乘法规则
       T ( n ) = T 1 ( n ) × T 2 ( n ) = O ( f ( n )) × O ( g ( n )) = O ( f ( n ) × g ( n ))
     ( 多项相乘,都保留
例:
       T 3 (n)= n 3 + n 2 log 2 n
       = O(n 3 ) + O(n 2 log 2 n)
       = ???
                        
                                             “常对幂指阶”

T 3 (n)= n 3 + n 2 log 2 n
= O(n 3 ) + O(n 2 log 2 n)
= O(n 2* n) + O(n 2*  log 2 n)
              我们要判断
T 1 (n) = O(n)
T 2 (n) = O(log 2 n)
哪个的阶数更高(时间复杂度更高)?
= O( n) + O(   log 2n)      (n> log 2 n)
=O(n 3 ) 保留该项

2.4三种时间复杂度

   1)  最坏时间复杂度:最坏情况下算法的时间复杂度。
    2) 平均时间复杂度 所有输入示例等概率出现 的情况下,算法的期望运行时间。
   3) 最好时间复杂度:最好情况下算法的时间复杂度。

三、算法的空间复杂度

3.1空间复杂度的计算

3.1.1普通程序

1)

//逐步递增
void dizi(int n){ 
     int i=1;
     while(i<=n){
        i++; //每次都+1
        printf("pandas don't play the flute %d\n",i);
      }
      printf("pandas really don't play the flute %d\n",n);
}

在此例当中,n为问题规模,但不管n的值怎么变化,在执行的过程当中它所需要的内存空间大小都是固定不变的一个常数值,所以算法的空间复杂度为 S(n)=O(1) 

2)

void dizi(int n){
     int flag[n];  //数组的长度为n
     int i;
}

假设:一个int类型的变量占4个字节 那么存放int n则需要四个字节,而int flag[n]这个int型的数组 每一个数组元素都需要占4个字节,最后对于i这个变量占4个字节。所以该例所需要的内存空间为:4+4n+4=4n+8

空间复杂度与时间复杂度类似,我们在计算一个算法的空间复杂度时,只要关注它所需要消耗的空间是什么数量级的,什么阶数即可。所以同样用大O表示法来表示S(n)=O(4n+8)=O(n)

3.1.2递归程序

void dizi(int n){
     int a,b,c; //局部变量的声明
    //......
     if(n>1){
          dizi(n-1);
      }
      printf("pandas don't play the flute %d\n",n);
}

 int main(){
    dizi(5);
 }

运行结果为:

        pandas don't play the flute 1

        pandas don't play the flute 2

        pandas don't play the flute 3

        pandas don't play the flute 4

        pandas don't play the flute  5

每一级的函数调用都需要f个字节(f为常数) 当n=5时总共发生了5层递归调用。由此可知递归调用的层数与问题规模n是相等的。所以当问题规模为n时所需要的内存空间大小为f*n个字节。

用大O表示法只关注阶数可得空间复杂度为:S(n)=O(n)

空间复杂度=递归调用的深度

3.2技巧总结

  1)加法规则
       O (f( n) )+   O (g ( n )) = O ( max ( f ( n ), g ( n )))
  
  2)乘法规则
      O ( f ( n )) × O ( g ( n )) = O ( f ( n ) × g ( n ))
  3)“常对幂指阶”


由于个人知识和经验的局限性,文章中难免存在疏漏和不足之处,欢迎大家指正!

     
  • 42
    点赞
  • 49
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

熊猫不吹笛子

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值