时间估计---预测一个算法处理一定规模数据所需的时间

当你写的一个程序在跑一组很大的数据的时候结果迟迟没有出来,这个时候你就会想这个程序要跑多久?
那么不要等了,尝试估计一下让心里有个底,不再迷茫等待!
当你想到一个算法处理一定数据量所需要的时间会是多少,你先会去计算这个算法的时间复杂度。时间复杂度是估计一个程序运行时间概念上的重要参考。

一般估计

如果算法的时间复杂度是线性的,数学模型是 T = aN + b;

  • T是运行时间
  • N是数据规模
    下面出现的T,N含义都一样.
    尝试绘制一个N关于T的函数图像。

倍率实验


倍率实验的数据表现形式

实验规模实验耗时倍率(本次实验与上一次实验运行时间之比)
NTX

实验规模按N的倍数增长

实验的数据来源于随机生成

理论依据

如果一个算法的时间复杂度是T(N)且T(N)~a(N^b)lgN那么
T ( 2 N ) / T ( N ) →   2 b T(2N)/T(N) \rightarrow\ 2^b T(2N)/T(N) 2b

实验的准备

一个模拟数据生成器
这个生成器得就是一个方法,该方法

  • 接收一个模拟规模数

  • 返回 算法处理这个规模的数据所需要的时间
    我们来看下面的这个实现

/**
	 * 
	 * @param n 模拟数据的规模
	 * @return 返回算法处理这个规模数据所耗费的时间
	 */
public static double libIn(Integer n) {
		Random ran = new Random();
		int[][] Data = new int[n][2];//模拟数据容器
		for(int i = 0; i<n; i++)
		{
			Data[i][0] = ran.nextInt(n);
			Data[i][1] = ran.nextInt(n);
		}//随机生成数据
		Stopwatch stopwatch = new Stopwatch();//开始计时 beginTime
		//算法开始
		QuickUnion uf = new QuickUnion(n);
		for(int[] a : Data)
		{
			int p = a[0];
			int q = a[1];
			if(uf.connected(p, q))
				continue;
			uf.union(p, q);
		}
		//算法结束
		return stopwatch.elapsedTime();//结算耗时 currentTime - beginTime
	}

预测方式

假设 算法处理N组数据所需要的时间为time

  1. 选定一个初始规模N。记录其运行时间 T。

  2. 根据倍率实验的数据得出 倍率 X

  3. 根据公式

N 0 ∗ 2 b = N N_{0} * 2^b = N N02b=N

算出
b = l o g 2 N / N 0 b = log_2{N/N_0} b=log2N/N0
最后得到运行时间
t i m e = T 0 ∗ X b time = T_{0}*X^b time=T0Xb
这是根据极限比例来计算的。即 N–>无穷
你如果没有看过书,我这个专题的名字就是那本书的名字,你会看不懂,不过没关系,你可以根据下面的实例演示结合体会;
除了根据极限比例,我们还可以通过绘图!

幂次法则

描绘 对数图像
一个二维图像

  • X轴:lg(N )
  • Y轴:lg(T(N)) (时间的对数)
  • T(N) 是数据量和时间的关系函数。

用这个法则怎么来算程序的运行时间呢
设这个算法满足数学模型
l g ( T ( N ) ) = k l g ( N ) + l g ( a ) ① lg(T(N)) = klg(N) + lg(a)① lg(T(N))=klg(N)+lg(a)

T = T ( N ) T = T(N) T=T(N)
k是图像的斜率,而a的计算只需要从实验数据中取一对(N,T)带入公式就能得出.
我们再将上面的公式①推一推就可以得到
T ( N ) = a ∗ N k T(N) = a*N^k T(N)=aNk
给你们看一个图。
在这里插入图片描述

代码贡献

模拟数据生成器,因应对的算法的不同而不同。
而倍率实验因为对任何的算法的数据输出格式都是一致的。
所以我现实了一个倍率实验通用类。
如果你想使用下面的代码,那么你只需要实现一个方法将其标志为public double libIn(Integer n),方法实现请参考上面的代码,然后将包含这个方法的类的对象作为参数传给MPA的构造方法。
当你得到倍率实验数据的时候,我们就可以从实验数据中提取相关的参数,来预测该算法在处理一定规模数据时大概将耗费的时间。
为了方便,我同时也实现了这样的一个类,你需要提供

  • 预测数据的规模 targetN
  • 实验数据中的一个数据规模 startN
  • 该规模对应的运行时间 baseTime
  • 倍率 X
  • startN怎么选? 这个的选择没有一定。一般来讲,在倍率接近于X的数据项中选中间的一个。
  • 倍率X怎么确定? 最下面的一项的倍率就是我们的X因为越靠近下面即数据规模越大越趋近于理论倍率。
//倍率实验 
/**
 * 用于  预测一个算法在处理一定量数据(很大的数据量)时所需要的时间
 * 信息输出格式   数据量 + 运行时间 + 与上一次实验运行时间之比
 * 当比值趋近于 2^b次方时 倍率被确定
 * 计算一个实验需要的时间 用上一次实验的时间乘于2^b 并将N加倍 如此反复
 */
public class MPA{
	Class<?> cla;
	Object obj;
	/**
	 * @param obj 需要传递一个你实现的模拟数据生成器的实例对象
	 */
	public MPA(Object obj)
	{
		this.cla = obj.getClass();
		this.obj = obj;
	}
	
	/**
	 * 输出的数据格式是 数据规模---实验耗时---倍率
	 * @param startDataGroup 初始的实验数据规模 以后的数据规模按这个规模成倍增长
	 * @throws Exception
	 */
	public void mpaExp(int startDataGroup) throws Exception
	{
		Method libIn = cla.getDeclaredMethod("libIn", Integer.class);
		Double pre = (Double) libIn.invoke(obj, startDataGroup);
		StdOut.println("N---time---X");
		for(int N = (startDataGroup*2);true;N*=2)
		{
			Double time = (Double) libIn.invoke(obj, N);
			StdOut.printf("%7d %5.1f %4.1f\n", N, time, time/pre);
			pre = time;
		}
	}
	
	/**
	 *这是一个对特定算法特定数据量的运行时间的预测
	 * startN * 2^b = targetN. resultTime = baseTime*T^b;
	 * 因为 targetN 可能不会刚好是startN乘2的幂的倍数。所以最后在确定 b 上,会挑选一个更接近于 targetN 的值,作为计算预测时间的指数。
	 * @param targetN 目标数据量
	 * @param startN 源数据量
	 * @param baseTime 该算法运行源数据量所需要的时间
	 * @param X 倍率
	 * @return Double 返回的是一个时间 ,即预测时间
	 * @author 肖沫
	 */
	public static Double pridictTime(int targetN, int startN, Double baseTime, Double X)
	{
		int b = -1;
		double truthX = targetN/startN;//实际倍率
		while(truthX>=1)
		{
			truthX = truthX / 2;
			b += 1;
		}
		b = Math.abs(Math.pow(2, b+1) - targetN) > Math.abs(Math.pow(2, b) - targetN) ? b : b+1; 
		//因为我们预测的数据规模targetN可能不是,startN与2^b的乘积的倍数,那么当循环出来以后,startN*2^b < targetN < startN*2^(b+1),那b要不要加一,就看b与(b+1)进行计算以后那种情况更趋近于targetN,我就选哪一个,作为时间估计的参数。
		return baseTime * Math.pow(X, b);
	}
}

如果你真的想试一试,但不知道如何下手,来吧,看我的演示!
运用实例

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值