浅谈时间复杂度

在此之前,先了解他们是如何产生的。学习数据结构与算法本身就是为了让代码可以高效运行,更省存储空间。而考究算法的质量就用到了时间、空间复杂度。

一、时间复杂度

一个算法执行所耗费的时间,从理论上是不能算出来的,必须上机运行测试才能知道。但我们不可能也没有必要对每个算法都上机测试,只需知道哪个算法花费的时间多,哪个算法花费的时间少就可以了。并且一个算法花费的时间与算法中语句的执行次数成正比例,哪个算法中语句执行次数多,它花费时间就多。一个算法中的语句执行次数称为语句频度或「时间频度」。记为T(n)。

时间频度T(n)中,n称为问题的规模,当n不断变化时,时间频度T(n)也会不断变化。但有时我们想知道它变化时呈现什么规律,为此我们引入时间复杂度的概念。算法的时间复杂度也就是算法的时间度量,记作:T(n) = O(f(n))。它表示随问题规模n的增大,算法执行时间的增长率和f(n)的增长率相同,称作算法的渐进时间复杂度,简称「时间复杂度」。

这种表示方法我们称为「 大O符号表示法」,又称为渐进符号,是用于描述函数渐进行为的数学符号

T(n)不同,但时间复杂度可能相同。如:T(n) = n2+3n+2,T(n) = n2+5n+8 ,T(n)不同,但时间复杂度都为O(n2)

计算时间复杂度的方法

  • 用常数1(代表常数项的复杂度为O(1))来代替运行时间中的所有加法常数
  • 修改后的运行次数函数中,只保留了最高阶项
  • 去除最高阶项的系数
常见的的时间复杂度(按照按照耗费的时间由低到高排序):
描述时间复杂度
常数阶O(1)
对数阶O(logn)
线性阶O(n)
线性对数阶O(nlogn)
平方阶O(n²)
立方阶O(n³)
k次方阶O(nk)
指数阶O(2n)
阶乘阶O(n!)

解析

  1. O(1)

    ​ O(1)表示常量阶时间复杂度,并非只执行一行代码。代码的的执行时间不是随着n的增大而增大的,这样的代码的时间复杂度都为O(1)。一般来讲算法中不存在循环、递归,即使代码有很多行,时间复杂度依然为O(1)。

    public static void main(String[] args){
            int a = 2;//执行一次
            int b = 3;//执行一次
            int sum = a+b;//执行一次
    }
    

    哈希算法就是典型的O(1)时间复杂度,无论数据规模多大,都可以在一次计算后找到目标(不考虑冲突的话)

  2. O(n)

    ​ O(n)表示线性阶时间复杂度,大部分遍历就是线性级算法。

    public static void main(String[] args){
    	int sum = 0;//执行1次
    	int n = 100;//1次
    	for(int i =1; i<=100 ; i++){
    		sum +=i; //执行n次
    	}
    }
    
  3. O(log2n)

    ​ O(log2n)表示对数阶时间复杂度,如下代码,在while循环里面,每次都将 count 乘以 2,乘完之后,count 距离 n 就越来越近了。假设循环x次之后,count 就大于 2 了,此时这个循环就退出了,也就是说 2 的 x 次方等于 n,那么 x = log2n也就是说当循环 log2n 次以后,这个代码就结束了。因此这个代码的时间复杂度为:O(log2n) 。 O(log2n) 的这个2 时间上是根据代码变化的,count = count * 3 ,则是 O(log2n) 。

    int count = 1;
    while (count < n){    
        count = count * 2; /* 时间复杂度为O(1)的程序步骤序列 */
    }
    
  4. O(nlog2n)

    ​ 线性对数阶O(nlogN) 其实就是将时间复杂度为O(logn)的代码循环N遍的话,那么它的时间复杂度就是 n * O(logN),也就是了O(nlogN)

    for(i = 1 ; i < n ; i++){
        int j = 1;
        while(j < n){
            j = j * 2 ;
        }
    }
    
  5. O(n²)

    ​ 表示一个算法的性能将会随着输入数据的增长而呈现出二次增长。最常见的就是对输入数据进行嵌套循环。如果嵌套层级不断深入的话,算法的性能将会变为立方阶O(n3)、O(n4)、O(nk)以此类推

    for(int i=0;i<n;i++){   // 循环次数为 n
          for(int j=0;j<n;i++){// 循环次数为 n
          //复杂度为O(1)的算法
             ... 
          }
      }
    
  6. O(2n)

    ​ 表示一个算法的性能会随着输入数据的每次增加而增大两倍,典型的方法就是裴波那契数列的递归计算实现

    public int getFbnqNum(int n){
        if (n <= 1){
            return n;
        }
        return getFbnqNum(n-1)+getFbnqNum(n-2);
    }
    

二、常用排序算法对比

排序算法平均时间复杂度最好情况最坏情况空间复杂度稳定性
冒泡排序O(n2)O(n)O(n2)O(1)稳定
选择排序O(n2)O(n2)O(n2)O(1)不稳定
插入排序O(n2)O(n)O(n2)O(1)稳定
希尔排序O(nlog2n)O(nlog2n)O(n2)O(1)不稳定
归并排序O(nlog2n)O(nlog2n)O(nlog2n)O(n)稳定
快速排序O(nlog2n)O(nlog2n)O(n2)O(nlog2n)不稳定
堆排序O(nlog2n)O(nlog2n)O(nlog2n)O(1)不稳定
计数排序O(n+k)O(n+k)O(n+k)O(n+k)稳定
桶排序O(n+k)O(n)O(n2)O(n+k)稳定
基数排序O(n*k)O(n*k)O(n*k)O(n+k)稳定

(k:代表桶)

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

叁Mar.

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

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

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

打赏作者

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

抵扣说明:

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

余额充值