时间复杂度

时间复杂度
时间复杂度:实际上就是一个函数,函数的计算结果是算法执行的基本操作的次数。
比如:

void Test(int n){
    int count = 0;
    int i = 0;
    for(;i < n;++i){
        int j = 0;
        for(;j < n;++j){
            count++;   //总共执行了  n*n 次
        }
    }
    int k = 0;
    for(;k < 10*n;++k){
        count++;       //总共执行了  10*n  次
    }
    int num = 5;
    while(num--){
        count++;        //总共执行了   num次
    }
}
//由此可得出总的执行次数就是各部分的执行次数的和
//   f(n) = n*n + 10*n + 5 
//

注意!注意!!注意!!!这里伴随着一个问题

Q:为什么使用执行次数而不是时间来衡量算法的好坏???

A:
1、每一台机器运行指令的时间可能是不同的
2、无论n怎么变。一个计算时间复杂度的函数的计算结果在不同的环境下总是确定的,
之所以不能用时间衡量是因为。环境无法确定(内核,内存)

通常情况下,算法总是会存在最好、平均和最坏情况。
比如我们要在一个线性表中查找某一个元素的位置:

int find(int arr[],int size,int to_find)
{
    int i = 0;
    for(;i < size;i++){
        if(arr[i] == to_find)  
            //找到了返回下标
            return i;
    }
    //没找到返回-1
    return -1;
}

//假如线性表中的数据依次是:1,4,7,2,9,5,0

最好情况下:一下就找到了(我们查找的是数据1)
最坏情况下:找遍了整个线性表(我们查找的数据是0,或者这个数据在线性表中根本就不存在)
平均情况:所谓的平均就是把所有数据要比较的次数加起来再除以数据元素个数
(1 + 2 + 3 + 4 + … +N)/ N
计算的结果就是((1+N)*N / 2)/ N 化简:(N+1) / 2
在实际中我们通常关注的是最坏的情况,主要有以下3点原因:
1、大体上看,平均情况与最坏情况一样差
2、有些算法,最坏的情况出现的比较频繁
3、一个算法的最坏情况的基本操作执行次数是在任意输入下的基本操作执行次数的上界
也因此,常用O渐进表示法来计算算法的时间复杂度

O渐进表示法:

一个算法语句执行的总的次数是关于问题规模N的函数,记为f(N)N称为问题的规模。语句总的执行次数记为T(N),当N不断变化时,T(N)也在变化,算法执行次数的增长速率和f(N)的增长速率相同,则有T(N) = O( f(N) ),称 O( f(N) )为时间复杂度的O渐进表示法。

练习:

void Test0(int n){
    int count = 0;
    int num = 5;
    while(num--){
        count++;        //总共执行了   num 次
    }
}
//   f(n) = 5 
//   O(10)

void Test1(int n){
    int count = 0;
    int k = 0;
    for(;k < 10*n;++k){
        count++;       //总共执行了  10*n  次
    }
    int num = 5;
    while(num--){
        count++;        //总共执行了   num次
    }
}
//由此可得出总的执行次数就是各部分的执行次数的和
//   f(n) =10*n + 5
//   O(10*n + 5)

void Test2(int n){
    int count = 0;
    int i = 0;
    for(;i < n;++i){
        int j = 0;
        for(;j < n;++j){
            count++;   //总共执行了  n*n 次
        }
    }
}
//   f(n) = n*n 
//   O(n^2)

void Test3(int n,int m){
    int count = 0;
    int i = 0;
    for(;i < n;++i){
        count++;       //总共执行了  n  次
    }
    int j = 0;
    for(;j < m;++j){
        count++;       //总共执行了  m  次
    }
}
//   f(n) = m+n
//   O(m+n)

void Test4(int n,int m){
    int count = 0;
    int i = 0;
    for(;i < 2*m;++i){
        int j = 0;
        for(;j < n;++j){
            count++;   //总共执行了  n*n 次
        }
    }
}
//   f(n) = 2m*n
//   O(2*m*n)

O(n)计算方法:
1、用常数1取代运行时间中的所有加法常数
2、在修改后的运行次数函数中,只保留最高阶的那一项
3、如果最高阶项的系数存在且不是1,则去除与这个项相乘的常数
现在我们回头重新看一下刚刚计算的那几个时间复杂度,经过这些规则之后,正确的O渐进表示法应该是什么样子:

//用常数1取代运行时间中的所有加法常数
f(n) = 5   ->   O(10)   ->   O(1)

//用常数1取代运行时间中的所有加法常数
//在修改后的运行次数函数中,只保留最高阶的那一项
//如果最高阶项的系数存在且不是1,则去除与这个项相乘的常数
f(n) =10*n + 5   ->   O(10*n + 5)   ->   O(n)

用常数1取代运行时间中的所有加法常数
//在修改后的运行次数函数中,只保留最高阶的那一项
f(n) = n*n + 10*n + 5    ->   O(n*n + 10*n + 5)   ->   O(n^2)

f(n) = n*n   ->   O(n^2)    ->   O(n^2)
f(n) = m+n   ->   O(m+n)    ->   O(m+n)

//如果最高阶项的系数存在且不是1,则去除与这个项相乘的常数
f(n) = 2m*n  ->  O(2*m*n)   ->   O(mn)

像这样我们常见的有这些循环的时间复杂度我们已经掌握如何去求解,但是,现在有一个递归的算法,我们又将如何去计算他的时间复杂度呢??

//求1+2+3+4+...+n的和
int Sum(int n)
{
    if(n == 1)
        return 1;
    else
        return n+Fun1(n-1);
}

规则:递归算法的时间复杂度=递归总次数*每次递归次数
所以这个递归算法的时间复杂度就是:
假设我们要求前5项的和,那么我们要先算前4项的和,那么又要先算前3项的和…先算前1项的和。最终我们需要递归5次,每次递归的次数是一次,因此这个递归的求和算法的时间复杂度为:O(n)
下面再来看一看求阶乘的递归算法的时间复杂度:

//求n的阶乘
int Fac(int n)
{
    if(n == 0)
        return 1;
    else
        return n*Fac(n-1);
}

这里假设我们需要计算5的阶乘,那么我们只需要知道4的阶乘再乘以5即可,如果要知道4的阶乘的结果就要先知道3的阶乘的记过在乘以4,要知道3的阶乘的结果要先知道2的阶乘的结果在乘以3,…要知道1的阶乘结果就的先知道0的阶乘的结果在乘以1。至此,想一想,我们已经递归了6次,每次递归的次数是一次,因此该递归算法的时间复杂度为:O( (n+1)*1 ) -> O(n)。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值