2.3、由java实现的简单算法——时间复杂度

一  前言

如果对本系列产生什么疑问的话,  建议先下前言,  里面有我的联系方式,  教材的下载地址,   特殊词语的规定之类的........   链接地址: https://blog.csdn.net/qq_41057280/article/details/89209081 ;   最后, 以下说法仅为个人理解, 如有错误, 欢迎教正

二  介绍

程序语句重复执行的次数作为程序的时间量度。时间复杂度则是描述该时间量度的函数.  如果通俗点解释的话,  时间复杂度就是程序语句的执行次数的函数表达式。 

时间复杂度常用大O符号表述,不包括这个函数的低阶项和首项系数。使用这种方式时,时间复杂度可被称为是渐近的,亦即考察输入值大小趋近无穷时的情况。

三、渐近时间复杂度

时间复杂度虽然可以表述为执行次数的函数表达式,但是不代表直接用该表达式进行算法效率的比较。因为一个算法执行所耗费的时间,从理论上是不能算出来的,必须上机运行测试才能知道。但我们不可能也没有必要对每个算法都上机测试,只需知道哪个算法花费的时间多,哪个算法花费的时间少就可以了。并且一个算法花费的时间与算法中语句的执行次数成正比例,哪个算法中语句执行次数多,它花费时间就多。

不过,一个算法运行不只包含算法本身,还有维持该算法运行的其他语句,但比较算法优劣的时候不应该将其包括在内。  因此,计算时间复杂度时,一般将其排除。也就是排除常数项

并且,在程序中,不同的输入值,运行次数不同,可能产生不同的比较结果。因此我们通常使用算法的最坏情况复杂度(一般是无穷大)来进行比对。

所以,我们应该比较的是时间复杂度的增长率(因为无穷大无法计算)。 举个例子, O(n)与 O(n^2)一眼就能看出, O(n^2)的时间复杂度大。 但是O(n)与O(n+1)呢?在无穷大的时候,这两者的差距是忽略不计的,可以写作O(n)。这便是渐近时间复杂度

 四、计算方法

原理说完了,下面总结下该如何计算。

  1. 找出算法的具体实现语句
  2. 计算该语句的基础数量级
  3. 只保留最高项(不小于1)
  4. 去掉常数项和最高项的系数
  5. 如果不存在最高项(不小于1),计作O(1)
  6. 用大O表示该表达式

五、计算示例

为了方便理解,我这边写几个简单的例子。下列示例的参数都是代表问题规模n, 每行后面的注释代表当前行的执行次数

1、时间复杂度: O(1)

执行次数2次

因为,如果不存在最高项(不小于1),只能计作O(1)

所以时间复杂度为O(1)

	public void test1(int n) {
		int x = n + 1; // 1
		System.out.println(x); // 1
	}

2、时间复杂度: O(n)

执行次数为 (n+1) + n = 2n+1

去掉常数项和最高项的系数

所以时间复杂度为O(n)

	public void test2(int n) {
		for (int i=0; i<n; i++) { // n+1
			System.err.println(i); // n
		}
	}

3、时间复杂度: O(n²)

执行次数: (n+1) + n(n+1) + n² = 2n² + 2n + 1

只保留最高项(不小于1)去掉常数项和最高项的系数

所以时间复杂度为O(n²)

	public void test3(int n) {
		for (int i=0; i<n; i++) { // n+1
			for (int j=0; j<n; j++) { // n(n+1)
				System.out.println(i + ":" + j); // n²
			}
		}
	}

如果不懂for循环执行次数为什么加1,那请你回头看看for循环的原理。

时间复杂度的基本计算规则大抵就是这些。

说到底,可以不用标注其余语句的执行次数,只标注代码的运算主体即可(也就是上面的system.out输出语句)。在绝大多数情况下,运算主体的执行次数就是算法的时间复杂度

下面的例子也就不再对全部语句进行标注

4、 O(logn)

logn = log₂n

这里的执行主体是 i *= 2;  可以推出等式 2的i次方 <= n, 即 i = logn = log₂n

所以时间复杂度为 O(logn) 

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

5、O(logₖn)

同理可得,下列算法的时间复杂度为O(logₖn)

	public void test5(int n, int k) {
		int i = 1;
		while(i< n) { 
			i *= k;
		}
	}

6、O(n)

这是一段递归算阶乘的程序, 其总运算次数为 n。所以时间复杂度为O(n)

	public int test6(int n) {
		if (n <= 1) return 1;
		return n * test6(n -1); 
	}

7、O(nlogn)

	public void test7(int n) {
		for (int i=0;i<n; i*=2) { // 注意这里, i *= 2
			for (int j=0; j<n; j++) { 
				System.out.println(i + ":" + j); 
			}
		}
	}

8、O(√n)

运算过程为 1+2+……+i >= n, 用等差数量的求和公式, i(1 + i)/2 >= n 
所以, 时间复杂度为O(√n)

	public void test8(int n) {
		int i = 0;
		int sum = 0;
		while(sum < n) {
			sum += ++i; // ++i => i=i+1, 自增之后再运算
		}
	}

9、O(³√n)

i*i*i > n  => i > ³√n

所以, 时间复杂度为O(³√n)

	public void test9(int n) {
		for (int i=1; i<=n; i = i*i*i) {
			System.err.println(i);
		}
	}

六、总结

时间复杂度一般求的是最坏时间复杂度,即n为无穷大时。为了方便对比,采用渐近时间复杂度进行表示,也就是大O。

一般来讲,时间复杂度有下列基准进行对比:

c < log2N < n < n * Log2N < n^2 < n^3 < 2^n < 3^n < n!

c为常数, 时间复杂度越大,代表代码执行效率越低。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值