『算法』读书笔记 1.4算法分析 Part1

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

近似的概念,感觉上类似于微积分里面无穷小,即如果首项目的数量级比其他项大很多,则可以只考虑首项,因为其他幂次较低的项对最终结果的贡献几乎无关紧要。

 

至于如何对一些数学模型进行总时间的计算,作者也给了微积分方面的相应解决方案,个人觉得比用数列求和的方式做高级点。

TM截图20130125153335

事实上,为任何程序建立数学模型从理论上来说都是可行的,只不过有时候处理过程和方法会变得很复杂。

 

 

-----------------------------------------------------------------------------------------------------------------------

小结:

对于大多数程序,得到其运行时间的数学模型的步骤如下:

1.确定输入模型input model,定义问题的规模。如在ThreeSum中,输入规模即是标准输入中大小为N的整型数组a[N]。

2.识别内循环inner loop。对应回ThreeSum的例子,内循环便是三层的for循环。

3.根据内循环中的操作确定成本模型。所谓成本模型,即是算法中的基本操作。如ThreeSum的成本模型则是对数组元素的访问次数。

4.对于给定的输入,判断这些操作的执行效率。

posted @ 2013-01-25 15:36  Memphis Yip  阅读(535)  评论(0编辑  收藏  举报