算法时间复杂度的计算 [整理]

本文详细介绍了算法时间复杂度的概念及其计算方法,并通过多种典型示例深入浅出地讲解了如何确定算法的时间复杂度,包括单层循环、多层循环、函数调用等不同场景。

From: http://univasity.iteye.com/blog/1164707

基本的计算步骤 

时间复杂度的定义
 
    一般情况下,算法中基本操作重复执行的次数是问题规模n的某个函数,用T(n)表示,若有某个辅助函数f(n),使得当n趋近于无穷大时,T(n)/f(n)的极限值为不等于零的常数,则称f(n)是T(n)的同数量级函数。记作T(n)=O(f(n)),称O(f(n))为算法的渐进时间复杂度(O是数量级的符号 ),简称时间复杂度。

根据定义,可以归纳出基本的计算步骤 
1. 计算出基本操作的执行次数T(n) 
    基本操作即算法中的每条语句(以;号作为分割),语句的执行次数也叫做语句的频度。在做算法分析时,一般默认为考虑最坏的情况。

2. 计算出T(n)的数量级 
    求T(n)的数量级,只要将T(n)进行如下一些操作:
    忽略常量、低次幂和最高次幂的系数

    令f(n)=T(n)的数量级。

3. 用大O来表示时间复杂度 
    当n趋近于无穷大时,如果lim(T(n)/f(n))的值为不等于0的常数,则称f(n)是T(n)的同数量级函数。记作T(n)=O(f(n))。


一个示例: 
(1) int num1, num2;
(2) for(int i=0; i<n; i++){ 
(3)     num1 += 1;
(4)     for(int j=1; j<=n; j*=2){ 
(5)         num2 += num1;
(6)     }
(7) }
 

分析:
1.
语句int num1, num2;的频度为1;
语句i=0;的频度为1;
语句i<n; i++; num1+=1; j=1; 的频度为n;
语句j<=n; j*=2; num2+=num1;的频度为n*log2n;
T(n) = 2 + 4n + 3n*log2n

2.
忽略掉T(n)中的常量、低次幂和最高次幂的系数
f(n) = n*log2n

3.
lim(T(n)/f(n)) = (2+4n+3n*log2n) / (n*log2n)
                     = 2*(1/n)*(1/log2n) + 4*(1/log2n) + 3

当n趋向于无穷大,1/n趋向于0,1/log2n趋向于0
所以极限等于3。

T(n) = O(n*log2n)

简化的计算步骤 

再来分析一下,可以看出,决定算法复杂度的是执行次数最多的语句,这里是num2 += num1,一般也是最内循环的语句。

并且,通常将求解极限是否为常量也省略掉?

于是,以上步骤可以简化为: 
1. 找到执行次数最多的语句 
2. 计算语句执行次数的数量级
3. 用大O来表示结果
 

继续以上述算法为例,进行分析:
1.
执行次数最多的语句为num2 += num1

2.
T(n) = n*log2n
f(n) = n*log2n

3.
// lim(T(n)/f(n)) = 1
T(n) = O(n*log2n)

 

--------------------------------------------------------------------------------
一些补充说明 
最坏时间复杂度 
    算法的时间复杂度不仅与语句频度有关,还与问题规模及输入实例中各元素的取值有关。一般不特别说明,讨论的时间复杂度均是最坏情况下的时间复杂度。这就保证了算法的运行时间不会比任何更长。

求数量级 
即求对数值(log),默认底数为10,简单来说就是“一个数用标准科学计数法表示后,10的指数”。例如,5000=5x10 3 (log5000=3) ,数量级为3。另外,一个未知数的数量级为其最接近的数量级,即最大可能的数量级。

求极限的技巧 
要利用好1/n。当n趋于无穷大时,1/n趋向于0
 

--------------------------------------------------------------------------------
一些规则(引自:时间复杂度计算 ) 
1) 加法规则 
T(n,m) = T1(n) + T2(n) = O (max ( f(n), g(m) )

2) 乘法规则
 
