簡體   English   中英

提高Python 3.4中大型字典的速度

[英]Improving speed of large dictionary in Python 3.4

因此,我正在研究具有1 000 000鍵的字典,我的任務是使它在3秒內(在Intel 2.4 GHz上)工作。 我嘗試對我的代碼進行性能分析,而while循環有很多成功之處,但是我想不出一種方法來使我的代碼在沒有它的情況下運行得更快。 有沒有一種方法可以改善我的代碼以使其更快地工作?

該代碼應該(並且這樣做,但是太慢)創建一個字典,其中的鍵都是從2到999999的整數,並且值是由序列模式制成的列表的長度。 模式是:如果整數是偶數,則將其除以2,如果整數是奇數且大於1,則將其乘以3並加1。這一直持續到達到數字1。

例如:3-> 10-> 5-> 16-> 8-> 4-> 2->1。此列表的長度是8。

碼:

import time
start = time.clock()

first = 2
last = 1000000

def function1(n,d):
    if n/2 in d:
        d[n] = d[n/2] + 1
    if n not in d:
        d[n] = 0
        temp = n
        while temp > 1:
            if temp%2 == 0:
                temp /= 2
                d[n] += 1
            else:
                temp = 3*temp + 1
                d[n] += 1
            if temp in d:
                d[n] += d[temp]
                break
    return d[n]

d={}
d[1]=1
d={key: function1(key,d) for key in range(first,last)}

print(time.clock() - start)

在我的系統上,您的代碼確實耗時超過3秒(在最近的2.3 GHz Intel Core i7 Macbook Pro上使用Python 3.4)。

我可以通過使用局部變量並避免兩次構建字典,在3秒內(減少2.65秒,減少12%)獲得它:

def function1(n,d):
    if n/2 in d:
        d[n] = d[n/2] + 1
        return
    if n not in d:
        length = 0
        temp = n
        while temp > 1:
            if temp%2 == 0:
                temp //= 2
            else:
                temp = 3*temp + 1
            length += 1
            if temp in d:
                length += d[temp]
                break
        d[n] = length

d={1: 1}
for key in range(first,last):
    function1(key, d)

請注意,我使用局部length變量,而不是一直從d[n]讀取長度。 Python中的局部變量存儲在C數組中,從而避免了對鍵進行哈希處理和查找(可能包括哈希沖突)的麻煩。

我從/ (浮點除法)切換到// (整數除法); 當您感興趣的只是整數結果時,無需處理小數點。

如果在字典中找到n/2我也會返回 測試成功后,沒有必要測試n not in d ,因為我們剛剛添加了d[n]

字典的理解是完全多余的, function1()已經就地更改了d ,因此構建新字典來替換現有結果沒有意義。

下一步是利用剛剛計算的temp值序列。 當您從3開始時,您將在此過程中計算其他幾個值。 所有這些都可以存儲在d一旦你完成,所以你不必重新計算順序為1051684 兩種

def function1(n,d):
    if n not in d:
        length = 0
        seen = []
        while n > 1:
            seen.append(n)
            if n % 2 == 0:
                n //= 2
            else:
                n = 3 * n + 1
            length += 1
            if n in d:
                length += d[n]
                break
        for num in seen:
            d[num] = length
            length -= 1

這里3需要8個步驟,但是我們可以將7存儲為10存儲為5 ,依此類推。

我一共丟掉了if n/2 in d測試, while循環已經解決了這種情況。 由於if n not in d塊中不再需要n了,我將temp完全刪除,然后繼續n

現在整個測試僅需1.75秒。

我相信一個有用的優化(可以在我的MB Air上使用Core i5在1.3 GHz上獲得2.4秒的性能,最好運行3次,使用Python 2.7.3; 3.4.1,2.7秒),這是避免“浪費”各種計算的最佳方法的temp -保持它們不變可以讓您非常直接地計算它們的d值。 這是我的版本...:

import time
start = time.clock()

first = 2
last = 1000000

def function1(n, d):
    if n%2 == 0 and n//2 in d:
        d[n] = d[n//2] + 1
    if n not in d:
        temp = n
        intermediates = []
        while temp > 1:
            if temp%2 == 0:
                temp //= 2
            else:
                temp = 3 * temp + 1
            if temp in d:
                d[n] = res = d[temp] + len(intermediates) + 1
                for i, temp in enumerate(intermediates, 1):
                    d[temp] = res - i
                return res
            else:
                intermediates.append(temp)
    return d[n]

d={1: 1}
for k in range(first, last): function1(k, d)

print(time.clock() - start)

這是Collat​​z的猜想 。您可以檢查一些有關Internet的信息,一些有關Internet的C或C ++代碼,例如Python。 我認為您會發現人們以前做過的一些有用的功能。

您也可以使用numpy模塊,並可以使用它創建一些公式,我認為這樣做會更快。Numpy是一個可以輕松進行數學運算的模塊。

暫無
暫無

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

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