天天看點

合理選擇資料結構

寫程式很重要的一點是選擇合理的資料結構,不合适的資料結構在如今高性能計算機盛行的情況下,小資料量展現不出什麼來,但是在超大資料的時候,

你所面臨的困境将會無窮的放大。

在python裡主要的資料結構,也就是内置資料結構,包括了清單,元組,字典以及集合。這四種資料結構分别具有不同的特性,影響着python的方方面面。

清單和元組類似于C的數組,但是不同的是,清單是動态的數組,具有着增删改查的操作,元組是靜态的數組,本身是不可變的(除非裡面包含了可變的容器類)

。那python為啥還要實作元組呢?按照python之禅所述,Special cases aren't special enough to break the rules...There should be one-- and preferably only one --obvious way to do it.

這是因為元組可以緩存于python的運作環境,在每次使用元組時我們都無需去通路核心配置設定記憶體,元組和清單代表着兩種不同的方式,元組是一個不會改變事物的多種屬性,而

清單是儲存多個相對獨立的對象的集合。

清單的搜尋,如果在已知次序的情況下,使用二分法效率會變得很好,但是如前言所述,在相對獨立的對象的資料集合中,有序是比較少見的情況,這意味着對清單的搜尋

在python内部結構就隻能是周遊。python的内建排序不是如《python源碼剖析》所述是快速排序,而是Tim排序,這個排序是google發明的,可以在最好的情況下實作O(n)的複雜度排序

,在最壞的情況下也有O(log(n))。對于資料的搜尋,

def b_search(i, haystack):

imin, imax = 0, len(haystack)

while True:

if imin > imax:

return -1

mid = (imin + imax) // 2

if haystack[mid] > i:

imax = mid

elif haystack[mid] < i:

imin = mid + 1

else:

return mid

python的二分搜尋實作很簡單,因為你不需要再考慮記憶體溢出以及安全性,這些python已經幫你做好了。還有和二分搜尋相似的,就是二叉搜尋樹。至于如果你不想自己實作

你可以選擇bisect子產品幫你解決這個問題。

元組因為其的不可改變性,對于清單為了其可變性犧牲的額外的記憶體以及使用它們進行的額外的計算,元組就記憶體消耗和速度就快的多了。并且小元組在申請了記憶體後也就是

不會返還給系統,還留待未來使用,在接下來需要新元組時就不需要向系統申請記憶體了。

下面看看字典和集合,字典在很多語言内都有實作,也就是映射,屬于key-value的一種,在python裡集合也是類似字典的結構,隻不過沒有了value,隻有key了。

字典和集合的查詢無需周遊,隻需要計算散列函數就可獲得其值,但這也意味着這兩種資料結構會占用更大的記憶體,而且O(1)的複雜度也取決于散列函數的計算複雜度。

字典插入時,會計算鍵的散列值,理想的散列函數對應的鍵應該是就是整數,不會出現任何形式的沖突。計算出散列值後,很重要的一點要計算掩碼,來得知value應該存放的

位置。對于沖突的處理,python使用的是開放定址法,會在一個數組裡不斷‘嗅探’,獲得空的記憶體空間。當然,在字典的記憶體不夠用時,自然會申請空間,這意味着我們需要重新散列值和

掩碼。

是以,每種資料結構都有其不同的特性,是以這也意味着選擇一個良好的資料資料會使得你的代碼效率快上不少。