T(n,m) = T1(n) * T2(m) = O (f(n) * g(m))

3) 一个特例(问题规模为常量的时间复杂度) 
在大O表示法里面有一个特例,如果T1(n) = O(c), c是一个与n无关的任意常数,T2(n) = O ( f(n) ) 则有
T(n) = T1(n) * T2(n) = O ( c*f(n) ) = O( f(n) )

也就是说,在大O表示法中,任何非0正常数都属于同一数量级,记为O(1)。

4) 一个经验规则 
复杂度与时间效率的关系:
c < log2n < n < n*log2n < n2 < n3 < 2n < 3n < n! (c是一个常量)
|--------------------------|--------------------------|-------------|
          较好                     一般              较差
其中c是一个常量,如果一个算法的复杂度为c 、 log2n 、n 、 n*log2n,那么这个算法时间效率比较高 ,如果是 2n , 3n ,n!,那么稍微大一些的n就会令这个算法不能动了,居于中间的几个则差强人意。


--------------------------------------------------------------------------------------------------
复杂情况的分析 

以上都是对于单个嵌套循环的情况进行分析,但实际上还可能有其他的情况,下面将例举说明。

1.并列循环的复杂度分析 
将各个嵌套循环的时间复杂度相加。

例如:

  for (i=1; i<=n; i++)
      x++;

  for (i=1; i<=n; i++)
      for (j=1; j<=n; j++)
          x++;

解:
第一个for循环
T(n) = n
f(n) = n
时间复杂度为Ο(n)

第二个for循环
T(n) = n2
f(n) = n2
时间复杂度为Ο(n2)

整个算法的时间复杂度为Ο(n+n2) = Ο(n2)。

2.函数调用的复杂度分析 
例如:
public void printsum(int count){
    int sum = 1;
    for(int i= 0; i<n; i++){
       sum += i;
    }   
    System.out.print(sum);
}

分析:
记住,只有可运行的语句才会增加时间复杂度,因此,上面方法里的内容除了循环之外,其余的可运行语句的复杂度都是O(1)。
所以printsum的时间复杂度 = for的O(n)+O(1) = 忽略常量 = O(n)

*这里其实可以运用公式 num = n*(n+1)/2,对算法进行优化,改为:
public void printsum(int count){
    int sum = 1;
    sum = count * (count+1)/2;   
    System.out.print(sum);
}
这样算法的时间复杂度将由原来的O(n)降为O(1),大大地提高了算法的性能。
 

