寻找递归关系和复杂性

Finding recurrence relation and complexity

根据运算次数,找出递归关系!

a = N;
var = 0;
while (a > 1) 
{
var = var + a; 
num = 2 * var; 
a = a / 2;
}

我认为会形成的递归关系是:(赋值操作不算)

T(n)= (from a=1 to N)Σ(3)

我说的对吗??

现在使用这个递归关系,如何求它的复杂度。

你想要做的是找到这个操作被调用了多少次,所以考虑一下:在每次调用之后 a 除以 2,所以如果 M = N/2 那么 T(M) = T( N) - 1.

现在,此循环的每次迭代都会再次除以 N,因此您会得到以下结果:

T(N) = T(N/2) + 1 = ... = k + T(N/(2^k))

停止条件是这样的:a>1所以你需要检查什么时候N/(2^k) <= 1

N/2^k = 1 -> log (n) = k

所以T(N) = log(n) + T(1) = log(n)

这是 'big O' 表示法的答案。

实证方法:

首先通过简化代码减少"educational noise",并添加一个迭代计数器(c)。然后查看结果 (N,count),一段时间后您会看到,对于 [1,2,4,8,16,..] 中的所有 N,2 ^ count = N。

所以复杂度 Compl(loop) = O(log_2(N)).

let rec loop a c = 
    match a with
    | x when x > 1 -> 
        let a1 = a / 2
        loop a1 (c+1)
    | _ -> (a,c)

// after staring at the result of the computation we came up with this theory:
let theory n = int (System.Math.Log10(float n) / System.Math.Log10(2.0))

[1..64] 
|> List.map (fun a -> a,loop a 0, theory a) 
|> List.map (fun (a0,(a,c),aa) -> a0,c,aa)

数据:

[(1, 0, 0); (2, 1, 1); (3, 1, 1); (4, 2, 2); (5, 2, 2); (6, 2, 2); (7, 2, 2); (8, 3, 3); (9, 3, 3); (10, 3, 3); (11, 3, 3); (12, 3, 3); (13, 3, 3); (14, 3, 3); (15, 3, 3); (16, 4, 4); (17, 4, 4); (18, 4, 4); (19, 4, 4); (20, 4, 4); (21, 4, 4); (22, 4, 4); (23, 4, 4); (24, 4, 4); (25, 4, 4); (26, 4, 4); (27, 4, 4); (28, 4, 4); (29, 4, 4); (30, 4, 4); (31, 4, 4); (32, 5, 5); (33, 5, 5); (34, 5, 5); (35, 5, 5); (36, 5, 5); (37, 5, 5); (38, 5, 5); (39, 5, 5); (40, 5, 5); (41, 5, 5); (42, 5, 5); (43, 5, 5); (44, 5, 5); (45, 5, 5); (46, 5, 5); (47, 5, 5); (48, 5, 5); (49, 5, 5); (50, 5, 5); (51, 5, 5); (52, 5, 5); (53, 5, 5); (54, 5, 5); (55, 5, 5); (56, 5, 5); (57, 5, 5); (58, 5, 5); (59, 5, 5); (60, 5, 5); (61, 5, 5); (62, 5, 5); (63, 5, 5); (64, 6, 6)]

递推关系为:

T(1) = a
T(n) = b + T(n/2)

第一部分来自循环变量等于 1 的情况,在这种情况下,只执行循环顶部的比较。第二行来自循环体 b 中完成的恒定工作量加上使用更新的循环变量值执行循环的时间。

前几项是:

n   T
1   a
2   a + b
4   a + 2b
8   a + 3b

据此我们可以猜出大概的形式:

T(n) = a + b log n

证明留作练习;但是你可以把它插入到递推关系中看看它是否满足要求。

渐近复杂度是对数的。