算法的时间复杂度和空间复杂度

1. 衡量算法的指标

同一个问题可以用不同的算法解决,而一个算法的优劣将影响到算法乃至程序的效率。算法分析的目的在于为特定的问题选择合适算法。一个算法的评价主要从时间复杂度和空间复杂度来考虑。
算法在时间的高效性和空间的高效性之间通常是矛盾的。所以一般只会取一个平衡点。通常我们假设程序运行在足够大的内存空间中,所以研究更多的是算法的时间复杂度

2. 时间复杂度

时间复杂度的计算不是通过计算程序的具体运行时间,而是算法执行语句的次数。
(1)语句频度T(n): 一个算法执行所花费的时间,从理论上是不能算出来的,必须上机运行测试才能知道。但我们不可能对每个算法都上机测试,只需知道哪个算法花费的时间多,哪个算法花费的时间少就可以了。而且一个算法花费的时间与算法中的基本操作语句的执行次数成正比例,哪个算法中语句执行次数多,它花费时间就多。一个算法中的语句执行次数称为语句频度,记为T(n)。
(2)时间复杂度: 在刚才提到的语句频度中,n称为问题的规模,当n不断变化时,语句频度T(n)也会不断变化。但有时我们想知道它的变化呈现什么规律。为此,我们引入时间复杂度概念。 一般情况下,算法中的基本操作语句的重复执行次数是问题规模n的某个函数,用T(n)表示,若有某个辅助函数f(n),使得当n趋近于无穷大时,T(n) / f(n) 的极限值为不等于零的常数,则称f(n)是T(n)的同数量级函数。记作 T(n)=O( f(n) ),称O( f(n) ) 为算法的渐进时间复杂度,简称时间复杂度。T(n) 不同,但时间复杂度可能相同。 如:T(n)=n²+5n+6 与 T(n)=3n²+3n+2 它们的T(n) 不同,但时间复杂度相同,都为O(n²)。
(3)平均时间复杂度和最坏时间复杂度:
平均时间复杂度是指所有可能的输入实例均以等概率出现的情况下,该算法的运行时间。
最坏情况下的时间复杂度称最坏时间复杂度。一般讨论的时间复杂度均是最坏情况下的时间复杂度。 这样做的原因是:最坏情况下的时间复杂度是算法在任何输入实例上运行时间的界限,这就保证了算法的运行时间不会比最坏情况更长。

2.1 常见的时间复杂度

  • 常数阶O(1)
  • 对数阶O(log2n)
  • 线性阶O(n)
  • 线性对数阶O(nlog2n)
  • 平方阶O(n2)
  • 立方阶O(n3)
  • k次方阶O(nk)(一般控制k的大小,否则就和指数阶一样)
  • 指数阶O(2n)(一般不使用,性能较差)
    随着n的不断增大,时间复杂度不断增大,算法花费时间越多。

2.2 时间复杂度的计算方法

(1)计算方法:

  • 选取相对增长最高的项
  • 最高项系数化为1
  • 若是常数的话用O(1)表示
    如f(n)=2*n3+2n+100,则O(n)=n3
    通常我们计算时间复杂度都是计算最坏情况

(2) 如果算法的执行时间不随着问题规模n的增加而增长,即使算法中有上千条语句,其执行时间也不过是一个较大的常数。此类算法的时间复杂度是O(1)。

	int x = 1;
	while(x < 10){
		x++;
	}

该算法执行次数为10,是一个常数,用时间复杂度表示是O(1)。

(3) 当有若干个循环语句时,算法的时间复杂度是由嵌套层数最多的循环语句中最内层语句的频度f(n)决定的。

	for(int i = 0; i < n; i++){
		for(int j = 0; j < n; j++){
		//to do;
		}
	}

最外层循环每执行一次,内层循环都要执行n次,执行次数是根据n所决定的,时间复杂度是O(n2)。

(4) 循环不仅与n有关,还与执行循环满足的判断条件有关。

	int i = 0;
	while(i < n && arr[i] = 1){
		i ++;
	}

在此循环中,如果arr[i]不等于1的话,时间复杂度是O(n)。如果arr[i]等于1的话,则循环不能执行,时间复杂度是0。

3. 空间复杂度

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

3.1 空间复杂度的计算方法

(1) 计算方法

  • 忽略常数,用O(1)表示
  • 递归算法的空间复杂度= 递归深度N * 每次递归所要的辅助空间
  • 对于单线程来说,递归有运行时堆栈,求的是递归最深的那一次压栈所耗费的空间的个数,因为递归最深的那一次所耗费的空间足以容纳它所有递归过程。
    如:
	int a;
	int b;
	int c;
	System.out.printf("%d %d %d\n",a,b,c);

空间复杂度O(n) = O(1);

	int fun(int n){
		int k = 10;
		if(n == k){
			return n;
		}else{
			return fun(++n);
		}
	}

递归实现,调用fun函数,每次都创建1个变量k。调用n次,空间复杂度O(n * 1) = O(n)。

4. 计算案例

4.1 实现二分查找算法的递归及非递归

4.1.1 迭代算法
public class Test {
	public static void main(String[] args) {
		int arr[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
		int length = arr.length;
		int aim = 9;
		int result;

		result = binarySearch(arr, length, aim);

		if (result == -1) {
			System.out.println("Can't find " + aim);
		} else {
			System.out.println(aim + " is at position " + result);
		}
	}

	static int binarySearch(int arr[], int len, int num) {
		int left = 0;
		int right = len - 1;
		int mid;
		while (left <= right) {
			mid = (left + right) / 2;
			if (num > arr[mid]) {
				left = mid + 1;
			} else if (num < arr[mid]) {
				right = mid - 1;
			} else {
				return mid;
			}
		}
		return -1;
	}
}

二分查找时,每次都在原有查找内容进行二分,所以时间复杂度为O(log2 n)
因为变量值创建一次,所以空间复杂度为O(1)。

4.1.2 递归算法
package com.matthew.xu;

public class Test {
	public static void main(String[] args) {
		int arr[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
		int length = arr.length;
		int aim = 9;
		int result;

		result = binarySearch(arr, 0, length - 1, aim);

		if (result == -1) {
			System.out.println("Can't find " + aim);
		} else {
			System.out.println(aim + " is at position " + result);
		}
	}

	static int binarySearch(int[] arr, int left, int right, int num) {
		System.out.println(left + "," + right + "," + num);
		int mid = (left + right) / 2;
		if (left <= right) {
			if (num > arr[mid]) {
				left = mid + 1;
				return binarySearch(arr, left, right, num);
			} else if (num < arr[mid]) {
				right = mid - 1;
				return binarySearch(arr, left, right, num);
			} else if (num == arr[mid]) {
				return mid;
			}
		}
		return -1;
	}
}

时间复杂度为O(log2 n)。
每进行一次递归都会创建变量,所以空间复杂度为O(log2 n)。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值