简单认识时间复杂度和空间复杂度

本文详细介绍了时间复杂度的计算方法,包括大O表示法及其原则,展示了常见渐进函数,并对比了不同复杂度级别。同时,深入讲解了空间复杂度的定义及计算,通过实例解析了空间复杂度的计算技巧。

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

1. 算法效率

算法效率分析分为两种:

  • 第一种是时间效率,即时间复杂度。
  • 第二种是空间效率,即空间复杂度。

2. 时间复杂度

在计算机科学中,时间复杂性,又称时间复杂度,算法的时间复杂度是一个函数,它定性描述该算法的运行时间。这是一个代表算法输入值的字符串的长度的函数。

🆗时间复杂度主要是由次数决定的。
一般来说,程序对数据处理的次数越多,程序所花费的时间就越多。即:
算法的执行时间 =∑ 原操作(i)的执行次数×原操作(i)的执行时间

2.1 大O的渐进表示法

先了解下渐进分析的概念:

渐进分析:忽略用来表示问题规模和时间关系的函数中不能显著改变函数数量级的部分,其结果是原函数的近似值,该近似值在问题规模很大时会足够接近原值。

大O的渐进表示法考虑的是程序运行的最坏的时间情况,故算法的时间复杂度通常是用大O的渐进表示法来进行估算的。

2.11 大O的渐进表示法的原则

先来看看下面代码中的语句x*=2执行次数T(n)

int main()
{
	int n = 0;
	int x = 2;
	scanf("%d", &n);
	for (int i = 1; i < n; i++)
	{
		for (int j = 1; j < 2 * n; j++)
		{
			x *= 2;   //语句1 
		}
	}
	return 0;
}

显然T(n) = ( n - 1 ) * ( 2n - 1 ) = 2n2 - n - 1.
在计算时间复杂度的时候并不需要精确的计算,我们只需对算法进行简单化的评估,把注意力放在最只要的部分。
在大O的渐进分析法中是用程序执行次数的最高阶项的数量级来表示其时间复杂度。
🆗这里的T(n)的项数如下:

2n2-n-1
对应项的数量级n2n1

显然,最高项的数量级为: n2
故这个程序的时间复杂度为O(n2)
🔥下面是大O表示法的方法:

  • 寻找循环和递归得到大致的数据处理次数表达式
  • 去掉表达式中每项的系数
  • 取最高阶项的数量级来表示其时间复杂度

2. 12 常用的渐进函数

函数名称
O(1)常量级
O(logn)对数级
O(n)线性级
O(n logn)n个logn
O(n2平方级
O(2n指数级
O(n!)阶乘级


🍈一般地,常用的时间复杂度有如下关系:
O(1) ≤ O(logn) ≤ O(n) ≤ O(nlogn) ≤ O(n2) ≤ O(n3) ≤ … ≤ O(nk) ≤O(2n) ≤O(3n) ≤O(n!)

2.2总结

  • 算法的时间复杂度通常以算法中关键操作重复执行的次数作为度量标准。
  • 循环递归来作为主要目标来进行估算
  • 估算时只需求出其关于n的数量级即可。

3.空间复杂度

空间复杂度是来形容算法的存储空间需求,他是用来描述程序运行时程序对内存占用最大时刻时程序占用的空间。(读起来会很变扭,主要是为了强调空间是可以重复使用的,后面会再次强调的)

3.1空间复杂度的计算

空间复杂度取决与开辟内存的大小,比如一般的变量的建立,数组的声明,函数栈帧的创建等。

🌠函数小补充
简单理解,函数在调用时会有两个指针在内存上移动,而这两个指正中间部分的内存即为函数栈帧开辟的内存。

空间复杂度的计算方式和时间复杂度是一样的,都是使用大O的渐进表示法,这里便不多提。

🚀 例子

    public static void main(String[] args) {
        int[] arr = new int[5];
        for (int i = 0; i < arr.length; i++) {
            arr[i] = i;
        }

在这个程序的空间复杂度为O(1),关键代码int[] arr = new int[5]开辟了5个int大小的的空间,故空间复杂度为常数级O(1) 。
同样的,int[][] arr = new int[n][n];对应的是O(n2
2️⃣再来看看下面这个代码

    public static void main(String[] args) {
        int n=new Scanner(System.in).nextInt();
        for (int i = 0; i < n; i++) {
            int num=1;
        }
    }

每个循环时都会开辟一个int大小的空间给num,而当给num开辟新的内存其实是将num中的引用换成新开辟空间的引用。所以是O(1).

在这里插入图片描述
3️⃣最后一个!!
递归的斐波那契。

long Fib(int N) {
return N < 2 ? N : Fib(N-1)+Fib(N-2);
}

前面提过,函数在调用的时候也是会开辟内存的,即使是传入相同的参数也是会重新开辟的.
如果仅仅是看开辟过的内存的话应该会得到下面的样子
在这里插入图片描述
通过估计大致可以得到空间复杂度是O(2n),然而它真正的空间复杂度是O(n).
在分析空间复杂度时要根据代码的逻辑进行判断,在return N < 2 ? N : Fib(N-1)+Fib(N-2)
N>=2时会执行return Fib(N-1)+Fib(N-2) ,而程序读到Fib(N-1)时就会进入函数内部,只有当左边的Fib(N-1)读取结束后才会读取右边的Fib(N-2).

在这里插入图片描述

以此类推,只有左边全部走完后才会考虑右边的函数调用.
而当F(1)调用完毕后准备调用F(2)时,F(1)因为已近调用完毕其内存以及被释放出来了,其余部分也如此
故最终,程序的空间复杂度为O(n)。

评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值