假如一个算法中包含了某些冗余的计算过程,那么一定有方法能够继续优化。

时间:2020-03-26
本文章向大家介绍假如一个算法中包含了某些冗余的计算过程,那么一定有方法能够继续优化。,主要包括假如一个算法中包含了某些冗余的计算过程,那么一定有方法能够继续优化。使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

关于算法效率的一些考虑

减少冗余计算

假如一个算法中包含了某些冗余的计算过程,那么一定有方法能够继续优化。

比方双重递归

#下面是一个求2的幂的运算
def powerOfTwo1 (n):
    if n == 0:
        return 1
    else if n == 1:
        return 2
    else
    	return powerOfTwo1( n//2 )*powerOfTwo1( (n+1)//2 )

这里powerOfTwo(n//2)powerOfTwo((n+1)//2) 两局部的计算是有冗余的,当n是偶数时,2个结果一样,但是却反复了计算;而当n是奇数时,powerOfTwo((n+1)//2) = 2 * powerOfTwo(n//2), 同样计算呈现冗余,时间复杂度到达O(2^n),所以能够进一步优化。

def powerOfTwo2 (n):
    if n == 0:
        res = 1
    else
    	res = 2*powerOfTwo2(n-1) 
        
    return res

优化后时间复杂度为O(n)

加大计算粒度

当然上面的powerOfTwo2算法还不算太好,某种水平上来说里面还存在冗余,由于有太多反复的 乘2 操作了,如何进一步减少这些操作呢?那就是在运算过程中动态地改动计算粒度。

def powerOfTwo3 (n):
    if n == 0:
        return 1
    
    table = [2]
    res = 1
    while(n):
        if len(table) >= n:
            res *= table[n-1]
            n = 0
    	else:
            table.append(2*table[-1])
            res *= table[-1]
            n -= len(table)
            
    return res

这次powerOfTwo3会动态地改动每一次计算的粒度,从最小的2开端,之后可能为更大的4、8、16等。

比方计算2的13次方幂,运算过程为2 * 4 * 8 * 16 * 8, 即2 * 2^2 * 2^3 * 2^4 * 2^3
此时时间复杂度变为O(logN)

当然上面的指数n是经过减法衰减的( n -= len(table) ), 因而还能更快,比方运用除法来更快地衰减n,比方下面

#求k的n次方, powerOfTwo4(n) = power4(2,n)
def power4 (k, n):
    if n == 0:
    	return 1
    else:
        if n % 2 == 0:
            return power4( k*k, n//2 )
        else:
            return k * power4( k*k, n//2 )

这种办法每次运算基于的底数都不同,即新的运算粒度,因而需求保管新的底数,就像power4函数中的参数k,但是这点空间换来的效率提升是完整值得的。

这里之所以能加大计算粒度,是由于每次幂运算都是基于相同的底数,即2,因而相当于另一种方式的“冗余计算”,但是有时分在计算中或许不能进一步加大计算粒度,比方下面的阶乘计算:

#计算n!
def fac(n):
    if n == 0:
        return 1
    else
    	return n*fac(n-1)

阶乘里每一次运算操作的对象都不同,因而不存在冗余,不能进一步加大粒度。

加大计算粒度的办法很多,详细多大的粒度才最好,这还要看需求处置的数据的范围。

减少乘除

有时分某个算法的粒度曾经不小,而且操作过程也没有明显的冗余,这时分某些细微的运算过程或许还潜藏着冗余操作,能够从减少乘除运算的角度去进一步优化。

下面是一个求整数平凡根的程序,eg. intRoot(7) = 2

def increase( r, n ):
    return r if (r+1)*(r+1) > n else r+1
def intRoot(n) :
    if n == 0:
        return 0
    else:
        return increase( intRoot( n // 4 ) * 2, n )

操作的参数n每次以4倍的速度衰减,貌似曾经没有冗余。但是increase里的(r+1)*(r+1)性能耗费还是有点大,能够看看能否进一步优化,如下:

def intRootOptimize(n):
    if n == 0:
        return [0,0]
    else:
        preR, preR2 = intRootOptimize( n//4 )
        incR2 = 4*preR2 + 4*preR + 1  
        if incR2 > n:
            return [ 2*preR, 4*preR2 ]
        else:
            return [ 2*preR+1, incR2]

incR2 = 4*preR2 + 4*preR + 1 即前面的(2r+1)*(2r+1),这里的运算更合适编译器优化,能够优化为移位运算,效率进步许多。

原文地址:https://www.cnblogs.com/1654kjl/p/12573068.html