Chapter 1
本章结构
1.1Java语法
1.2数据抽象
1.3集合类抽象数据类型:背包 (Bags) 、队列 (Queues) 、栈 (Stacks)
1.4算法分析
1.5连通性问题-Case Study: Union - Find ADT
本节开篇使用了一个ThreeSum程序进行示例:
ThreeSum所起到的作用为Count the number of triples in a file of N integers that sum to 0,简单来说,就是从N个数里面取3个数的组合,统计这些组合和为零的数量。
public class ThreeSum { public static int count(int[] a) { int N = a.length; int cnt = 0; for (int i = 0; i < N; i++) for (int j = i+1; j < N; j++) for (int k = j+1; k < N; k++) if (a[i]+a[j]+a[k] == 0) cnt++; return cnt; } public static void main(String[] args) { int[] a = In.readInts(args[0]); StdOut.println(count(a)); } }
与此同时,我们需要一个计时器来确定程序运行的时间,书上给出了一种计时器的实现方案,大概就是先在算法程序开始运行前先记录当前的系统时间,当算法运算完毕后,再次记录当前的系统时间,然后对两个时间进行时间差的运算便可得到整个算法所消耗的时间。
public class StopWatch { private final long start; public StopWatch() { start = System.currentTimeMillis(); } public double elapseTime() { long now = System.currentTimeMillis(); return (now - start) / 1000.0; } public static void main(String[] args) { int N = Integer.parseInt(args[0]); int[] a = new int[N]; for (int i = 0; i < N; i++) a[i] = StdRandom.uniform(-1000000, 1000000); StopWatch timer = new StopWatch(); int cnt = ThreeSum.count(a); double time = timer.elapseTime(); StdOut.println(cnt + " triples " + time + " seconds "); } }
D.E Knuth认为,一个程序运行的总时间主要和两点有关:
a.执行每条语句的耗时;
b.执行每条语句的频率;
如在Threesum.count()中的if语句会执行N(N-1)(N-2)/6次(由排练组合N个选3个可得)
正是这些执行最频繁的指令决定了程序运行的总时间,而这些指令也被称为程序的内循环inner loop。许多程序的运行时间往往取决于这一小部分指令的耗时。
ThreeSum运行时间分析
语句块 |
运行时间 |
频率 |
总时间 |
cnt++ |
t0 |
取决于输入x |
t0*x |
for对k的循环 |
t1 |
N取3的组合数 |
t1*C N 3 |
for对j的循环 |
t2 |
N取2的组合数 |
t2*C N 2 |
for对i的循环 |
t3 |
N |
t3*N |
count方法 |
t4 |
1 |
t4 |
总时间 |
上述汇总求和 |
||
近似 |
~(t1/6)N^3 |
||
增长的数量级 |
N^3 |
至于如何对一些数学模型进行总时间的计算,作者也给了微积分方面的相应解决方案,个人觉得比用数列求和的方式做高级点。
事实上,为任何程序建立数学模型从理论上来说都是可行的,只不过有时候处理过程和方法会变得很复杂。
-----------------------------------------------------------------------------------------------------------------------
小结:
对于大多数程序,得到其运行时间的数学模型的步骤如下:
1.确定输入模型input model,定义问题的规模。如在ThreeSum中,输入规模即是标准输入中大小为N的整型数组a[N]。
2.识别内循环inner loop。对应回ThreeSum的例子,内循环便是三层的for循环。
3.根据内循环中的操作确定成本模型。所谓成本模型,即是算法中的基本操作。如ThreeSum的成本模型则是对数组元素的访问次数。
4.对于给定的输入,判断这些操作的执行效率。