簡體   English   中英

使用遞歸尋找力量

[英]Finding Power Using Recursion

在 Python 3

def power(base,exponent):
    if exponent == 1:
        return base
    return base * power(base, exponent - 1)

我沒有考慮過極端情況(指數<= 0)

為什么我們不使用上面編寫的代碼來代替使用分而治之技術計算的代碼,這段代碼看起來更簡單易懂? 這段代碼的效率會降低嗎?

這些是使用您的代碼計算 2^8 所采取的步驟:

power(2,8)=
2*power(2,7)=
2*2*power(2,6)=
2*2*2*power(2,5)=
2*2*2*2*power(2,4)=
2*2*2*2*2*power(2,3)=
2*2*2*2*2*2*power(2,2)=
2*2*2*2*2*2*2*power(2,1)=

這些是用分而治之計算 2^8 所采取的步驟:

power(2,8)=
power(2,4)**2=
power(2,2)**2**2=
power(2,1)**2**2**2=

如您所見,您的方法需要 O(n) 步,而分而治之需要 O(lg(n)) 步,這要快得多。

如果您關心速度,那么對此類問題使用遞歸絕不是一個好主意,因為正如您所見,迭代方法(函數式語言中的尾遞歸)通常要快得多,在此示例中,它的速度是您在基准測試中看到的兩倍,至於分而治之的方法,你應該總是使用它,除非你使用的權力小於~22。

以下是一些基准:

代碼:

def r_power(base, exponent):  # recursive credits to OP
    if exponent == 1:
        return base
    return base * r_power(base, exponent - 1)


def lindc_power(x, y):  # linear divide and conquer, credits to Smitha Dinesh Semwal
    if y == 0:
        return 1
    elif int(y % 2) == 0:
        return lindc_power(x, int(y / 2)) * lindc_power(x, int(y / 2))
    else:
        return x * lindc_power(x, int(y / 2)) * lindc_power(x, int(y / 2))


def lgdc_power(x, y):  # logarithmic divide and conquer
    if y == 0:
        return 1
    elif int(y % 2) == 0:
        return lgdc_power(x, int(y / 2)) ** 2
    else:
        return x * lgdc_power(x, int(y / 2)) ** 2


def i_power(base, exponent):  # iterative, credits to Yugandhar Chaudhari
    acc = 1
    while True:
        if exponent == 0:
            return acc
        base, exponent, acc = base, exponent - 1, acc * base

結果:

|---------------------------------------------------------------------|
| base | power   | recursive | iterative | linear dc | logarithmic dc |
|---------------------------------------------------------------------|
| 2    | 10      | 1.27 µs   | 746 ns    | 8.99 µs   | 2.33 µs        |
| 2    | 22      | 2.96 µs   | 1.58 µs   | 18.6 µs   | 2.95 µs        |
| 2    | 100     | 15.1 µs   | 8.31 µs   | 75.3 µs   | 4.14 µs        |
| 2    | 500     | 96.7 µs   | 48.9 µs   | 312 µs    | 5.69 µs        |
| 2    | 1000    | 424 µs    | 178 µs    | 1.3 ms    | 6.58 µs        |
| 2    | 1500    | 201 µs    | 108 µs    | 620 µs    | 7.89 µs        |
| 2    | 2000    | 435 µs    | 242 µs    | 1.23 ms   | 8.15 µs        |
| 2    | 3000    | error     | 409 µs    | 2.49 ms   | 10.3 µs        |
| 2    | 6000    | error     | 1.13 ms   | 5.01 ms   | 17.6 µs        |
| 2    | 10000   | error     | 2.64 ms   | 9.84 ms   | 25.2 µs        |
| 2    | 20000   | error     | 8.74 ms   | 19.9 ms   | 45.7 µs        |
| 2    | 100000  | error     | 161 ms    | 82.4 ms   | 249 µs         |
| 2    | 200000  | error     | 626 ms    | 159 ms    | 532 µs         |
| 2    | 1000000 | error     | 15 s      | 651 ms    | 3.23 ms        |
|---------------------------------------------------------------------|

我的最大遞歸深度是 3000。

# a pow n = a pow n%2 * square(a) pow(n//2)
def powofn(a, n):
    if n == 0:
        return 1
    elif n == 1:
        return a
    else:
        return powofn(a, n%2) * powofn(a*a, n//2)

是的,如果它不是尾遞歸,這可能會降低效率。 遞歸創建的堆棧幀太大,您可以從 memory 中取出 go。 正確的方法是使用尾遞歸來表達它。 您只需要使用一個變量來存儲結果acc它將在變量中評估結果而不是進行遞歸 function 調用

def power2(base,exponent,acc):
    if exponent == 0:
        return acc
    return power2(base,exponent-1,acc*base)

print(power2(10,2,1)) #start acc from 1 initially

但是 python 不是尾部優化的,所以這是在這里使用尾部優化的方法

def power2(base,exponent,acc):
    while True:
        if exponent == 0:
            return acc
        base,exponent,acc = base,exponent-1,acc*base

print(power2(10,100,1))

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM