【1】 数学基础
1.1)本书将使用以下4个定义:
对上述定义的分析(Analysis):
- A1)第一个定义是说T(N)的增长率小于等于f(N)的增长率;
- A2)第二个定义是说T(N)的增长率大于等于g(N)的增长率;
- A3)第三个定义是说T(N)的增长率等于h(N)的增长率;
- A4)第四个定义是说T(N)的增长率小于p(N)的增长率, 它不同于大O,因为大O 包含增长率相同这种可能性;
1.2)我们引入了相对增长率的概念, 并将其应用到算法分析;
1.3)比较1000N 与 N^2 的大小?
虽然N 较小时,1000N 大于 N^2 ,但 N^2 以更快的速度增长,因为N^2 最终将更大;
1.4)这种情况下,N=1000 是个转折点;
第一个定义说,最后总会存在某个点 n0, 从它以后 cf(N) 总是至少与 T(N)一样大, 从而忽略掉常数因子, 则f(N) 至少与 T(N) 一样大;
1.5)上界与下界
当我们说T(N)=O(f(N))时,我们是在保证函数T(N)是在不快于f(N)的速度增长;因此f(N)是T(N)的一个上界, 也可以说f(N)=Ω(T(N))意味着T(N)是f(N)的一个下界;
1.6)直观上说
1.7)我们需要掌握的结论为:
1.8)以上信息足以按照增长率对大部分常见的函数进行分类(如下图)
【2】递归简论
1)当编写递归例程的时候,关键是要牢记递归的四条基本法则-Principle:
P1)基准情形:必须总是有某些基准情形,它无需递归就能解除;P2)不断推进:对于那些需要递归求解的情形,每一次递归调用都必须要是求解状况朝接近基准情形的方向前进;P3)设计法则:假设所有的递归调用都能运行;P4)合成效益法则(compound interest rule):在求解一个问题的同一实例时, 切勿在不同的递归调用中作重复性工作 ;
Attention)凡是可以用循环代替的 递归函数,他就不是一个好的递归函数;(因为当一个递归可以被转化为循环时,其递归使用效率低得离谱)
【3】递归荔枝
荔枝1)F(0)=0 且 F(x)=2F(x-1)+x^2
#include <stdio.h>
// compute the expr F(0)=0 且 F(x)=2F(x-1)+x^2
int func(int x)
{
if(x==0)
{
return 0;
}
return 2*func(x-1) + x*x;
}
int main()
{
int x = 1;
for(;x<10;x++)
{
printf("func(%d) = %d \n", x, func(x));
}
}
荔枝2)打印整数: 1234 -> 1 2 3 4
#include <stdio.h>
// output the single integer towards given x.
// ex. 1234 should output as 1 2 3 4.
void printOutput(int x)
{
if(x>10)
{
printOutput(x/10);
}
printf("%d ", x%10);
}
int main()
{
int x[] = {12345, 123456, 1234567, 12345678, 123456789};
int length = 5;
int i = 0;
for(;i<length;i++)
{
printf("printOutput(%d) = ", x[i]);
printOutput(x[i]);
printf("\n");
}
}