3.混合情况(多个方法调用与循环)的复杂度分析 
例如:
public void suixiangMethod(int n){
    printsum(n);//1.1
    for(int i= 0; i<n; i++){
       printsum(n); //1.2
    }
    for(int i= 0; i<n; i++){
       for(int k=0; k
        System.out.print(i,k); //1.3
      }
  }
suixiangMethod 方法的时间复杂度需要计算方法体的各个成员的复杂度。
也就是1.1+1.2+1.3 = O(1)+O(n)+O(n2) ----> 忽略常数 和 非主要项 == O(n2)

--------------------------------------------------------------------------------------------------
更多的例子 

O(1) 
交换i和j的内容
temp=i;
i=j;
j=temp;                    

以上三条单个语句的频度为1,该程序段的执行时间是一个与问题规模n无关的常数。算法的时间复杂度为常数阶,记作T(n)=O(1)。如果算法的执行时间不随着问题规模n的增加而增长,即使算法中有上千条语句,其执行时间也不过是一个较大的常数。此类算法的时间复杂度是O(1)。

O(n2) 
    sum=0;                /* 执行次数1 */
    for(i=1;i<=n;i++)      
       for(j=1;j<=n;j++) 
         sum++;       /* 执行次数n2 */
解:T(n) = 1 + n2 = O(n2)

   for (i=1;i<n;i++)
   { 
       y=y+1;        ①   
       for (j=0;j<=(2*n);j++)    
          x++;        ②      
   }         
解:  语句1的频度是n-1
         语句2的频度是(n-1)*(2n+1) = 2n2-n-1
         T(n) = 2n2-n-1+(n-1) = 2n2-2
         f(n) = n2
         lim(T(n)/f(n)) = 2 + 2*(1/n2) = 2
         T(n) = O(n2).

O(n)                                         
   a=0;
   b=1;                     ①
   for (i=1;i<=n;i++) ②
   {  
      s=a+b;    ③
      b=a;     ④  
      a=s;     ⑤
   }
解:  语句1的频度:2,        
         语句2的频度:n,        
         语句3的频度:n,        
         语句4的频度:n,    
         语句5的频度:n,                                  
         T(n) = 2+4n
         f(n) = n
         lim(T(n)/f(n)) = 2*(1/n) + 4 = 4
         T(n) = O(n).     
                                                                            
O(log2n) 
   i=1;       ①
   while (i<=n)
      i=i*2; ②
解: 语句1的频度是1,  
       设语句2的频度是t,  则:nt<=n;  t<=log2n
       考虑最坏情况,取最大值t=log2n,
        T(n) = 1 + log2n
        f(n) = log2n
        lim(T(n)/f(n)) = 1/log2n + 1 = 1
        T(n) = O(log2n)

 O(n3) 
   for(i=0;i<n;i++)
   {  
      for(j=0;j<i;j++)  
      {
         for(k=0;k<j;k++)
            x=x+2;  
      }
   }
解:当i=m, j=k的时候,内层循环的次数为k当i=m时, j 可以取 0,1,...,m-1 ,  所以这里最内循环共进行了0+1+...+m-1=(m-1)m/2次所以,i从0取到n, 则循环共进行了: 0+(1-1)*1/2+...+(n-1)n/2=n(n+1)(n-1)/2次
T(n) = n(n+1)(n-1)/2 = (n3-n)/2
f(n) = n3
所以时间复杂度为O(n3)。


<think>好的,我现在需要帮助用户了解时间复杂度计算方法,并通过例题进行练习。首先,我得回顾一下时间复杂度的基本概念,确保自己理解正确。根据用户提供的引用内容,时间复杂度是衡量算法执行时间的指标,主要关注语句的执行次数,而不是具体时间。这点很重要,因为用户可能容易混淆实际运行时间和时间复杂度。 接下来,我需要整理计算时间复杂度的步骤。引用中提到,关键是分析问题规模n和执行次数x的关系。用户可能需要一个清晰的步骤指南,比如如何识别循环结构、嵌套循环,以及如何处理条件语句等。例如,顺序执行的语句取最大复杂度,循环结构看循环次数,嵌套循环则是各层循环次数的乘积,这些都需要详细说明。 然后,例题解析部分需要选择几个典型的例子,覆盖常见情况,比如单层循环、嵌套循环、对数复杂度、平方复杂度和条件语句组合的情况。每个例题应该分步骤解析,让用户能跟着思路一步步分析。比如,第一个例题可以是简单的单层循环,计算执行次数与n的关系,得出O(n)的结论。第二个例题可以是嵌套循环,展示O(n²)的情况。第三个例题可以是类似二分查找的对数复杂度,解释为什么是O(log n)。 还要注意引用中的例子,比如引用5中的O(log n)的例子,用户提供的代码中i每次乘以2,循环次数是log₂n,所以时间复杂度是对数级别。这个例子需要详细解释,确保用户明白循环变量如何变化影响执行次数。 另外,用户提供的引用4中提到,多个复杂度组合时,取最大的时间复杂度。比如条件语句中两个分支分别有不同的复杂度,整体取较大的那个。这个点也需要在例题中体现,例如一个分支是O(n²),另一个是O(n),则整体复杂度是O(n²)。 在组织内容时,结构要清晰。先讲方法,再举例题,每个例题有步骤和解析。可能还需要提醒用户注意常见误区,比如忽略系数和低阶项,只保留最高阶项。例如,即使执行次数是3n² + 2n + 1,时间复杂度仍然是O(n²)。 最后,生成的相关问题需要围绕用户可能进一步想了解的内容,比如空间复杂度、优化方法、不同算法比较等,但根据用户当前的问题,重点应放在时间复杂度上。不过根据引用3,用户可能也对空间复杂度感兴趣,所以相关问题可以包括空间复杂度的计算,或者时间与空间复杂度的权衡。 总结一下,回答的结构应该是:先介绍时间复杂度的定义和重要性,然后详细讲解计算步骤,接着通过多个例题逐步解析,最后提供相关问题供用户深入学习。需要确保引用正确的参考文献,比如引用1到5中的相关内容,并在适当的位置标注引用标记,例如在讲解步骤时引用1和4,讲解对数复杂度时引用5等。 现在检查是否有遗漏点:是否覆盖了常见复杂度类型(O(1), O(n), O(n²), O(log n)),是否解释了如何从代码中分析执行次数,是否处理了条件语句和循环嵌套的情况,是否引用了正确的资料。确认无误后,就可以组织语言,用中文清晰、有条理地呈现答案了。</think>### 时间复杂度计算方法及例题解析 #### 一、时间复杂度定义 时间复杂度是衡量算法运行时间与输入规模$n$增长关系的数学表达式,表示**语句执行次数**的渐进上界,用大$O$符号表示。例如,$O(n)$表示执行次数与$n$成线性关系[^2][^3]。 #### 二、计算步骤 1. **识别基本操作**:找到代码中执行次数最多的核心语句(如循环体、递归调用)。 2. **分析执行次数与$n$的关系**:将执行次数表示为$n$的函数$f(n)$。 3. **简化表达式**:保留最高阶项并忽略系数,例如$3n^2 + 2n + 1$简化为$O(n^2)$[^1][^4]。 #### 三、常见类型及例题 --- ##### **例题1:单层循环** ```python def example1(n): count = 0 for i in range(n): # 循环n次 count += 1 # 基本操作 return count ``` **解析** - 循环执行$n$次,核心操作`count +=1`执行$n$次。 - 时间复杂度为$O(n)$。 --- ##### **例题2:嵌套循环** ```python def example2(n): count = 0 for i in range(n): # 外层循环n次 for j in range(n): # 内层循环n次 count += 1 # 基本操作 return count ``` **解析** - 外层循环执行$n$次,内层循环每次执行$n$次,核心操作共执行$n \times n = n^2$次。 - 时间复杂度为$O(n^2)$[^4]。 --- ##### **例题3:对数复杂度** ```python def example3(n): count = 0 i = 1 while i < n: # i每次乘以2 count += 1 i *= 2 return count ``` **解析** - 循环终止条件为$i \geq n$,每次$i$变为$2i$,需执行$\log_2 n$次。 - 时间复杂度为$O(\log n)$[^5]。 --- ##### **例题4:平方与线性组合** ```python def example4(n): count = 0 for i in range(n): # O(n²) for j in range(n): count += 1 for k in range(n): # O(n) count += 1 return count ``` **解析** - 第一部分嵌套循环执行$n^2$次,第二部分单层循环执行$n$次。 - 总时间复杂度取最高阶项$O(n^2)$[^4]。 --- ##### **例题5:条件分支** ```python def example5(n, flag): count = 0 if flag: for i in range(n): # O(n²) for j in range(n): count += 1 else: for k in range(n): # O(n) count += 1 return count ``` **解析** - 根据条件选择分支,时间复杂度取最大可能的复杂度$O(n^2)$[^4]。 --- #### 四、总结 1. **单层循环**:$O(n)$ 2. **嵌套循环**:各层循环次数相乘,如$O(n^2)$ 3. **对数循环**:循环变量以倍数增长,如$O(\log n)$ 4. **组合结构**:取各部分最大时间复杂度 #### 五、练习 1. 分析以下代码的时间复杂度: ```python def practice(n): total = 0 for i in range(n): for j in range(i, n): total += 1 return total ``` **提示**:内层循环次数从$i$到$n$,总次数为$\frac{n(n+1)}{2}$。 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值