python中的迭代與遞迴

pythontab發表於2014-01-17

遇到一個情況,需要進行遞迴操作,但是呢遞迴次數非常大,有一萬多次。先不說一萬多次遞迴,原來的測試程式碼是java的,沒裝jdk和編譯環境,還是用python吧

先看下原本的java程式碼:

public class UpCount {
    private long calc(int depth) {
        if (depth == 0) return 1;
        long cc = calc(depth - 1);
        return cc + (depth % 7) + ((((cc ^ depth) % 4) == 0) ? 1 : 0); 
    }
    public static void main(String[] args) {
        UpCount uc = new UpCount();
        System.out.println(uc.calc(11589));
    }
}

java沒怎麼玩過,但是這幾行程式碼看過來還是沒壓力的,快刀斬亂麻改為對於python程式碼

def calc(depth):
    if depth == 0:
        return 1
    cc = long(calc(depth-1))
    xor_mod = (cc ^ depth)%4
    if xor_mod == 0:
        return cc+(depth%7)+1
    else:
        return cc+(depth%7)
 
number = long(calc(11589))
print number

程式碼粘上去,F5,出錯了

這個版本的程式碼本來是沒有加long的,因為之前一串十幾位的整數直接拿來就可以用,所以懷疑跟long是不是有關係

當然啦,事實上這裡跟long完全沒關係,python支援的整數長度可是非常長的,參考之前寫的程式碼如下:

cimal = 7
original = 28679718602997181072337614380936720482949
array = ""
result= ""
while original !=0:
    remainder = original % cimal
    array += str(remainder)
    original /= cimal
length = len(array)
for i in xrange(0,length):
    result += array[length-1-i]
print result

上面這段程式碼將一串很長的十進位制數字轉為7進製表示,也可以轉為任意進位制,換做是8進位制和16進位制,一個oct(),hex()就搞定了,用輾轉相除法來解決吧

因此,可以看出來,出錯不在於數的大小,畢竟11589對現在的計算機來說只是小菜,2^16還有65536呢

其實到這裡才發現,沒有說前面遞迴報錯的真正原因,憔悴了

遞迴出錯的原因是因為python預設的遞迴限制只有1000次左右,但是這裡卻要執行10000+,刷了半天:RuntimeError: maximum recursion depth exceeded

於是趕緊查了下,發現可以自己設定遞迴的限制,見python中遞迴的最大次數,作為延伸也可以檢視官網文件

總的說來就是,為了防止益處和崩潰,python語言預設對次數加了限制,那麼我改了這個限制是不是就ok了呢

import sys

# set the maximun depth as 20000

sys.setrecursionlimit(20000)

插入上面程式碼,果斷改20000,這下沒這限制應該沒問題了,但是結果卻大跌眼鏡,什麼都沒輸出來,不解了

沒有繼續查了,問了下小夥伴littlehann,討論了下, 沒有對這個問題深究下去。而是提到遞迴這種運算在實際應用中的效率,確實除了課本上很少看到使用遞迴的

本來的目的就只是求值,沒想對它深究下去,還是改用迭代吧,雖然沒太大印象了,不過一個for語句據可以搞定了

程式碼如下:

def calc(depth):
    tmp = 0
    result = 1
    
    for i in xrange(0,depth+1):
        cc = result
        if (cc ^ i)%4 == 0:
            tmp = 1
        else:
            tmp = 0
        result = result + (i)%7 + tmp
        
    return result
final = calc(11589)
print final

短短几行程式碼,一下子搞定了。想到上次面試的時候,tx的面試官問我演算法,當時提到了用遞迴實現一個運算,再想想是不是也可以用迭代呢?

時間過去很久了,當時的題目也記不太清楚了,但是今天的教訓是:大多數(程式碼寫得少,憑感覺說的估計值)情況下,遞迴的效率是比較低下的,這一點可以確定,上課的

時候也有講到過。使用迭代的效率明顯要高過遞迴(迭代的具體概念記不太清楚了),起碼用迴圈,運算幾十萬次我可以肯定沒問題,但是即便我改了遞迴限制,還是遇到了罷工

最後,再貼出一個python long VS C long long的連結,感興趣的可以去看看


相關文章