【数据结构】算法复杂度分析

博客介绍了算法复杂度分析的必要性,因事后统计法有依赖测试环境和受数据规模影响大的局限,所以采用时间和空间复杂度表示。阐述了大O时间复杂度的由来、表示方法及分析方法,列举常见时间复杂度类型,还提及最好、最坏、平均时间复杂度和空间复杂度分析。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.为什么需要复杂度分析

虽然将代码执行⼀遍,通过统计、监控等手段就能得到算法执行时间和占用内存大小(有些书上将这种方法称为事后统计法),但是这种方法有2个局限性。

  1. 测试结果非常依赖测试环境。
  2. 测试结果受数据规模影响很大。

所以一般不采用这种方法,而是采用时间复杂度和空间复杂度两方面来表示算法复杂度。

2.大O时间复杂度的由来与表示方法

eg1.

	int cal(int n){
        int sum = 0;
        int i = 1;
        for (;i <= n;i++){
            sum = sum + i;
        }
        return sum;
    }

假设执行每行代码的时间是n,则总时间T(n) = 2n + 3(一个循环条件n次,循环结果n次,共2n次)

eg2.

	int cal(int n) {
        int sum = 0;
        int i = 1;
        int j = 1;
        for (; i <= n; ++i){
            j = 1;
            for (; j <= n; ++j) {
                sum = sum + i * j;
            }
        }
    }

外部for循环执行了2n次,内部for循环执行了2n^2, 所以T(n) = 3+2n+2n^2

至此,我们可以总结出一个规律:所有代码的执行时间 T(n) 与每行代码的执行次数 n 成正比,可以写成一个公式:T(n) = O(f(n))。T(n)表示代码执行的总时间,n表示数据规模的大小,f(n)表示每段代码执行的次数之和,O表示T(n)与f(n)成正比。这就是大O时间复杂度表示法。
大O时间复杂度实际并不是代码时间执行时间,只是表示一种数据代码执行时间,随数据规模增长的变化趋势。所以也叫做渐进时间复杂度,简称:时间复杂度

3.时间复杂度如何分析

1.只关注循环次数最多的那一段代码
2.加法法则:总复杂度等于量级最大的那一段代码的复杂度

时间复杂度表示的是一种趋势,所以可以忽略掉低阶、常量、系数,只用关心最高阶即可。
所以eg1的时间复杂度为O(n),eg2为O(n^2)

3.乘法法则:嵌套代码的复杂度等于嵌套内外代码复杂的乘积

eg3.

int cal(int n) {
        int ret = 0;
        int i = 1;
        for (; i < n; ++i) {
            ret = ret + f(i);
        }
    }
    int f(int n) {
        int sum = 0;
        int i = 1;
        for (; i < n; ++i) {
            sum = sum + i;
        }
        return sum;
    }
for(int i = 0;i < n;i++){
	for(int j = 0; j < i;j++){}	
}

这两种时间复杂度为O(n^2)

4.常见的的时间复杂度:

1.多项式时间复杂度:
除O(1),O(n),O(n^2)外常见的还有O(logn)、O(nlogn)、O(m + n)、O(m * n)
1.1 O(1):
只要代码不随n的增长而变化,即为这O(1)。

1.2 O(logn):
eg4.

int i = 1;
while(i <= n) {
  i = i * 2;
}

i每循环一次就乘2,所以循环m次之后,2^m > n,则m = log⁡(n)\log(n)log(n)
根据换底公式,所有对数形式的都可以换为以2为底的对数.

1.3 O(nlogn):
eg5.

int i = 1;
for(int i = 0;i < n;i++){
	while(i <= n) {
 	i = i * 2;
	}
}

1.4 O(m + n)
eg6.

int cal(int m, int n) {
	  int sum_1 = 0;
	  int i = 1; 
	  for (; i < m; ++i) {
	  	sum_1 = sum_1 + i;
	  }
	  int sum_2 = 0;
	  int j = 1;
	  for (; j < n; ++j) {
	  	sum_2 = sum_2 + j;
	  }
	  return sum_1 + sum_2;
}

无法事先评估m与n的量级大小,所以无法直接省略掉一个,所以为(m + n)。
O(m * n) 同理。

2.非多项式时间复杂度:(这种情况较少,当n越来越大时,非多项式的时间复杂度急剧增加,因此非多项式的算法基本不用)
O(2^n)
O(n!)

5.最好,最坏,平均时间复杂度

eg7.

int find(int[] array, int n, int x) {
        int i = 0;
        int pos = -1;
        for (; i < n; ++i) {
            if (array[i] == x) {
                pos = i;
                break;
            }
        }
        return pos;
    }

最好情况:O(1)
最坏情况:O(n)
平均:共有(n + 1)种情况,n种在数组中,一种不在数组中,加权平均之后,时间复杂度还是为O(n)
在这里插入图片描述
也可以这样理解:最平均的话就是在最中间的那个位置,当n逐渐变大的时候,中间的次数也会变化,所以也是O(n)

6.空间复杂度分析

空间复杂度是对一个算法在运行临时占用存储空间大小的度量。
eg8.

public static int sum(int n) {
 	int count = 0;
	for (int i = 1; i <= n; i++) {
 		count += i;
 	}
 return count;
}

算法执行所需要的临时空间不随着某个变量n的大小而变化,即此算法空间复杂度为一个常量,可表示为S(n) = O(1)。
eg9.

int[] m = new int[n]
for(i=1; i<=n; ++i)
{
   j = i;
   j++;
}

这段代码中,第一行new出来一个数组之后占用的空间大小为n,,此后几行虽然有循环,但是没有再分配新的空间,因此这段代码的复杂度只用看第一行即可,S(n) = O(n)
附:
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

我顶得了

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

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

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

打赏作者

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

抵扣说明:

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

余额充值