2016-04-30 43 views
3

我試圖執行下面的Python代碼將按照字母順序返回「ABCDEGGHIJK」,這在項目歐拉問題336排序迭代的最大數量來定義它會採取一個非常簡單的排序算法的第一置換。在更快的機器上完全相同的python代碼慢了20倍?

這裏是代碼(壞的變量名道歉):

from itertools import permutations 

def first_out_letter(st): 
    """ 
    returns the first letter alphabetically in st which is not in sorted order 
    alphabetically, string must be all in captials. 
    """ 
    def first(string): 
     """ 
     returns the first alphabetical letter in a string, only capitals allowed 
     """ 
     alpha = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" 

     for i in alpha: 
      if i in string: 
       return i 
     return None 
    sor = ''.join(sorted(st)) 
    for i in range(len(st)): 
     if st[i] != sor[i]: 
      return first(st[i:]) 
    return None 

def get_arrangement_size(arrang,dictionary): 
    """ 
    returns the number of shifts needed to arrange a string in lexographic order 
    using a dumb method of first getting the first digit correct, then the second 
    and so on... 

    the argument dictionary stores precomputed results and is modified during execution. 
    """ 
    if arrang in dictionary.keys(): 
     return dictionary[arrang] 
    sor = ''.join(sorted(arrang)) 
    if arrang == sor: 
     dictionary[arrang] = 0 
     return 0 
    else: 
     bing = first_out_letter(arrang) 
     num_arr = 0 
     pos_bing = 0 
     for i in range(len(arrang)): 
      if arrang[i] == sor[i]: 
       num_arr += 1 
      else: 
       break 
     for i in range(len(arrang)): 
      if arrang[i] != bing: 
       pos_bing += 1 
      else: 
       break 
     if bing == arrang[-1]: 
      low = get_arrangement_size(arrang[:num_arr]+arrang[num_arr:][::-1],dictionary) 
     else: 
      low = get_arrangement_size(arrang[:pos_bing]+arrang[pos_bing:][::-1],dictionary) 
     dictionary[arrang] = low+1    
     return low+1 

solutions = {} 
letters = ["A","B","C","D","E","F","G","H","I","J","K"] 
piv = permutations(letters) 
for item in piv: 
    get_arrangement_size(''.join(item),solutions) #builds up the solutions dictionary 
ma = max(solutions.values()) 
fir = [] 
for item in solutions.keys(): 
    if solutions[item] == ma: 
     fir.append(item) 
fir = sorted(fir) 
print(fir[0]) 

代碼工作在兩個我的機器罰款,並給出了正確的答案,但我看到高達20的非常大的轉速差時間在我的兩臺機器上。

我的(理論上)更快的計算機與i5運行Linux Mint和Python 2.7.6,並具有更多的內存,但是當我運行此代碼時,我發現它執行速度遠遠低於我的較慢的計算機,這是一個賽揚與Windows和python 3.5.1。當我在我的任一臺機器上運行此代碼並且它們都使用相同的IDE(Spyder)時,我不會同時運行其他任何程序,所以我不知道爲什麼會有這種速度差異?

任何幫助或理由來解釋這將是大加讚賞。

編輯:由於根據CHRISS的建議,我想我的速度較慢的計算機上運行的Python 2.7版的代碼,它也比當我跑的代碼上3.5在同一臺計算機上要慢得多。所以這種差異是由python版本引起的,但是究竟是什麼導致了我不知道的並且仍然想知道的差異。

+0

你有沒有嘗試過的Python 2.7在Windows或Linux上的Python 3.5? – Chris

+0

@Chris。我剛剛做了,事實證明,窗口上的python 2.7也比python 3.5慢得多,所以我想這種差異是由於python版本。但究竟是什麼導致這種差異,我仍然不知道,並希望找出。 –

+0

這可能是因爲Python 2和Python 3之間'範圍'的差異。你可以嘗試將所有'range'調用轉換爲'xrange'並在Python 2上運行它以查看它是否有幫助?我會做我自己,但原碼結果的內存錯誤我的機器... – niemmi

回答

4

這是由於Python 2和Python 3之間的差異dict.keys()引起的。在Python 2中,dict.keys()將創建鍵列表副本並返回它。在Python 3 dict.keys()將返回dictionary view反而是set狀物體。檢查list是否可以找到一個元素比檢查它是否在set中解釋不同。

如果進行如下修改代碼大致運行在同一時間上的Python 2 & 3:

if arrang in dictionary: # Instead of if arrang in dictionary.keys() 
    return dictionary[arrang] 
+0

謝謝,這工作得很好。但是,如果我想檢查一個元素是否存在字典的值,我將不得不使用set(dictionary.values())中的if元素:'如果我沒有弄錯。它是否正確? –

+1

@AbdulHadiKhan:是的,你可以使用,但它不會任何不僅僅是'元素更快dictionary.values()'。生成'set'和檢查值是否在'list'中都具有'O(n)'時間複雜度。如果您需要快速檢查鍵和值,最好將值存儲到單獨的容器中,例如['Counter'](https://docs.python.org/2/library/collections.html#collections.Counter) (如果你知道值是唯一的,'set'也可以。 – niemmi

相關問題