【Algorithms公开课学习笔记2】 算法性能分析方法

Analysis of Algorithms 算法性能分析方法

1.Observation观察

使用编程语言实现一个算法,测试其运行时间是一件非常重要的事情。

常用的有以下3中方法(针对Java程序)

方法1:手动测量

直接使用计时器来测量运行时间(估计没有人会接受这种方法)

方法2:使用程序自动测量

在java中Stopwatch类里面有elapsedTime()方法可以测量程序的运行时间。

Stopwatch stopwatch=new Stopwatch();
double time =stopwatch.elapsedTime();

好处是使用方便,效果明显;缺点是当运行时间较长的,需要观察者等待。

方法3:数据模型分析

在下表的数据中:

运行时间TN与N的关系的非线性的,不易确定其模型,如下图:

那么可以两边取对数,取得其重对数图像,如下图:

由于呈线性关系,假设其模型为lg(TN)=blg(N)+c

对以上模型两遍取平方,得到幂定律:TN=aN^b

因此,通过数据所推演的模型是符合幂定律的。接着要推算常数a与b的值

对于常数b,使用双倍假设法r=T2N/TN=2^b,所以b=lg®

对于常数a,使用过表中的数据即可求出近似值

2.mathematical model数学模型

一般而言,都是使用开销最大、频率最高的操作来代表算法的的运行时间的。例如具体开销的1/6N^3+100N+16,那么描述的时候就近似于~1/6N3

常用的几个运行时间的模型如下图所示:

3.order-of-growth classifications 增长阶数分类

增长阶数分类主要有以下

开销英文名称代表算法
1constant一行代码
lgNlogarithmic对有序数列的二叉搜索
Nlinear循环
NlgNlinearithmic归并排序
N^2quardratic二重循环
N^3cubic三重循环
2^Nexponential查子集

各类别的增长曲线如下图:

这里主要分析一下3-sum问题:即从一个集合中找到3个数,是这3个数的和是指定的值(如a1+a2+a3=10)。

通常,我们可以使用三重循环来完成

/**
	 * 三重循环O(N3)
	 */
	public void solution1() {
		List<Integer> numList = new ArrayList<>();

		for (int i = 0; i < numList.size(); i++) {
			// 内循环避开已遍历过的树
			for (int j = i + 1; j < numList.size(); j++) {
				for (int k = j + 1; j < numList.size(); k++) {
					// 找出和未10的数
					if (numList.get(i) + numList.get(j) + numList.get(k) == 10) {
						// 输出操作(没写)
					}
				}
			}
		}

	}

分析其时间复杂度,发现内循环的一条语句需要重复执行C(3,N)次

其中,C(3,N)=[n(n-1)(n-2)]/3!~n^3/6

这是3阶的情况,时间代价不可接受。

换一种思路,先使用选择排序法将数列从小到大排序,消耗NlgN的时间

再使用二重循环计算a[i]+a[j]的和s,再使用二叉搜索找10-s的值是否在数列里,消耗N*NlgN的时间(进行N的平方次搜索)

/**
	 * 改进方法O(N2lgN)
	 */
	public void solution2() {
		List<Integer> numList = new ArrayList<>();

		// 选择排序法排序,sort是选择排序函数
		sort(numList);

		for (int i = 0; i < numList.size(); i++) {
			for (int j = i + 1; j < numList.size(); j++) {
				// bSearch是二叉搜索函数(没写)
				if (bSearch(-(numList.get(i) + numList.get(j)))) {
					// 输出操作(没写)
				}
			}
		}

	}

4.算法分析理论

对于解决某种类型的算法存在最好的情况和最坏的情况,其中,最好的情况称为下界,而最坏的情况称为上界:

最坏的情况(上界)
|----------------|
存在优化的算法
|----------------|
最好的情况(下界)

在算法分析理论中由以下常用的标识

标识示例说明
~~N运行时间近似于N*C (C是常数)
big OhO(N)运行时间的上界是N*C
big Thetalinear运行时间就是N*C
big Omegalinearithmic运行时间的下界是N*C

通常,我们都是错误地将O(N)使用成~N,但随着使用人数增加,尽管是错误的,大家都是工人这两种标识都是一样的。

5.内存消耗(空间复杂度)

下面是Java基本类型的占用的内存字节数

typebytes
boolean1
byte1
char2
int4
float4
long8
double8
char[]2N+24(其中24的固定字节)
int[]4N+24
double[]8N+24
char[][]~2MN
int[][]~4MN
double[][]~8MN

对于对象而言,其所占字节有以下部分组成,结合下图参考下表

partbytes
Object overhead16
Reference8
padding将占用内存凑成8Byte的整数倍

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值